Last active
October 4, 2015 15:08
-
-
Save joelgrus/ea1fdb4341afe14d52ca to your computer and use it in GitHub Desktop.
semi-functional rewrite of Norvig monopoly simulator to avoid global state
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Rewrite of Norvig's monopoly simulator to avoid global state | |
# except for `board`, which is used immutably. | |
# http://nbviewer.ipython.org/url/norvig.com/ipython/Probability.ipynb | |
import random | |
split = str.split | |
# The board: a list of the names of the 40 squares | |
board = split("""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""") | |
# The deck of 16 community chest cards. See do_card. | |
def get_cc_deck(): | |
deck = split('GO JAIL' + 14 * ' ?') | |
random.shuffle(deck) | |
return deck | |
# The deck of 16 chance cards. See do_card. | |
def get_ch_deck(): | |
deck = split('GO JAIL C1 E3 H2 R1 R R U -3' + 6 * ' ?') | |
random.shuffle(deck) | |
return deck | |
def monopoly(steps): | |
"""Simulate given number of steps of monopoly game, yielding the name of the | |
current square after each step.""" | |
here = 0 | |
CC = get_cc_deck() | |
CH = get_ch_deck() | |
doubles = 0 | |
for _ in range(steps): | |
d1, d2 = random.randint(1, 6), random.randint(1, 6) | |
here = goto(here + d1 + d2) | |
doubles = (doubles + 1) if (d1 == d2) else 0 | |
if doubles == 3 or board[here] == 'G2J': | |
here = goto('JAIL') | |
elif board[here].startswith('CC'): | |
here = do_card(CC, here) | |
elif board[here].startswith('CH'): | |
here = do_card(CH, here) | |
yield board[here] | |
def goto(square): | |
"""Go to destination square, which can be either a square number or a square | |
name. Return the index of the resulting square.""" | |
if isinstance(square, int): | |
return square % len(board) | |
else: | |
return board.index(square) | |
def do_card(deck, square): | |
"""Take the top card from deck and do what it says. Return the index of the | |
resulting square.""" | |
card = deck.pop() # Remove card from deck | |
deck[0:0] = [card] # Put card back on bottom of deck | |
if card == 'R' or card == 'U': | |
while not board[square].startswith(card): | |
# Advance to next railroad or utility | |
square = goto(square + 1) | |
return square | |
elif card == '-3': | |
# Go back 3 spaces | |
return goto(square - 3) | |
elif card == '?': | |
# Card is about money, not about movement | |
return square | |
else: | |
# Go to destination named on card | |
return goto(card) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment