-
Notifications
You must be signed in to change notification settings - Fork 17
/
day21.py
executable file
·64 lines (43 loc) · 1.44 KB
/
day21.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#!/usr/bin/env python3
import sys
from itertools import product, cycle
from functools import lru_cache
QUANTUM_ROLLS = tuple(map(sum, product(range(1, 4), range(1, 4), range(1, 4))))
def play1(p1_pos, p2_pos, score_limit):
rolls = p1_score = p2_score = 0
die = cycle(range(1, 101)).__next__
while 1:
p1_pos = (p1_pos + die() + die() + die()) % 10
p1_score += p1_pos + 1
rolls += 3
if p1_score >= score_limit:
return rolls, p2_score
p2_pos = (p2_pos + die() + die() + die()) % 10
p2_score += p2_pos + 1
rolls += 3
if p2_score >= score_limit:
return rolls, p1_score
@lru_cache(maxsize=None)
def play2(my_pos, my_score, other_pos, other_score, score_limit):
if my_score >= score_limit:
return 1, 0
if other_score >= score_limit:
return 0, 1
my_wins = other_wins = 0
for roll in QUANTUM_ROLLS:
new_pos = (my_pos + roll) % 10
new_score = my_score + new_pos + 1
ow, mw = play2(other_pos, other_score, new_pos, new_score, score_limit)
my_wins += mw
other_wins += ow
return my_wins, other_wins
# Open the first argument as input or use stdin if no arguments were given
fin = open(sys.argv[1]) if len(sys.argv) > 1 else sys.stdin
p1_pos = int(fin.readline().split()[-1]) - 1
p2_pos = int(fin.readline().split()[-1]) - 1
rolls, loser_score = play1(p1_pos, p2_pos, 1000)
ans = rolls * loser_score
print('Part 1:', ans)
wins = play2(p1_pos, 0, p2_pos, 0, 21)
best = max(wins)
print('Part 2:', best)