I built a simulator to solve it (as did many) using OOP. Got the answer right away. Lots of ideas posted to the Euler forum, including solutions based on matrix operations.

But c’mon, a simulator is much more fun to build! Plus its so easy to change it to a 4-sided die.

#Euler84 import random from operator import itemgetter class Board: sqr = [['GO'],['A1'],['CC1'],['A2'],['T1'],['R1'],['B1'],['CH1'],['B2'],['B3'], ['JAIL'],['C1'],['U1'],['C2'],['C3'],['R2'],['D1'],['CC2'],['D2'],['D3'], ['FP'],['E1'],['CH2'],['E2'],['E3'],['R3'],['F1'],['F2'],['U2'],['F3'], ['G2J'],['G1'],['G2'],['CC3'],['G3'],['R4'],['CH3'],['H1'],['T2'],['H2']] moves = 0 def __init__(self): for i in self.sqr: index = self.sqr.index(i) record = i+[0]+[index] self.sqr.pop(index) self.sqr.insert(index,record) def findPos(self, name): for i in self.sqr: if i[0] == name: return self.sqr.index(i) class Player: pos = 0 def move(self, spaces): self.pos += spaces if self.pos >= 40: self.pos -= 40 class Dice: dice1 = [1,2,3,4] # or [1,2,3,4,5,6] dice2 = [1,2,3,4] # or [1,2,3,4,5,6] dub = [False, False, False] def __init__(self): random.seed() def roll (self): random.shuffle(self.dice1) random.shuffle(self.dice2) self.dub.pop(0) if self.dice1[0] == self.dice2[0]: self.dub += [True] else: self.dub += [False] return self.dice1[0]+self.dice2[0] class Chance: cards = ['']*6 cards.extend(['GO','JAIL','C1','E3','H2','R1','RX','RX','UX','-3']) def __init__(self): random.shuffle(self.cards) def pick (self): top = self.cards.pop(0) self.cards.append(top) return top class Chest: cards = ['']*14 cards.extend(['GO','JAIL']) def __init__(self): random.shuffle(self.cards) def pick (self): top = self.cards.pop(0) self.cards.append(top) return top if __name__ == '__main__': B = Board() P = Player() D = Dice() CH = Chance() CC = Chest() print "Calculating Moves:", while B.moves < 2000001: if B.moves % 200000 == 0: print B.moves, P.move(D.roll()) spot = B.sqr[P.pos][0] if D.dub == [True, True, True]: spot = 'JAIL' if spot == 'G2J': spot = 'JAIL' if ['CH1','CH2','CH3'].count(spot) == 1: card = CH.pick() if ['GO','JAIL','C1','E3','H2','R1'].count(card) == 1: spot = card elif card == 'RX' and spot == 'CH1': spot = 'R2' elif card == 'RX' and spot == 'CH2': spot = 'R3' elif card == 'RX' and spot == 'CH3': spot = 'R1' elif card == 'UX' and spot == 'CH1': spot = 'U1' elif card == 'UX' and spot == 'CH2': spot = 'U2' elif card == 'UX' and spot == 'CH3': spot = 'U1' elif card == '-3' and spot == 'CH1': spot = 'T1' elif card == '-3' and spot == 'CH2': spot = 'D3' elif card == '-3' and spot == 'CH3': spot = 'CC3' if ['CC1','CC2','CC3'].count(spot) == 1: card = CC.pick() if ['GO', 'JAIL'].count(card) == 1: spot = card P.pos = B.findPos(spot) B.moves += 1 B.sqr[P.pos][1] += 1 B.sqr.sort(key=itemgetter(1), reverse=True) print "\nSorted Board Statistics:", for n in range (0,40): if n % 10 == 0: print "\n", print "%s:%i:%.2f" % (B.sqr[n][0],B.sqr[n][2],float(B.sqr[n][1])*100/B.moves), print "\nAnswer =", B.sqr[0][2], B.sqr[1][2], B.sqr[2][2]