Пример #1
0
    /// <summary>
    /// Given an array of tiles and a starting coordinate,
    /// find all reachable tiles (and paths to get to those tiles).
    /// This is implemented using a modified form of Djikstra's algorithm.
    ///
    /// We return a dictionary of <option, tuple<cost-to-option, path-to-option>>.
    /// </summary>
    /// <param name="tiles"></param>
    /// <param name="startCoord"></param>
    public static Dictionary <Coordinate, Tuple <int, List <Coordinate> > > FindReachableTiles(
        Unit unit,
        Tile[,] tiles)
    {
        int rows = Util.GetRows(tiles);
        int cols = Util.GetCols(tiles);

        int[,] dist        = new int[rows, cols];
        Coordinate[,] prev = new Coordinate[rows, cols];

        var frontier = new MinHeap <TileCoordinateNode>();

        TileCoordinate startTileCoordinate = new TileCoordinate(
            tiles[unit.location.r, unit.location.c],
            unit.location);

        TileCoordinateNode startNode = new TileCoordinateNode(startTileCoordinate, 0);

        frontier.Insert(startNode);

        for (int r = 0; r < rows; ++r)
        {
            for (int c = 0; c < cols; ++c)
            {
                Coordinate coord = new Coordinate(r, c);

                if (!coord.Equals(unit.location))
                {
                    dist[coord.r, coord.c] = int.MaxValue;
                    prev[coord.r, coord.c] = null;
                }
                else
                {
                    dist[coord.r, coord.c] = 0;
                    prev[coord.r, coord.c] = null; // doesn't matter for start coord
                }
            }
        }

        while (frontier.HeapSize() > 0)
        {
            TileCoordinateNode node           = frontier.Pop();
            TileCoordinate     tileCoordinate = node.tileCoordinate;
            Coordinate         coordinate     = tileCoordinate.coordinate;

            foreach (TileCoordinate adjacentTileCoord
                     in GetAllowableAdjacentTiles(tiles, coordinate, unit.board, unit.team))
            {
                Coordinate adjacentCoord = adjacentTileCoord.coordinate;

                // watch for overflow here
                int calculatedDist = dist[coordinate.r, coordinate.c]
                                     + adjacentTileCoord.tile.movementCost;

                bool calculatedDistPreferrable
                    = dist[adjacentCoord.r, adjacentCoord.c] == int.MaxValue ||
                      calculatedDist < dist[adjacentCoord.r, adjacentCoord.c];

                if (calculatedDistPreferrable && calculatedDist <= unit.movementPoints)
                {
                    dist[adjacentCoord.r, adjacentCoord.c] = calculatedDist;
                    prev[adjacentCoord.r, adjacentCoord.c] = coordinate;

                    TileCoordinateNode adjacentNode
                        = new TileCoordinateNode(adjacentTileCoord, calculatedDist);

                    if (!frontier.Contains(adjacentNode))
                    {
                        frontier.Insert(adjacentNode);
                    }
                    else
                    {
                        frontier.DecreaseKey(adjacentNode, adjacentNode);
                    }
                }
            }
        }

        // djikstra finished
        // now processing and adding to the return dict

        var answer = new Dictionary <Coordinate, Tuple <int, List <Coordinate> > >();

        for (int r = 0; r < rows; ++r)
        {
            for (int c = 0; c < cols; ++c)
            {
                Coordinate targetCoord      = new Coordinate(r, c);
                int        distanceToTarget = dist[r, c];

                // cell must also be empty, unless it is the starting coord
                if (distanceToTarget != int.MaxValue &&
                    (targetCoord.Equals(unit.location) ||
                     unit.board[targetCoord.r, targetCoord.c] is null))
                {
                    /*
                     * Console.WriteLine($"Distance from {unit.currentLocation}" +
                     *  $" to {targetCoordinate}" +
                     *  $" is: {distanceToTarget}");
                     */

                    //string ans = targetCoordinate.ToString();
                    List <Coordinate> pathToTarget = new List <Coordinate>();

                    Coordinate currentCoord = targetCoord;

                    // all paths lead to the starting coordinate
                    // and the starting coordinate's prev is null
                    while (prev[currentCoord.r, currentCoord.c] != null)
                    {
                        // ans = $"{prev[targetCoordinate.r, targetCoordinate.c]}, {ans}";
                        pathToTarget.Insert(0, prev[currentCoord.r, currentCoord.c]);

                        currentCoord = prev[currentCoord.r, currentCoord.c];
                    }

                    pathToTarget.Add(targetCoord);

                    // Console.WriteLine($"path to {targetCoord}: {String.Join(", ", pathToTarget)}");

                    answer.Add(
                        targetCoord,
                        new Tuple <int, List <Coordinate> >(
                            distanceToTarget,
                            pathToTarget)
                        );
                }
            }
        }

        return(answer);
    }
Пример #2
0
    /// <summary>
    /// Given an array of tiles and a starting coordinate,
    /// find all reachable tiles (and paths to get to those tiles).
    /// This is implemented using a modified form of Djikstra's algorithm.
    /// </summary>
    /// <param name="tiles"></param>
    /// <param name="startCoord"></param>
    public static void FindReachableTiles(
        int rows,
        int cols,
        int[,] dist,
        Coordinate[,] prev,
        Tile[,] tiles,
        Coordinate startCoord,
        int movementPoints)
    {
        var frontier = new MinHeap <TileCoordinateNode>();

        TileCoordinate startTileCoordinate = new TileCoordinate(
            tiles[startCoord.r, startCoord.c],
            startCoord);

        TileCoordinateNode startNode = new TileCoordinateNode(startTileCoordinate, 0);

        frontier.Insert(startNode);

        for (int r = 0; r < rows; ++r)
        {
            for (int c = 0; c < cols; ++c)
            {
                Coordinate coord = new Coordinate(r, c);

                if (!coord.Equals(startCoord))
                {
                    dist[coord.r, coord.c] = int.MaxValue;
                    prev[coord.r, coord.c] = null;
                }
                else
                {
                    dist[coord.r, coord.c] = 0;
                    prev[coord.r, coord.c] = null; // doesn't matter for start coord
                }
            }
        }

        while (frontier.HeapSize() > 0)
        {
            TileCoordinateNode node           = frontier.Pop();
            TileCoordinate     tileCoordinate = node.tileCoordinate;
            Coordinate         coordinate     = tileCoordinate.coordinate;

            foreach (TileCoordinate adjacentTileCoord
                     in GetAdjacentTiles(tiles, coordinate))
            {
                Coordinate adjacentCoord = adjacentTileCoord.coordinate;

                // watch for overflow here
                int calculatedDist = dist[coordinate.r, coordinate.c]
                                     + adjacentTileCoord.tile.movementCost;

                bool calculatedDistPreferrable
                    = dist[adjacentCoord.r, adjacentCoord.c] == int.MaxValue ||
                      calculatedDist < dist[adjacentCoord.r, adjacentCoord.c];

                if (calculatedDistPreferrable && calculatedDist <= movementPoints)
                {
                    dist[adjacentCoord.r, adjacentCoord.c] = calculatedDist;
                    prev[adjacentCoord.r, adjacentCoord.c] = coordinate;

                    TileCoordinateNode adjacentNode
                        = new TileCoordinateNode(adjacentTileCoord, calculatedDist);

                    if (!frontier.Contains(adjacentNode))
                    {
                        frontier.Insert(adjacentNode);
                    }
                    else
                    {
                        frontier.DecreaseKey(adjacentNode, adjacentNode);
                    }
                }
            }
        }
    }