// inspired by http://www.redblobgames.com/pathfinding/a-star/introduction.html public virtual PathResult pathFromTo(Tile start, Tile goal, HeuristicPathFinder heuristic, bool playersCanBlockPath = false) { HexRegion region = GameControl.gameSession.mapGenerator.getRegion() as HexRegion; return(pathFromTo(region, start, goal, heuristic, playersCanBlockPath)); }
public virtual PathResult pathFromTo(HexRegion region, Tile start, Tile goal, HeuristicPathFinder heuristic, bool playersCanBlockPath = false) { PathResult pathResult = new PathResult(); PathTile goalPt = new PathTile(goal); // set up lists PriorityQueue <PathTile> frontier = new PriorityQueue <PathTile>(); Dictionary <Vector2, PathTile> explored = new Dictionary <Vector2, PathTile>(); Dictionary <Vector2, PathTile> previous = new Dictionary <Vector2, PathTile>(); Dictionary <Vector2, float> costs = new Dictionary <Vector2, float>(); PathTile crt; crt = new PathTile(start); crt.depth = 0; frontier.Enqueue(crt, 0); previous[crt.tile.index] = null; costs[crt.tile.index] = 0; // start pathfinding while (!frontier.IsEmpty()) { // get current crt = frontier.Dequeue(); // record that the tile was explored explored[crt.tile.index] = crt; if (crt.CompareTo(goalPt)) { // reached goal; search complete pathResult.reachedGoal = true; pathResult.pathCost = costs[crt.tile.index]; break; } // get neighbor tiles List <PathTile> neighbors = new List <PathTile>(); foreach (Tile neighborTile in region.getTileNeighbors(crt.tile.index)) { PathTile neighbor = new PathTile(neighborTile); //neighborPt.cost = crt.cost + costBetween(crt, neighborPt); neighbor.depth = crt.depth + 1; neighbors.Add(neighbor); } // add neighbor tiles to search float cost, priority; foreach (PathTile neighbor in neighbors) { // check if exceeding max depth if (neighbor.depth > maxDepth) { break; } // compute cost float _cost = costBetween(crt, neighbor); // check if path is blocked by another player if (playersCanBlockPath && GameControl.gameSession.checkForPlayersAt(neighbor.tile) != null) { if (!neighbor.CompareTo(goalPt)) // ensures that you can move to a tile with an enemy { _cost = float.PositiveInfinity; // set highest cost to signify that the tile is unreachable } } cost = costs[crt.tile.index] + _cost; if (cost <= maxCost) { if (!costs.ContainsKey(neighbor.tile.index) || cost < costs[neighbor.tile.index]) { costs[neighbor.tile.index] = cost; // compute heuristic priority priority = cost + heuristic.heuristic(neighbor, goalPt); priority -= neighbor.depth * heuristicDepthInfluence; // makes so that tiles closest to goal are more eagerly explored frontier.Enqueue(neighbor, priority); previous[neighbor.tile.index] = crt; } } } } // build list of tiles on path if goal was reached if (pathResult.reachedGoal) { pathResult.addPathtile(goalPt); crt = previous[goal.index]; while (crt != null) { pathResult.addPathtile(crt); crt = previous[crt.tile.index]; } } foreach (PathTile pt in explored.Values) { pathResult.addExploredPathtile(pt); } return(pathResult); }