public static GameState Start( GridCell[,] grid, int elfAttackPower = 3) { var gridPair = GridPair.For(grid); GridOperations.CalculateCloseness(gridPair); var elfHitPoints = ImmutableDictionary <int, int> .Empty; var goblinHitPoints = ImmutableDictionary <int, int> .Empty; int height = gridPair.Primary.GetLength(0); int width = gridPair.Primary.GetLength(1); for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { GridCell cell = gridPair.Primary[y, x]; if (cell.IsElf) { elfHitPoints = elfHitPoints.Add(cell.ElfId.Value, 200); } else if (cell.IsGoblin) { goblinHitPoints = goblinHitPoints.Add(cell.GoblinId.Value, 200); } } } return(new GameState(gridPair, elfHitPoints, goblinHitPoints, elfAttackPower)); }
public static (int score, bool totalElfVictory) SolvePart1(string map, bool show = false, int elfAttackPower = 3) { int rounds = 0; GameState g; int startLine = Console.CursorTop; bool combatEnds = false; for (g = GameState.Start(GridOperations.ParseGrid(map), elfAttackPower); !combatEnds; (g, combatEnds) = g.PlayRound()) { rounds += 1; if (show) { Console.SetCursorPosition(0, startLine); ShowGrid(g.Grid); } } bool goblinsWon = g.GoblinHitPoints.Any(kv => kv.Value > 0); int winningTeamHitPointsRemaining = (goblinsWon ? g.GoblinHitPoints : g.ElfHitPoints) .Select(kv => kv.Value) .Where(p => p > 0) .Sum(); return(winningTeamHitPointsRemaining * (rounds - 1), g.ElfHitPoints.All(kv => kv.Value > 0)); }
public (GameState state, bool combatEnds) PlayRound() { bool combatEnds = false; var coordinates = new List <(int x, int y)>(); int height = Grid.GetLength(0); int width = Grid.GetLength(1); for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { GridCell cell = Grid[y, x]; if (cell.IsElf || cell.IsGoblin) { coordinates.Add((x, y)); } } } var elfHitPoints = ElfHitPoints; var goblinHitPoints = GoblinHitPoints; GridCell[,] grid = Grid; for (int i = 0; i < coordinates.Count; ++i) { var xy = coordinates[i]; GridCell unitCell = grid[xy.y, xy.x]; if (!(unitCell.IsElf || unitCell.IsGoblin)) { // Already taken out in an earlier turn this round. continue; } if ((unitCell.IsElf && !goblinHitPoints.Any(kv => kv.Value > 0)) || (unitCell.IsGoblin && !elfHitPoints.Any(kv => kv.Value > 0))) { combatEnds = true; break; } int hitPower = unitCell.IsElf ? elfHitPoints[unitCell.ElfId.Value] : goblinHitPoints[unitCell.GoblinId.Value]; // Move if appropriate. var move = GridOperations.CalculateMove(grid, xy.x, xy.y); if (move.HasValue) { bool isElf = unitCell.IsElf; int unitId = isElf ? unitCell.ElfId.Value : unitCell.GoblinId.Value; RemoveItem(height, width, grid, xy); var newCoordinates = (x : xy.x + move.Value.dx, y : xy.y + move.Value.dy); grid[newCoordinates.y, newCoordinates.x] = isElf ? GridCell.Elf(unitId) : GridCell.Goblin(unitId); GridOperations.CalculateCloseness(_gridPair); coordinates[i] = newCoordinates; } // Attack if appropriate. xy = coordinates[i]; var match = GridOperations.FindBest( grid, xy.x, xy.y, c => { bool isTarget = unitCell.IsElf ? c.IsGoblin : c.IsElf; return(isTarget ? NullIfDead(unitCell.IsElf ? goblinHitPoints[c.GoblinId.Value] : elfHitPoints[c.ElfId.Value]) : default); int?NullIfDead(int v) => v > 0 ? v : default; },