-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday21.py
82 lines (64 loc) · 2.45 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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
import sys
from functools import lru_cache
PLAYER_COUNT = 2
def roll_deterministic(turn):
low = 3 * turn + 1
mid = low + 1
high = mid + 1
return low + mid + high
def part1(positions):
scores = [0] * PLAYER_COUNT
turn = -1
winner = None
while winner is None:
for player in range(PLAYER_COUNT):
turn += 1
rolls = roll_deterministic(turn)
positions[player] = (positions[player] + rolls) % 10
scores[player] += (positions[player] + 1)
# print(f"Player {player+1} rolls {rolls} and moves to position {positions[player] + 1} for a total score {scores[player]}")
if scores[player] >= 1000:
winner = player
break
print(f"After {turn+1} turns = {3*(turn+1)} rolls")
for player in range(PLAYER_COUNT):
print(f"Player {player+1} is on position {positions[player] + 1} with score {scores[player]}")
return scores[winner+1 % 2] * 3 * (turn+1)
# Map of equal sums of 3 rolls - sums and number of cases where they can be the same
dirac_rolls = {
3: len(set([ 111 ])),
4: len(set([ 112, 121, 211 ])),
5: len(set([ 113, 131, 311, 122, 212, 221 ])),
6: len(set([ 123, 132, 312, 321, 213, 231, 222 ])),
7: len(set([ 223, 232, 322, 133, 313, 331 ])),
8: len(set([ 233, 323, 332 ])),
9: len(set([ 333 ]))
}
@lru_cache(maxsize=None)
def roll_dirac(playerPosition, opponentPosition, playerScore, opponentScore):
if playerScore >= 21:
return 1, 0
if opponentScore >= 21:
return 0, 1
scores = [ 0, 0 ]
for rolls, count in dirac_rolls.items():
newPlayerPosition = (playerPosition + rolls) % 10
newPlayerScore = playerScore + newPlayerPosition + 1
wins_now = [ count * win for win in reversed(roll_dirac(opponentPosition, newPlayerPosition, opponentScore, newPlayerScore)) ]
for player in range(2):
scores[player] += wins_now[player]
return scores
def part2(positions):
scores = [0] * PLAYER_COUNT
results = roll_dirac(*positions, *scores)
return max(results)
def main(args = ()):
fileName = "day21.txt" if len(args) < 1 else args[0]
positions = []
with open(fileName) as lines:
for line in lines:
positions.append(int(line.split(":")[-1]) - 1)
print("Part 1:", part1(positions[:]))
print("Part 2:", part2(positions))
if __name__ == "__main__":
sys.exit(main(sys.argv[1:]))