91 lines
2.3 KiB
Python
91 lines
2.3 KiB
Python
import functools
|
|
|
|
def parse_input(s):
|
|
p1, p2 = s.splitlines()
|
|
p1 = int(p1.split()[4])
|
|
p2 = int(p2.split()[4])
|
|
|
|
return p1, p2
|
|
|
|
def gen_die():
|
|
while True:
|
|
for n in range(1, 101):
|
|
yield n
|
|
|
|
def step(player, score, die):
|
|
r1 = next(die)
|
|
r2 = next(die)
|
|
r3 = next(die)
|
|
player += r1 + r2 + r3
|
|
while player > 10:
|
|
player -= 10
|
|
score += player
|
|
|
|
return player, score
|
|
|
|
def part1(s):
|
|
p1, p2 = parse_input(s)
|
|
s1, s2 = 0, 0
|
|
|
|
die = gen_die()
|
|
|
|
rolls = 0
|
|
|
|
while True:
|
|
p1, s1 = step(p1, s1, die)
|
|
rolls += 3
|
|
if s1 >= 1000:
|
|
break
|
|
p2, s2 = step(p2, s2, die)
|
|
rolls += 3
|
|
if s2 >= 1000:
|
|
break
|
|
|
|
answer = rolls * min(s1, s2)
|
|
|
|
print(f'The answer to part one is {answer}')
|
|
|
|
def part2(s):
|
|
p1, p2 = parse_input(s)
|
|
|
|
@functools.cache
|
|
def impl(p1, p2, s1=0, s2=0, active_player=1):
|
|
p1_wins = 0
|
|
p2_wins = 0
|
|
for r1 in (1, 2, 3):
|
|
for r2 in (1, 2, 3):
|
|
for r3 in (1, 2, 3):
|
|
if active_player == 1:
|
|
new_p1 = p1 + r1 + r2 + r3
|
|
while new_p1 > 10:
|
|
new_p1 -= 10
|
|
new_s1 = s1 + new_p1
|
|
if new_s1 >= 21:
|
|
p1_wins += 1
|
|
else:
|
|
sub_p1_wins, sub_p2_wins = impl(new_p1, p2, new_s1, s2, 2)
|
|
p1_wins += sub_p1_wins
|
|
p2_wins += sub_p2_wins
|
|
else:
|
|
new_p2 = p2 + r1 + r2 + r3
|
|
while new_p2 > 10:
|
|
new_p2 -= 10
|
|
new_s2 = s2 + new_p2
|
|
if new_s2 >= 21:
|
|
p2_wins += 1
|
|
else:
|
|
sub_p1_wins, sub_p2_wins = impl(p1, new_p2, s1, new_s2, 1)
|
|
p1_wins += sub_p1_wins
|
|
p2_wins += sub_p2_wins
|
|
return p1_wins, p2_wins
|
|
|
|
p1_wins, p2_wins = impl(p1, p2)
|
|
|
|
answer = max(p1_wins, p2_wins)
|
|
|
|
print(f'The answer to part two is {answer}')
|
|
|
|
with open('./2021/21.input') as input_file:
|
|
INPUT = input_file.read()
|
|
part1(INPUT)
|
|
part2(INPUT) |