Monopoly Odds
In a simplified Monopoly game with two 4-sided dice, find the three most visited squares. Express the answer as a six-digit string of their two-digit square numbers (in descending order of frequency).
Problem Statement
This archive keeps the full statement, math, and original media on the page.
In the game, Monopoly, the standard board is set up in the following way:

A player starts on the GO square and adds the scores on two 6-sided dice to determine the number of squares they advance in a clockwise direction. Without any further rules we would expect to visit each square with equal probability: 2.5%. However, landing on G2J (Go To Jail), CC (community chest), and CH (chance) changes this distribution.
In addition to G2J, and one card from each of CC and CH, that orders the player to go directly to jail, if a player rolls three consecutive doubles, they do not advance the result of their 3rd roll. Instead they proceed directly to jail.
At the beginning of the game, the CC and CH cards are shuffled. When a player lands on CC or CH they take a card from the top of the respective pile and, after following the instructions, it is returned to the bottom of the pile. There are sixteen cards in each pile, but for the purpose of this problem we are only concerned with cards that order a movement; any instruction not concerned with movement will be ignored and the player will remain on the CC/CH square.
Community Chest (2/16 cards):
Advance to GO
Go to JAIL
Chance (10/16 cards):
Advance to GO
Go to JAIL
Go to C1
Go to E3
Go to H2
Go to R1
Go to next R (railway company)
Go to next R
Go to next U (utility company)
Go back 3 squares.
The heart of this problem concerns the likelihood of visiting a particular square. That is, the probability of finishing at that square after a roll. For this reason it should be clear that, with the exception of G2J for which the probability of finishing on it is zero, the CH squares will have the lowest probabilities, as 5/8 request a movement to another square, and it is the final square that the player finishes at on each roll that we are interested in. We shall make no distinction between "Just Visiting" and being sent to JAIL, and we shall also ignore the rule about requiring a double to "get out of jail", assuming that they pay to get out on their next turn.
By starting at GO and numbering the squares sequentially from 00 to 39 we can concatenate these two-digit numbers to produce strings that correspond with sets of squares.
Statistically it can be shown that the three most popular squares, in order, are JAIL (6.24%) = Square 10, E3 (3.18%) = Square 24, and GO (3.09%) = Square 00. So these three most popular squares can be listed with the six-digit modal string: 102400.
If, instead of using two 6-sided dice, two 4-sided dice are used, find the six-digit modal string.
Problem 84: Monopoly Odds
Mathematical Foundation
Definitions and Notation
Definition 1 (Board). The Monopoly board consists of 40 squares indexed . The distinguished squares are:
- GO = 0, JAIL = 10, G2J (Go To Jail) = 30.
- Community Chest (CC): .
- Chance (CH): .
- Railroads (R): .
- Utilities (U): .
Definition 2 (Dice distribution). Two independent 4-sided dice yield a sum with probability mass function
The probability of doubles (both dice showing the same value) is .
State Space Construction
Lemma 1 (Sufficiency of the doubles counter). The state space , where denotes the current square and the number of consecutive doubles already rolled, is a sufficient state representation for the Monopoly Markov chain. In particular, .
Proof. The transition distribution from a given position depends on two quantities: the current square (which determines whether special rules apply upon landing) and the consecutive doubles count (which determines whether the next double triggers a forced move to JAIL). The count takes values in because:
- If and the next roll is a double, the player moves to JAIL and the count resets to .
- If and the next roll is a double, the count increments to .
- If the next roll is not a double, the count resets to .
Hence never persists as a state, and is exhaustive. The total state count is .
Existence and Uniqueness of the Stationary Distribution
Theorem 1 (Ergodicity). The Markov chain on is irreducible and aperiodic. Consequently, by the Perron—Frobenius theorem, there exists a unique stationary distribution satisfying and .
Proof.
Irreducibility. It suffices to show that every state communicates with a fixed reference state, say (JAIL with zero doubles). From any state , three consecutive doubles lead to regardless of and , and this event has positive probability for the required number of doubles . From , any target square is reachable: the dice sums form a set of step sizes whose greatest common divisor is . By Bezout’s lemma, every residue modulo 40 is representable as a non-negative integer linear combination of these step sizes, so any square is reachable in a bounded number of non-double rolls (each setting ).
Aperiodicity. From state , a non-double roll moves to some state , and a subsequent sequence of non-double rolls can return to in varying numbers of steps. Since the gcd of possible return times is 1, the chain is aperiodic.
By the fundamental theorem of finite Markov chains, an irreducible aperiodic chain on a finite state space possesses a unique stationary distribution.
Transition Matrix Construction
Theorem 2 (Transition probabilities). The transition matrix is defined as follows. For each state and each dice outcome (each occurring with probability ):
- If (doubles) and : the player moves to state with certainty (three consecutive doubles rule).
- Otherwise, the player lands on square and the following redirection rules apply:
- G2J (): redirect to where if , else .
- Community Chest (): draw a card uniformly from 16 cards. With probability , move to GO (0); with probability , move to JAIL (10); with probability , remain at .
- Chance (): draw a card uniformly from 16 cards. The outcomes are: GO (0), JAIL (10), C1 (11), E2 (24), H2 (39), R1 (5) each with probability ; next railroad with probability ; next utility with probability ; go back 3 squares with probability (which may trigger a further Community Chest draw); remain at with probability .
- Set if (and ), otherwise .
Proof. Each of the 16 equiprobable dice outcomes contributes probability to the appropriate transitions. The card draw probabilities follow from the uniform distribution over 16 cards for both Community Chest and Chance decks. Since the redirections are deterministic given the card drawn, and card draws are independent of previous events, the transition probabilities are well-defined and sum to 1 from each state.
Marginal Distribution
Definition 3 (Marginal square probability). The marginal probability of occupying square in stationarity is
The three most visited squares are those with the largest values of .
Editorial
The theoretical model is a Markov chain on states of the form “current square plus consecutive doubles count”, because those are the only pieces of information that affect the next move. In principle one can solve the stationary distribution exactly from that state graph.
The implementation takes the simulation route instead. It performs a very long random walk with a fixed seed, applies every Monopoly rule exactly as it occurs, and counts how often each square is visited. Each turn generates a candidate next state from the dice roll, and that state is then constrained by the special rules for three consecutive doubles, Go To Jail, Community Chest, and Chance. After enough turns, the empirical frequencies stabilize well enough that the top three squares produce the required modal string.
Pseudocode
Initialize the board position, the consecutive-doubles counter, and an array of visit counts.
Repeat for a very large number of turns:
Roll two 4-sided dice
Update the doubles counter
If this is the third consecutive double:
move directly to JAIL
Otherwise:
move forward by the dice total
apply Go To Jail if needed
apply Community Chest if needed
apply Chance if needed, including next railroad, next utility, and go-back-three-squares effects
Increase the visit count of the final square for this turn
Rank the 40 squares by visit count.
Return the top three square numbers written as a six-digit string.
Complexity Analysis
Time (exact method): for Gaussian elimination or eigenvalue decomposition. Power iteration converges in where is the number of iterations (typically for convergence to machine precision).
Time (simulation): where is the number of simulated turns (typically for sufficient accuracy).
Space: for the full transition matrix, or for the stationary vector alone.
Answer
Code
Each problem page includes the exact C++ and Python source files from the local archive.
#include <bits/stdc++.h>
using namespace std;
int main(){
// Problem 84: Monopoly Odds
// Two 4-sided dice. Find the 3 most visited squares via Monte Carlo.
// Answer: 101524
const int GO = 0, JAIL = 10, G2J = 30;
const int CC[] = {2, 17, 33};
const int CH[] = {7, 22, 36};
const int R[] = {5, 15, 25, 35};
const int U[] = {12, 28};
auto isCC = [&](int s){ return s==2||s==17||s==33; };
auto isCH = [&](int s){ return s==7||s==22||s==36; };
auto nextR = [&](int s) -> int {
for(int r : R) if(s < r) return r;
return R[0];
};
auto nextU = [&](int s) -> int {
for(int u : U) if(s < u) return u;
return U[0];
};
mt19937 rng(42);
int SIDES = 4;
long long visits[40] = {};
int pos = 0;
int doubles_count = 0;
int N = 10000000;
for(int t = 0; t < N; t++){
int d1 = rng() % SIDES + 1;
int d2 = rng() % SIDES + 1;
bool is_double = (d1 == d2);
if(is_double){
doubles_count++;
} else {
doubles_count = 0;
}
if(doubles_count == 3){
pos = JAIL;
doubles_count = 0;
visits[pos]++;
continue;
}
pos = (pos + d1 + d2) % 40;
if(pos == G2J){
pos = JAIL;
}
else if(isCC(pos)){
int card = rng() % 16;
if(card == 0) pos = GO;
else if(card == 1) pos = JAIL;
}
else if(isCH(pos)){
int card = rng() % 16;
switch(card){
case 0: pos = GO; break;
case 1: pos = JAIL; break;
case 2: pos = 11; break;
case 3: pos = 24; break;
case 4: pos = 39; break;
case 5: pos = 5; break;
case 6: pos = nextR(pos); break;
case 7: pos = nextR(pos); break;
case 8: pos = nextU(pos); break;
case 9:
pos = (pos - 3 + 40) % 40;
if(isCC(pos)){
int cc_card = rng() % 16;
if(cc_card == 0) pos = GO;
else if(cc_card == 1) pos = JAIL;
}
break;
default: break;
}
}
visits[pos]++;
}
vector<pair<long long,int>> freq;
for(int i = 0; i < 40; i++)
freq.push_back({visits[i], i});
sort(freq.rbegin(), freq.rend());
string ans;
for(int k = 0; k < 3; k++){
int sq = freq[k].second;
if(sq < 10) ans += "0";
ans += to_string(sq);
}
cout << ans << endl;
return 0;
}
"""
Problem 84: Monopoly Odds
Using two 4-sided dice, find the six-digit modal string for the three
most popular squares in Monopoly via Monte Carlo simulation.
Answer: 101524
"""
import random
def simulate(sides=4, num_turns=10_000_000, seed=42):
"""Monte Carlo simulation of the Monopoly Markov chain."""
rng = random.Random(seed)
GO, JAIL, G2J = 0, 10, 30
CC = {2, 17, 33}
CH = {7, 22, 36}
R = [5, 15, 25, 35]
U = [12, 28]
def next_r(pos):
for r in R:
if pos < r:
return r
return R[0]
def next_u(pos):
for u in U:
if pos < u:
return u
return U[0]
visits = [0] * 40
pos = 0
doubles_count = 0
for _ in range(num_turns):
d1 = rng.randint(1, sides)
d2 = rng.randint(1, sides)
is_double = (d1 == d2)
if is_double:
doubles_count += 1
else:
doubles_count = 0
if doubles_count == 3:
pos = JAIL
doubles_count = 0
visits[pos] += 1
continue
pos = (pos + d1 + d2) % 40
if pos == G2J:
pos = JAIL
elif pos in CC:
card = rng.randint(1, 16)
if card == 1:
pos = GO
elif card == 2:
pos = JAIL
elif pos in CH:
card = rng.randint(1, 16)
if card == 1:
pos = GO
elif card == 2:
pos = JAIL
elif card == 3:
pos = 11 # C1
elif card == 4:
pos = 24 # E2
elif card == 5:
pos = 39 # H2
elif card == 6:
pos = 5 # R1
elif card == 7:
pos = next_r(pos)
elif card == 8:
pos = next_r(pos)
elif card == 9:
pos = next_u(pos)
elif card == 10:
pos = (pos - 3) % 40
if pos in CC:
cc_card = rng.randint(1, 16)
if cc_card == 1:
pos = GO
elif cc_card == 2:
pos = JAIL
visits[pos] += 1
return visits
def main():
visits = simulate(sides=4, num_turns=10_000_000)
ranked = sorted(range(40), key=lambda i: visits[i], reverse=True)
modal_string = ''.join(f'{sq:02d}' for sq in ranked[:3])
print(modal_string)
if __name__ == "__main__":
main()