After a while in the game a player might own all the properties of the same "color", and he is said to have a "monopoly". Then he can begin to build houses, up to a hotel, on this property, and get much more rent from the other players.
Much of the game is "automatic", that is the player really does not make any decisions. Even the buying of property is (almost) automatic because it is understood that the more property he has, the better off he is. The one time strategy comes into play is when two players have the properties to form two monopolies, but need to "trade" some of them. As an example say player "A" owns New York Ave, Tennessee Ave (orange) and Indiana Ave (red). "B" owns St. James Place (orange), Kentucky Ave and Illinois Ave (red). So if they exchanged St. James Place for Indiana Ave, both would have a monopoly and can build houses. The question is, should they?
One thing is clear: the "red" properties have a higher rent than the orange ones ($950 vs $1050). But rent is only paid if somebody steps on the property, so we also need to know the probability of that happening. This would be easy (all would be equally likely) except for those Chance and Community Chest cards, and the "Go to Jail" option. Notice that everytime somebody gets out of jail, the probability to step on an orange field is P(6, 8,or 9) =(5+7+8)/36=0.55!
So. how can we find these probabilities? Really, the only way to do this is via a simulation.
How do we set this up as a simulation? First we need to get the "board into R". The board has 40 fields. Each field has a name ("Go", " Mediterreanen Ave", ..) . Many, but not all have a color. Finally there is the rent to be paid (for a hotel). So, we will represent the board as a vector of length 40. In monopoly this setup is done at the beginning.
How do we represent the position of a token on the board? One way would be as one of the numbers 1-40, but another option is to use 0-39 instead. An advantage of this is it makes the move counting easier, because R has a modulus function built in. So say we are on field 35, and roll (2,4). What is the next field:
(35+2+4)mod40=41mod40=41%%40=1 (Baltic Ave.)
But there is also a problem: In R vectors cannot be indexed by 0, fields would give an error message. fields is "Go", not "Baltic Ave". So if we use x=0-39, we need to use fields[x+1] to find out where we are.
So the basic move is done with the R commands:
dice=sample(1:6,size=2,replace=T) #Throw the dice
x=(x+sum(dice))%%40 #Move along board
After a move we need to check whether we are on "Go to Jail" (if x=30), on a "Cummunity Chest" (fields[x+1]=="Community Chest") or on "Chance" (fields[x+1]=="Chance"). If we are on x=30 we go to Jail (x=10). If we are on "Community Chest" we pick a card and move as directed, which is done by the function communitymove(). Similarly for "Chance".
We need to include one more item in our simulation: if a player lands in jail he has two options: he can get out right away (paying $50 or using a card) or he can throw the dice. If they come up doubles he gets out, moving the sum of the doubles. On the third round he gets out for sure (paying $50). Of course, if he is just "visiting" the jail he moves on normaly. What should a player do? Clearly in the early rounds he wants to get out of jail as quickly as possible (so he has a chance of buying more property) but in the later rounds it is much better to stay in jail (where rent is free). Because in our simulation we are interested in the later stages of a game, this will be our policy.
So the idea is to have one token start at Go (x=0) and let it move over the board according to the rules for many many rounds.
What should we keep track off? Obviously we need to know where we have been, which is done in visits. We also keep track of the "rounds", that is how often we moved around the board. This happens everytime x gets "reset" by the mod function, so if we call "oldx" the current position, "x" the next position then if oldx>x we have gone around once more. Finally we keep track of the money paid, in rent. Here we assume that every property has a hotel, all the railroads are owned by the same person and all the "Utilities" are also owned by the same person.
What should we print out? We are interested in the fields that make money, and their probabilities, so we sort these by the probabilities and show the result. We also show the "rent per round", this for the different monopolies.
So, let's run our simulation: monopoly()
Here is the result with one million runs:
So, how about our original question, should players "A" and "B" exchange St. James Place for Indiana Ave? If they do "A" then has the orange monoploy and "B" has the red one. So "A" should make about $425 per round and "B" should make about $458. On average in each round "B" makes $33 more than "A". So this looks like "A" should not trade at all!
Well, there are other considerations. For example, say the players agree to play for another 10 rounds, and "B" offer "A" an extra $330. Now it is a fair trade.
Another thing to consider is the amount of money "A" and "B" have. For example, if "B" is just about broke but "A" has plenty of money, "B" should not trade because he won't be able to build any houses and so he won't get any rent anyway.
Let's assume instead "A" has $a and "B" has $b. Then a trade would be fair if either of the two is equally likely to win at some point in the future. How can we find out what the probability of say "A" winning is? Well if "A" starts with $a then
• he has to pay for building the hotels, after which he has a-sum(cost[colors=="Orange"]) left
then after one round
• his wealth will increase by rent["Orange"] with probability p["Orange"] (if "B" lands on an orange field)
• his wealth will decrease by rent["Red"] with probability p["Red"] (if he lands on red)
• his wealth remains the same (if neither lands on the others property)
Similar of course for B.
Note that the construction costs are $250 per hotel in "row 1", $500 in "row 2" and so on.
So now we can run a simulation, playing many games as above until one or the other is broke, in monopoly1. This routine is written to be easily understood, but it is a little slow. We need to run this a number of times, and so it is important to speed it up a bit. This is done in monopoly2. Here we essentially run all N simulation simultaneously.
Playing around with this routine we can find out what a fair trade value is.
Example Say both have $3000, then "A" wins with probability 66%. If as part of the trade "A" gives "B" $250, then a=2750 and b=3250, and they both have the same probability of going broke.
This is a very strange result: the orange properties are before the red ones, with lower rents, yet A should pay B? The explanation is this, B needs to pay more money ($750 more) to build his hotels, and so he can get broke by just a few visits to A. If both started out with $6000, it is B who needs to pay A, some $300.
In the example above we have used trial and error to find the right trade-value.
Can we write a routine that does this for us? Here is an idea:
• find the probability of A winning without any money changing hands, call it p0
• if p0>0.5 A needs to pay B, if p0<0.5 B needs to pay A.
• say p0>0.5, let m be some amount of money (for example 10% of a), let pm be the probability of A winning for a trade-value of m. If pm<0.5 the correct trade value is in [0,m], otherwise raise m and try again.
• once we have found an interval [m1,m2] that contains the fair trade-value, check the midpoints and half the intervals.
• if p0<0.5 do the same the other way around.
• stop when pm=0.5
This is an example of one of my favorite algorithms, the bisection algorithm. here is the basic idea:
so we change low to mid and run again. This algorithm works great if the function is monotone. It is very slow but extrememly stable. In our case because we don't have an explicit expression for the function (and therefore no derivative) it's probably as good as we can do.
There is one difficulty: our routine is a simulation and will give slightly different values in different runs. Here is what we need to consider:
Let's say we do N=10000 runs. On each run A either wins or looses. Let the rv Zi=1 if A wins, 0 otherwise. Then Z1,..,ZN is a sequence of independent Bernoulli rv's with success probability pm. Therefore
so if we run a simulation that gives pm[0.485,0.515] the "true" pm might just be 0.5 and the corresponding m is a fair-trade value.
This is implemented in monopoly3.
Example Run monopoly3(5000,3000,Show=T)
This routine is not yet very good. To see whether your routine has problems it is often a good idea to run "extreme" cases. For example, try
but the error message makes no sense, to begin with A and B had enough money to build. Any idea what's wrong with my routine?
So, next time you play monopoly, bring your laptop and at the right time run our little routine.
If you want to know more about strategy in Monopoly, check out these websites: