summaryrefslogtreecommitdiffstats
path: root/21.py
diff options
context:
space:
mode:
Diffstat (limited to '21.py')
-rw-r--r--21.py39
1 files changed, 39 insertions, 0 deletions
diff --git a/21.py b/21.py
new file mode 100644
index 0000000..674d95e
--- /dev/null
+++ b/21.py
@@ -0,0 +1,39 @@
+from itertools import count
+from re import compile as re_compile
+from utils import open_day
+from functools import cache, reduce
+
+pattern = re_compile(r'Player \d+ starting position: (\d+)')
+with open_day(21) as f:
+ positions = tuple(int(pattern.match(line).group(1)) - 1 for line in f)
+
+def part1(positions):
+ poss = list(positions)
+ scores = [0 for _ in poss]
+ for roll in count():
+ rolled = (3 * roll + 1) * 3 + 3
+ player = roll % len(poss)
+ poss[player] += rolled
+ poss[player] %= 10
+ scores[player] += poss[player] + 1
+ if scores[player] >= 1000:
+ return [score * (roll + 1) * 3 for score in scores if score < 1000][0]
+
+@cache
+def part2(positions, scores=(0, 0), player=0, maxscore=21):
+ dirac_triples = ((1, 3), (3, 4), (6, 5), (7, 6), (6, 7), (3, 8), (1, 9))
+ def times(t, c): return (t[0] * c, t[1] * c)
+ def tupsum(a, b): return (a[0] + b[0], a[1] + b[1])
+ def turn(rolled):
+ nposs = list(positions)
+ nscores = list(scores)
+ nposs[player] += rolled
+ nposs[player] %= 10
+ nscores[player] += nposs[player] + 1
+ if nscores[player] >= maxscore:
+ return (player == 0, player != 0)
+ return part2(tuple(nposs), tuple(nscores), int(not player), maxscore)
+ return reduce(tupsum, (times(turn(roll), count) for count, roll in dirac_triples))
+
+print(part1(positions))
+print(max(part2(positions)))