Finally a Day 21 part 2 solution

I was making this way too hard.
This commit is contained in:
2021-12-24 22:39:33 -06:00
parent f29dd5efa0
commit a2a5921219
2 changed files with 25 additions and 52 deletions

View File

@ -1,2 +1,2 @@
Player 1 starting position: 4 Player 1 starting position: 2
Player 2 starting position: 8 Player 2 starting position: 5

View File

@ -2,11 +2,6 @@
internal class Day21 : Day internal class Day21 : Day
{ {
private record struct GameState((int p1, int p2) Positions, int Turn, (int p1, int p2) Score, (long p1, long p2) Wins, int RollVal, int TotalRolls, int TotalRounds)
{
public override int GetHashCode() => HashCode.Combine(Positions.p1, Positions.p2, Turn, RollVal, TotalRounds);
}
internal override void Go() internal override void Go()
{ {
var lines = Util.ReadAllLines("inputs/21.txt"); var lines = Util.ReadAllLines("inputs/21.txt");
@ -35,12 +30,7 @@ internal class Day21 : Day
{ {
using var t = new Timer(); using var t = new Timer();
var playerPos = new int[2] var (p1wins, p2wins) = PlayQuantumGame(player1Pos - 1, player2Pos - 1, 0, 0, 21);
{
player1Pos,
player2Pos,
};
var (p1wins, p2wins) = PlayQuantumGame(new List<int>(playerPos), 21);
t.Stop(); t.Stop();
Logger.Log($"<+black>> part2: p1: {p1wins:N0}, p2: {p2wins:N0} -> <+white>{Math.Max(p1wins, p2wins)}<r>"); Logger.Log($"<+black>> part2: p1: {p1wins:N0}, p2: {p2wins:N0} -> <+white>{Math.Max(p1wins, p2wins)}<r>");
@ -78,57 +68,40 @@ internal class Day21 : Day
return ((playerPos + dieVal - 1) % 10) + 1; return ((playerPos + dieVal - 1) % 10) + 1;
} }
private static readonly Dictionary<int, GameState> cachedWinCases = new(); private static readonly Dictionary<(int, int, int, int), (long, long)> cachedWinCases = new();
private static (long, long) PlayQuantumGame(List<int> playerPos, int maxScore, List<int>? playerScores = null, int turn = 0, int rollNum = 0, int rollVal = 0, int totalRounds = 0, int totalRolls = 0) private static (long, long) PlayQuantumGame(int p1Pos, int p2Pos, int p1Score, int p2Score, int maxScore)
{ {
playerScores ??= new List<int> { 0, 0 }; if (p1Score >= maxScore)
if (cachedWinCases.TryGetValue(HashCode.Combine(playerPos[0], playerPos[1], turn, rollVal, totalRounds), out GameState winState))
{ {
return winState.Wins; return (1, 0);
}
if (p2Score >= maxScore)
{
return (0, 1);
}
if (cachedWinCases.TryGetValue((p1Pos, p2Pos, p1Score, p2Score), out (long, long) numWins))
{
return numWins;
} }
var wins = (0L, 0L); (long p1, long p2) wins = (0, 0);
while (true) for (int d1 = 1; d1 <= 3; d1++)
{ {
totalRounds++; for (int d2 = 1; d2 <= 3; d2++)
for (int i = rollNum; i < 3; i++)
{ {
totalRolls++; for (int d3 = 1; d3 <= 3; d3++)
var twoWins = PlayQuantumGame(new List<int>(playerPos), maxScore, new List<int>(playerScores), turn, i + 1, 2, totalRounds, totalRolls);
var threeWins = PlayQuantumGame(new List<int>(playerPos), maxScore, new List<int>(playerScores), turn, i + 1, 3, totalRounds, totalRolls);
wins = (wins.Item1 + twoWins.Item1 + threeWins.Item1, wins.Item2 + twoWins.Item2 + threeWins.Item2);
playerPos[turn] = PlayOneRoll(playerPos[turn], 1);
rollVal = 1;
}
if (rollNum == 3)
{
playerPos[turn] = PlayOneRoll(playerPos[turn], rollVal);
}
playerScores[turn] += playerPos[turn];
if (playerScores[turn] >= maxScore)
{
if (turn == 0)
{ {
wins.Item1++; var newP1Pos = (p1Pos + d1 + d2 + d3) % 10;
var newP1Score = p1Score + newP1Pos + 1;
var (p2wins, p1wins) = PlayQuantumGame(p2Pos, newP1Pos, p2Score, newP1Score, maxScore);
wins.p1 += p1wins;
wins.p2 += p2wins;
} }
else
{
wins.Item2++;
}
GameState state = new((playerPos[0], playerPos[1]), turn, (playerScores[0], playerScores[1]), wins, rollVal, totalRolls, totalRounds);
cachedWinCases[state.GetHashCode()] = state;
break;
} }
turn = 1 - turn;
rollNum = 0;
rollVal = 0;
} }
cachedWinCases[(p1Pos, p2Pos, p1Score, p2Score)] = wins;
return wins; return wins;
} }
} }