2021-03-23 19:42:57 +01:00
|
|
|
from random import randint
|
|
|
|
from dataclasses import dataclass
|
2019-08-16 05:26:47 +02:00
|
|
|
|
2021-03-23 19:42:57 +01:00
|
|
|
@dataclass
|
|
|
|
class State:
|
|
|
|
current_field: int
|
|
|
|
consecutive_doubles: int
|
|
|
|
current_cc: int
|
|
|
|
current_ch: int
|
|
|
|
|
|
|
|
NUMBER_OF_FIELDS = 40
|
|
|
|
DICE_SIDES = 4
|
|
|
|
NUMBER_OF_ROLLS = 10**5
|
|
|
|
NUMBER_OF_CARDS = 16
|
|
|
|
|
|
|
|
GO = 0
|
|
|
|
CC1 = 2
|
|
|
|
T1 = 4
|
|
|
|
R1 = 5
|
|
|
|
CH1 = 7
|
|
|
|
JAIL = 10
|
|
|
|
C1 = 11
|
|
|
|
U1 = 12
|
|
|
|
R2 = 15
|
|
|
|
CC2 = 17
|
|
|
|
D3 = 19
|
|
|
|
CH2 = 22
|
|
|
|
E3 = 24
|
|
|
|
R3 = 25
|
|
|
|
U2 = 28
|
|
|
|
G2J = 30
|
|
|
|
CC3 = 33
|
|
|
|
R4 = 35
|
|
|
|
CH3 = 36
|
|
|
|
H2 = 39
|
|
|
|
|
|
|
|
# special identifier for chance cards
|
|
|
|
NR = 100
|
|
|
|
NU = 101
|
|
|
|
B3 = 102
|
|
|
|
|
|
|
|
CC_CARDS = [GO, JAIL] + [None for i in range(NUMBER_OF_CARDS - 2)]
|
|
|
|
CH_CARDS = [GO, JAIL, C1, E3, H2, R1, NR, NR, NU, B3] \
|
|
|
|
+ [None for i in range(NUMBER_OF_CARDS - 10)]
|
|
|
|
|
|
|
|
|
|
|
|
def roll_two_dices():
|
|
|
|
return (randint(1, DICE_SIDES), randint(1, DICE_SIDES))
|
|
|
|
|
|
|
|
|
|
|
|
def next_state_cc(cc_field, state):
|
|
|
|
next_field = CC_CARDS[state.current_cc]
|
|
|
|
state.current_cc = (state.current_cc + 1) % NUMBER_OF_CARDS
|
|
|
|
|
|
|
|
if next_field is None:
|
|
|
|
state.current_field = cc_field
|
|
|
|
else:
|
|
|
|
state.current_field = next_field
|
|
|
|
return state
|
|
|
|
|
|
|
|
|
|
|
|
def next_state_ch(ch_field, state):
|
|
|
|
next_field = CH_CARDS[state.current_ch]
|
|
|
|
state.current_ch = (state.current_ch + 1) % NUMBER_OF_CARDS
|
|
|
|
|
|
|
|
if next_field is None:
|
|
|
|
state.current_field = ch_field
|
|
|
|
elif next_field == NR:
|
|
|
|
if ch_field == CH1:
|
|
|
|
state.current_field = R2
|
|
|
|
elif ch_field == CH2:
|
|
|
|
state.current_field = R3
|
|
|
|
elif ch_field == CH3:
|
|
|
|
state.current_field = R1
|
|
|
|
elif next_field == NU:
|
|
|
|
if ch_field == CH1:
|
|
|
|
state.current_field = U1
|
|
|
|
elif ch_field == CH2:
|
|
|
|
state.current_field = U2
|
|
|
|
elif ch_field == CH3:
|
|
|
|
state.current_field = U1
|
|
|
|
elif next_field == B3:
|
|
|
|
if ch_field == CH1:
|
|
|
|
state.current_field = T1
|
|
|
|
elif ch_field == CH2:
|
|
|
|
state.current_field = D3
|
|
|
|
elif ch_field == CH3:
|
|
|
|
state.current_field = CC3
|
|
|
|
return next_state_cc(state.current_field, state)
|
|
|
|
else:
|
|
|
|
state.current_field = next_field
|
|
|
|
return state
|
|
|
|
|
|
|
|
|
|
|
|
def next_state(state):
|
|
|
|
next_field = None
|
|
|
|
|
|
|
|
d1, d2 = roll_two_dices()
|
|
|
|
if d1 == d2:
|
|
|
|
state.consecutive_doubles += 1
|
|
|
|
else:
|
|
|
|
state.consecutive_doubles = 0
|
|
|
|
|
|
|
|
if state.consecutive_doubles == 3:
|
|
|
|
state.consecutive_doubles = 0
|
|
|
|
state.current_field = JAIL
|
|
|
|
return state
|
|
|
|
|
|
|
|
next_field = (state.current_field + d1 + d2) % NUMBER_OF_FIELDS
|
|
|
|
if next_field == G2J:
|
|
|
|
next_field = JAIL
|
|
|
|
elif next_field in [CC1, CC2, CC3]:
|
|
|
|
return next_state_cc(next_field, state)
|
|
|
|
elif next_field in [CH1, CH2, CH3]:
|
|
|
|
return next_state_ch(next_field, state)
|
|
|
|
|
|
|
|
state.current_field = next_field
|
|
|
|
return state
|
|
|
|
|
|
|
|
|
|
|
|
def euler_085():
|
|
|
|
state = State(GO, 0, 0, 0)
|
|
|
|
accesses_per_field = [0 for _ in range(NUMBER_OF_FIELDS)]
|
|
|
|
|
|
|
|
for _ in range(NUMBER_OF_ROLLS):
|
|
|
|
state = next_state(state)
|
|
|
|
accesses_per_field[state.current_field] += 1
|
|
|
|
|
|
|
|
p_field = [(float(a) / NUMBER_OF_ROLLS * 100, i)
|
|
|
|
for i, a in enumerate(accesses_per_field)]
|
|
|
|
p_field.sort(reverse=True)
|
|
|
|
solution = ""
|
|
|
|
for p, i in p_field[:3]:
|
|
|
|
solution += "{:2d}".format(i)
|
|
|
|
|
|
|
|
return solution
|
2019-08-16 05:26:47 +02:00
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
2021-03-23 19:42:57 +01:00
|
|
|
solution = euler_085()
|
|
|
|
print("e085.py: " + str(solution))
|
|
|
|
assert(solution == "101524")
|
|
|
|
|