Exemplo n.º 1
0
        /// <summary>
        /// If multiple paths are existing to a square, at a branch, always chose the first one in the X,Y order.
        /// </summary>
        public static Path SearchOptimalPath(VisitedSquare to)
        {
            var ret = new Path();

            var current = to;

            while (current.VisitedFrom != null)
            {
                ret.Steps.AddFirst(current.Coordinate);
                current = current.VisitedFrom.OrderBy(sq => sq.Coordinate.X).ThenBy(sq => sq.Coordinate.Y).First();
            }

            return(ret);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Searches for the shortest path for each reachable enemy's adjacent square.
        /// </summary>
        static public IDictionary <Player, List <Path> > ReachableEnemiesAndShortestPaths(Map map, Player fromPlayer)
        {
            bool newSquareVisitedThisStep       = true;
            List <VisitedSquare> visitedSquares = new List <VisitedSquare>()
            {
                new VisitedSquare()
                {
                    Coordinate  = fromPlayer.Location,
                    VisitedFrom = null,
                    InStep      = 0
                }
            };
            int currentStep = 1;

            var wallLocations   = map.Walls.Select(w => w.Location);
            var playerLocations = map.Players.Select(p => p.Location);

            // Visit the map starting from the given location
            // Create a structure where the visited squares are stored
            // also store that in which step they have been visited and from which square
            while (newSquareVisitedThisStep)
            {
                newSquareVisitedThisStep = false;

                var squaresFromLastStep = visitedSquares.Where(vs => vs.InStep == currentStep - 1).ToList();
                var squaresAlreadyVisitedBeforeCurrentStep = visitedSquares.Select(s => s.Coordinate).ToList();

                foreach (var square in squaresFromLastStep)
                {
                    var possiblenewCoordinates = new List <Coordinate>()
                    {
                        new Coordinate(square.Coordinate.X + 1, square.Coordinate.Y),
                        new Coordinate(square.Coordinate.X - 1, square.Coordinate.Y),
                        new Coordinate(square.Coordinate.X, square.Coordinate.Y + 1),
                        new Coordinate(square.Coordinate.X, square.Coordinate.Y - 1),
                    };

                    foreach (var newCoordinate in possiblenewCoordinates)
                    {
                        if (wallLocations.Contains(newCoordinate) || playerLocations.Contains(newCoordinate) || squaresAlreadyVisitedBeforeCurrentStep.Contains(newCoordinate))
                        {
                            continue;
                        }

                        var visitedSquare = visitedSquares.FirstOrDefault(sq => sq.Coordinate == newCoordinate);

                        if (visitedSquare == null)
                        {
                            var squareToAdd = new VisitedSquare()
                            {
                                Coordinate = newCoordinate,
                                InStep     = currentStep,
                            };
                            squareToAdd.VisitedFrom.Add(square);

                            visitedSquares.Add(squareToAdd);
                        }
                        else // square has been already visited from an other square in this step
                        {
                            visitedSquare.VisitedFrom.Add(square);
                        }

                        newSquareVisitedThisStep = true;
                    }
                }

                currentStep++;
            }

            // Calculate the squares which are adjacent to enemies
            // and they can be possibly reached (no wall, no other player unless its the current player already standing there)
            var adjacentPossiblyReachableSquaresToEnemies = new Dictionary <Player, List <Coordinate> >();

            var enemies = map.Players.Where(p => p.Team != fromPlayer.Team);

            foreach (var enemy in enemies)
            {
                var enemyLocation = enemy.Location;
                adjacentPossiblyReachableSquaresToEnemies.Add(enemy, new List <Coordinate>());

                var rightSquare = new Coordinate(enemyLocation.X + 1, enemyLocation.Y);
                if ((!wallLocations.Contains(rightSquare) && !playerLocations.Contains(rightSquare)) ||
                    rightSquare == fromPlayer.Location)
                {
                    adjacentPossiblyReachableSquaresToEnemies[enemy].Add(rightSquare);
                }

                var leftSquare = new Coordinate(enemyLocation.X - 1, enemyLocation.Y);
                if ((!wallLocations.Contains(leftSquare) && !playerLocations.Contains(leftSquare)) ||
                    leftSquare == fromPlayer.Location)
                {
                    adjacentPossiblyReachableSquaresToEnemies[enemy].Add(leftSquare);
                }

                var upSquare = new Coordinate(enemyLocation.X, enemyLocation.Y + 1);
                if ((!wallLocations.Contains(upSquare) && !playerLocations.Contains(upSquare)) ||
                    upSquare == fromPlayer.Location)
                {
                    adjacentPossiblyReachableSquaresToEnemies[enemy].Add(upSquare);
                }

                var downSquare = new Coordinate(enemyLocation.X, enemyLocation.Y - 1);
                if ((!wallLocations.Contains(downSquare) && !playerLocations.Contains(downSquare)) ||
                    downSquare == fromPlayer.Location)
                {
                    adjacentPossiblyReachableSquaresToEnemies[enemy].Add(downSquare);
                }
            }

            // search these adjacent square in the visit structure.
            // Create the optimal path to each of them.
            var enemiesWithPathsToAdjacentSquares = new Dictionary <Player, List <Path> >();

            foreach (KeyValuePair <Player, List <Coordinate> > enemyWithAdjacentSqures in adjacentPossiblyReachableSquaresToEnemies)
            {
                foreach (Coordinate adjSquare in enemyWithAdjacentSqures.Value)
                {
                    var visited = visitedSquares.FirstOrDefault(vs => vs.Coordinate == adjSquare);

                    if (visited != null)
                    {
                        var paths = SearchOptimalPath(visited);

                        if (!enemiesWithPathsToAdjacentSquares.ContainsKey(enemyWithAdjacentSqures.Key))
                        {
                            enemiesWithPathsToAdjacentSquares.Add(enemyWithAdjacentSqures.Key, new List <Path>());
                        }

                        enemiesWithPathsToAdjacentSquares[enemyWithAdjacentSqures.Key].Add(paths);
                    }
                }
            }

            // Out of all reachable adjacent squares of an enemy, search the shortest ones, and return them
            var enemiesWithPathsToClosestAdjacentSquares = new Dictionary <Player, List <Path> >();

            foreach (var item in enemiesWithPathsToAdjacentSquares)
            {
                int minLength = item.Value.Min(p => p.Length);
                enemiesWithPathsToClosestAdjacentSquares.Add(item.Key, item.Value.Where(p => p.Length == minLength).ToList());
            }

            return(enemiesWithPathsToClosestAdjacentSquares);
        }