コード例 #1
0
ファイル: GameState.cs プロジェクト: idg10/AoC2018
        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;
                },
コード例 #2
0
        private static bool ProcessOneClosenessStep(
            GridCell[,] lastGrid,
            GridCell[,] newGrid)
        {
            bool changed = false;
            int  height  = lastGrid.GetLength(0);
            int  width   = lastGrid.GetLength(1);

            for (int y = 0; y < height; ++y)
            {
                for (int x = 0; x < width; ++x)
                {
                    GridCell lastCell = lastGrid[y, x];
                    GridCell newCell  = lastCell;
                    if (!lastCell.IsWall &&
                        ((!lastCell.IsElf && !lastCell.DistanceToElfInRange.HasValue) ||
                         (!lastCell.IsGoblin && !lastCell.DistanceToGoblinInRange.HasValue)))
                    {
                        if (!lastCell.IsElf && !newCell.DistanceToElfInRange.HasValue)
                        {
                            var match = FindNearest(
                                c => c.IsElf ? 0 : c.DistanceToElfInRange,
                                (c, _) => c.IsElf ? (x, y) : c.ElfInRangePosition.Value);
                            if (match.HasValue)
                            {
                                (GridCell elfNearest, int hitX, int hitY) = match.Value;
                                int  inRangeX, inRangeY;
                                bool hitWasOnUnitItself = !elfNearest.DistanceToElfInRange.HasValue;
                                if (hitWasOnUnitItself)
                                {
                                    inRangeX = x;
                                    inRangeY = y;
                                }
                                else
                                {
                                    (inRangeX, inRangeY) = lastGrid[hitY, hitX].ElfInRangePosition.Value;
                                }
                                newCell = newCell.WithDistanceToElfInRange(
                                    (elfNearest.DistanceToElfInRange ?? 0) + 1,
                                    elfNearest.ElfId.Value,
                                    inRangeX,
                                    inRangeY);
                                changed = true;
                            }
                        }
                        if (!newCell.IsGoblin && !newCell.DistanceToGoblinInRange.HasValue)
                        {
                            var match = FindNearest(
                                c => c.IsGoblin ? 0 : c.DistanceToGoblinInRange,
                                (c, _) => c.IsGoblin ? (x, y) : c.GoblinInRangePosition.Value);
                            if (match.HasValue)
                            {
                                (GridCell goblinNearest, int hitX, int hitY) = match.Value;
                                int  inRangeX, inRangeY;
                                bool hitWasOnUnitItself = !goblinNearest.DistanceToGoblinInRange.HasValue;
                                if (hitWasOnUnitItself)
                                {
                                    inRangeX = x;
                                    inRangeY = y;
                                }
                                else
                                {
                                    (inRangeX, inRangeY) = lastGrid[hitY, hitX].GoblinInRangePosition.Value;
                                }
                                newCell = newCell.WithDistanceToGoblinInRange(
                                    (goblinNearest.DistanceToGoblinInRange ?? 0) + 1,
                                    goblinNearest.GoblinId.Value,
                                    inRangeX,
                                    inRangeY);
                                changed = true;
                            }
                        }

                        (GridCell cell, int x, int y)? FindNearest(
                            Func <GridCell, int?> distanceSelector,
                            Func <GridCell, (int x, int y), (int x, int y)> orderingSelector)
                        {
                            return(FindBest(
                                       lastGrid,
                                       x,
                                       y,
                                       c =>
                            {
                                var distance = distanceSelector(c);

                                return distance == 0 ? distance :
                                (c.IsGoblin || c.IsElf) ? default : distance;
                            },
                                       orderingSelector));
                        }
                    }

                    newGrid[y, x] = newCell;
                }
            }

            return(changed);
        }