#pragma warning disable class Program { static string[] input; static int P1Start; static int P2Start; public static void Main() { input = File.ReadAllLines(@"../../../../Input.in"); P1Start = (int)Char.GetNumericValue(input[0][^1]); P2Start = (int)Char.GetNumericValue(input[1][^1]); var die = new DeterministicDie(); var players = new List<Player> { new Player(P1Start), new Player(P2Start), }; var CurrentPlayer = 0; while (players.All(p => p.CurScore < 1000)) { players[CurrentPlayer].Move(die.Roll() + die.Roll() + die.Roll()); CurrentPlayer = (CurrentPlayer == 0) ? 1 : 0; } var losingPlayer = players.OrderBy(p => p.CurScore).First(); Console.WriteLine("The answer to part 1 is: " + (losingPlayer.CurScore * die.TimesRolled).ToString()); Dictionary<int, int> diracRolls = DiracRoll(); var startUniverse = (new Player(P1Start), new Player(P2Start), 0); var universes = new Dictionary<(Player P1, Player P2, int CurPlayer), long>() { [startUniverse] = 1 }; long P1Wins = 0; long P2Wins = 0; var winningScore = 21; while (universes.Count > 0) { var nextUniverses = new Dictionary<(Player, Player, int), long>(); foreach (var (universe, universeCount) in universes) { foreach (var (roll, timesRolled) in diracRolls) { Player newP1 = universe.P1.Copy(); Player newP2 = universe.P2.Copy(); if (universe.CurPlayer == 0) { newP1.Move(roll); if (newP1.CurScore >= winningScore) { P1Wins += universeCount * timesRolled; continue; } } else { newP2.Move(roll); if (newP2.CurScore >= winningScore) { P2Wins += universeCount * timesRolled; continue; } } var CurPlayer = (universe.CurPlayer + 1) % 2; var newUniverse = (newP1, newP2, CurPlayer); if (!nextUniverses.ContainsKey(newUniverse)) nextUniverses[newUniverse] = 0; nextUniverses[newUniverse] += universeCount * timesRolled; } } universes = nextUniverses; } Console.WriteLine("The winning player wins in " + Math.Max(P1Wins, P2Wins).ToString() + " universes"); } class DeterministicDie { public int TimesRolled = 0; public int LastRoll = 100; public int Roll() { TimesRolled++; LastRoll++; if (LastRoll > 100) LastRoll %= 100; return LastRoll; } } class Player { public int CurSpace; public int CurScore; public static bool operator ==(Player p1, Player p2) { return (p1.CurSpace == p2.CurSpace) && (p1.CurScore == p2.CurScore); } public static bool operator !=(Player p1, Player p2) { return !(p1 == p2); } public override int GetHashCode() { return (CurSpace, CurScore).GetHashCode(); } public override bool Equals(object obj) { return this == (Player)obj; } public override string ToString() => $"Space: {CurSpace}, Score: {CurScore}"; public void Move(int spaces) { CurSpace += spaces; if (CurSpace > 10) CurSpace %= 10; if (CurSpace == 0) CurSpace = 10; CurScore += CurSpace; } public Player Copy() { return new Player(CurSpace, CurScore); } public Player(int startSpace, int startScore = 0) { CurSpace = startSpace; CurScore = startScore; } } public static Dictionary<int, int> DiracRoll() { var ans = new Dictionary<int, int>(); foreach (var d1 in Enumerable.Range(1, 3)) { foreach (var d2 in Enumerable.Range(1, 3)) { foreach (var d3 in Enumerable.Range(1, 3)) { var CurRoll = d1 + d2 + d3; if (!ans.ContainsKey(CurRoll)) ans[CurRoll] = 0; ans[CurRoll] += 1; } } } return ans; } }