public void DoWork() { path = new Queue <T>(); HashSet <T> closedSet = new HashSet <T>(); PathfindingPriorityQueue <T> openSet = new PathfindingPriorityQueue <T>(); openSet.Enqueue(startTile, 0); Dictionary <T, T> came_from = new Dictionary <T, T>(); Dictionary <T, float> g_score = new Dictionary <T, float> { { startTile, 0 } }; Dictionary <T, float> f_score = new Dictionary <T, float> { { startTile, costEstimateFunc(startTile, endTile) } }; while (openSet.Count > 0) { T current = openSet.Dequeue(); if (ReferenceEquals(current, endTile)) { Reconstruct_path(came_from, current); return; } closedSet.Add(current); foreach (T edge_neighbor in current.GetNeighbors()) { T neighbor = edge_neighbor; if (closedSet.Contains(neighbor)) { continue; } float total_pathfinding_cost_to_neighbor = neighbor.AggregateCostToEnter(g_score[current], current, unit); float tentative_g_score = total_pathfinding_cost_to_neighbor; if (openSet.Contains(neighbor) && tentative_g_score >= g_score[neighbor]) { continue; } came_from[neighbor] = current; g_score[neighbor] = tentative_g_score; f_score[neighbor] = g_score[neighbor] + costEstimateFunc(neighbor, endTile); openSet.EnqueueOrUpdate(neighbor, f_score[neighbor]); } } }
public void ExecutePathfindingStep() { Node <Tile> currentNode = openSet.Dequeue(); if (currentNode == EndNode) { ConstructPath(); return; } closedSet.Add(currentNode); foreach (Edge <Tile> neighbouringEdge in currentNode.Edges) { Node <Tile> neighbor = neighbouringEdge.Node; if (closedSet.Contains(neighbor)) { continue; } float movementCostToNeighbor = neighbor.Data.MovementCost * DistanceBetween(currentNode, neighbor); float tentativeGScore = currentNode.GCost + movementCostToNeighbor; if (openSet.Contains(neighbor) && tentativeGScore >= neighbor.GCost) { continue; } cameFrom[neighbor] = currentNode; neighbor.GCost = tentativeGScore; neighbor.HCost = CalculateHeuristicCost(neighbor, EndNode); openSet.EnqueueOrUpdate(neighbor, neighbor.FCost); } }
public Path_AStar(World world, Tile tileStart, Pathfinder.GoalEvaluator isGoal, Pathfinder.PathfindingHeuristic costEstimate) { float startTime = Time.realtimeSinceStartup; // Set path to empty Queue so that there always is something to check count on path = new Queue <Tile>(); // if tileEnd is null, then we are simply scanning for the nearest objectType. // We can do this by ignoring the heuristic component of AStar, which basically // just turns this into an over-engineered Dijkstra's algo // Check to see if we have a valid tile graph if (world.tileGraph == null) { world.tileGraph = new Path_TileGraph(world); } // Check to see if we have a valid tile graph if (world.roomGraph == null) { world.roomGraph = new Path_RoomGraph(world); } // A dictionary of all valid, walkable nodes. Dictionary <Tile, Path_Node <Tile> > nodes = world.tileGraph.nodes; // Make sure our start/end tiles are in the list of nodes! if (nodes.ContainsKey(tileStart) == false) { UnityDebugger.Debugger.LogError("Path_AStar", "The starting tile isn't in the list of nodes!"); return; } Path_Node <Tile> start = nodes[tileStart]; /* * Mostly following this pseusocode: * https://en.wikipedia.org/wiki/A*_search_algorithm */ HashSet <Path_Node <Tile> > closedSet = new HashSet <Path_Node <Tile> >(); /* * List<Path_Node<Tile>> openSet = new List<Path_Node<Tile>>(); * openSet.Add( start ); */ PathfindingPriorityQueue <Path_Node <Tile> > openSet = new PathfindingPriorityQueue <Path_Node <Tile> >(); openSet.Enqueue(start, 0); Dictionary <Path_Node <Tile>, Path_Node <Tile> > came_From = new Dictionary <Path_Node <Tile>, Path_Node <Tile> >(); Dictionary <Path_Node <Tile>, float> g_score = new Dictionary <Path_Node <Tile>, float>(); g_score[start] = 0; Dictionary <Path_Node <Tile>, float> f_score = new Dictionary <Path_Node <Tile>, float>(); f_score[start] = costEstimate(start.data); while (openSet.Count > 0) { Path_Node <Tile> current = openSet.Dequeue(); // Check to see if we are there. if (isGoal(current.data)) { Duration = Time.realtimeSinceStartup - startTime; Reconstruct_path(came_From, current); return; } closedSet.Add(current); foreach (Path_Edge <Tile> edge_neighbor in current.edges) { Path_Node <Tile> neighbor = edge_neighbor.node; if (closedSet.Contains(neighbor)) { continue; // ignore this already completed neighbor } float pathfinding_cost_to_neighbor = neighbor.data.PathfindingCost * Dist_between(current, neighbor); float tentative_g_score = g_score[current] + pathfinding_cost_to_neighbor; if (openSet.Contains(neighbor) && tentative_g_score >= g_score[neighbor]) { continue; } came_From[neighbor] = current; g_score[neighbor] = tentative_g_score; f_score[neighbor] = g_score[neighbor] + costEstimate(neighbor.data); openSet.EnqueueOrUpdate(neighbor, f_score[neighbor]); } // foreach neighbour } // while // If we reached here, it means that we've burned through the entire // openSet without ever reaching a point where current == goal. // This happens when there is no path from start to goal // (so there's a wall or missing floor or something). // We don't have a failure state, maybe? It's just that the // path list will be null. Duration = Time.realtimeSinceStartup - startTime; }
public Path_AStar(World world, Tile tileStart, Tile tileEnd, string objectType = null, int desiredAmount = 0, bool canTakeFromStockpile = false, bool lookingForFurn = false) { // if tileEnd is null, then we are simply scanning for the nearest objectType. // We can do this by ignoring the heuristic component of AStar, which basically // just turns this into an over-engineered Dijkstra's algo // Check to see if we have a valid tile graph if (world.tileGraph == null) { world.tileGraph = new Path_TileGraph(world); } // A dictionary of all valid, walkable nodes. Dictionary <Tile, Path_Node <Tile> > nodes = world.tileGraph.nodes; // Make sure our start/end tiles are in the list of nodes! if (nodes.ContainsKey(tileStart) == false) { Debug.ULogErrorChannel("Path_AStar", "The starting tile isn't in the list of nodes!"); return; } Path_Node <Tile> start = nodes[tileStart]; // if tileEnd is null, then we are simply looking for an inventory object // so just set goal to null. Path_Node <Tile> goal = null; if (tileEnd != null) { if (nodes.ContainsKey(tileEnd) == false) { Debug.ULogErrorChannel("Path_AStar", "The ending tile isn't in the list of nodes!"); return; } goal = nodes[tileEnd]; } /* * Mostly following this pseusocode: * https://en.wikipedia.org/wiki/A*_search_algorithm */ HashSet <Path_Node <Tile> > closedSet = new HashSet <Path_Node <Tile> >(); /* * List<Path_Node<Tile>> openSet = new List<Path_Node<Tile>>(); * openSet.Add( start ); */ PathfindingPriorityQueue <Path_Node <Tile> > openSet = new PathfindingPriorityQueue <Path_Node <Tile> >(); openSet.Enqueue(start, 0); Dictionary <Path_Node <Tile>, Path_Node <Tile> > came_From = new Dictionary <Path_Node <Tile>, Path_Node <Tile> >(); Dictionary <Path_Node <Tile>, float> g_score = new Dictionary <Path_Node <Tile>, float>(); g_score[start] = 0; Dictionary <Path_Node <Tile>, float> f_score = new Dictionary <Path_Node <Tile>, float>(); f_score[start] = Heuristic_cost_estimate(start, goal); while (openSet.Count > 0) { Path_Node <Tile> current = openSet.Dequeue(); // If we have a POSITIONAL goal, check to see if we are there. if (goal != null) { if (current == goal) { Reconstruct_path(came_From, current); return; } } else { // We don't have a POSITIONAL goal, we're just trying to find // some kind of inventory or furniture. Have we reached it? if (current.data.Inventory != null && current.data.Inventory.objectType == objectType && lookingForFurn == false && current.data.Inventory.locked == false) { // Type is correct and we are allowed to pick it up if (canTakeFromStockpile || current.data.Furniture == null || current.data.Furniture.IsStockpile() == false) { // Stockpile status is fine Reconstruct_path(came_From, current); return; } } if (current.data.Furniture != null && current.data.Furniture.ObjectType == objectType && lookingForFurn) { // Type is correct Reconstruct_path(came_From, current); return; } } closedSet.Add(current); foreach (Path_Edge <Tile> edge_neighbor in current.edges) { Path_Node <Tile> neighbor = edge_neighbor.node; if (closedSet.Contains(neighbor)) { continue; // ignore this already completed neighbor } float movement_cost_to_neighbor = neighbor.data.MovementCost * Dist_between(current, neighbor); float tentative_g_score = g_score[current] + movement_cost_to_neighbor; if (openSet.Contains(neighbor) && tentative_g_score >= g_score[neighbor]) { continue; } came_From[neighbor] = current; g_score[neighbor] = tentative_g_score; f_score[neighbor] = g_score[neighbor] + Heuristic_cost_estimate(neighbor, goal); openSet.EnqueueOrUpdate(neighbor, f_score[neighbor]); } // foreach neighbour } // while // If we reached here, it means that we've burned through the entire // openSet without ever reaching a point where current == goal. // This happens when there is no path from start to goal // (so there's a wall or missing floor or something). // We don't have a failure state, maybe? It's just that the // path list will be null. }