from tools.aoc import AOCDay from typing import Any class Day(AOCDay): test_solutions_p1 = [739785] test_solutions_p2 = [444356092776315] def part1(self) -> Any: pos = list(map(int, [x.split(": ")[1] for x in self.getInput()])) scores = [0, 0] target_score = 1000 rolls = 0 dice_roll = 0 while scores[0] < target_score and scores[1] < target_score: for player in [0, 1]: this_roll = 0 rolls += 3 for _ in range(3): dice_roll = 1 + (dice_roll % 100) this_roll += dice_roll pos[player] = 1 + (this_roll + pos[player] - 1) % 10 scores[player] += pos[player] if scores[player] >= target_score: break return min(scores) * rolls def roll_dirac(self, pos1, pos2, score1, score2, cache): if (pos1, pos2, score1, score2) in cache: return cache[(pos1, pos2, score1, score2)] p1wins = 0 p2wins = 0 target_score = 21 for roll1 in range(3, 10): tpos1 = 1 + (roll1 + pos1 - 1) % 10 if score1 + tpos1 >= target_score: p1wins += 27 else: for roll2 in range(3, 10): tpos2 = 1 + (roll2 + pos2 - 1) % 10 if score2 + tpos2 >= target_score: p2wins += 27 else: sub_p1wins, sub_p2wins = self.roll_dirac(tpos1, tpos2, score1 + tpos1, score2 + tpos2, cache) p1wins += sub_p1wins p2wins += sub_p2wins cache[(pos1, pos2, score1, score2)] = p1wins, p2wins return p1wins, p2wins def part2(self) -> Any: pos = list(map(int, [x.split(": ")[1] for x in self.getInput()])) wins1, wins2 = self.roll_dirac(pos[0], pos[1], 0, 0, {}) return wins1, wins2