public Dictionary <int, int> getCostMap(int cellId, WARGrid grid) { // the map itself var map = new Dictionary <int, int>(); // Queue to store the cells to process starting with out target cellId var opened = new Queue <enqueued>(); opened.Enqueue(new enqueued { id = cellId, cost = 0 }); // the cells we've seen before var closed = new HashSet <int>(); // make sure we dont come back to the origin closed.Add(cellId); // while we have cells left to process while (opened.Count > 0) { // get the next cell to process var cell = opened.Dequeue(); // assign the cost to the map map.Add(cell.id, cell.cost); foreach (var neighbor in grid.GetCell(cell.id).neighbors) { // if we're looking at a cell for the first time if (!closed.Contains(neighbor)) { // process their children opened.Enqueue(new enqueued { id = neighbor, cost = cell.cost + 1 }); // and add it to the list of cells we've processed closed.Add(neighbor); } } } // return the map we just filled return(map); }
// calculate the final cell cost given our source, target and grid private int cellCost(int cell, Dictionary <int, int> sourceCostMap, Dictionary <int, int> targetCostMap, WARGrid grid) { var cost = sourceCostMap[cell] + targetCostMap[cell]; return(cost); // + grid.GetCell(cell).pathFindingCost }
public List <int> findPath(int source, int target, WARGrid grid) { // create the cost map for our source and target var sourceCostMap = getCostMap(source, grid); var targetCostMap = getCostMap(target, grid); // traverse our grid using cost maps to determine path // path to return var path = new List <int>(); // map from cellId to the Node representing it var nodeMap = new Dictionary <int, Node>(); nodeMap.Add(source, new Node(source)); // map to store the cell costs var finalCostMap = new Dictionary <int, int>(); finalCostMap.Add(source, cellCost(source, sourceCostMap, targetCostMap, grid)); // set of nodes we need to process var opened = new List <int> { source }; // set of nodes we have processed var closed = new List <int>(); // while there are still cells to process while (opened.Count > 0) { // find the cell with the lowest cost var cell = opened.Aggregate( (min, id) => { return(finalCostMap[id] < finalCostMap[min] ? id : min); } ); // remove the cell with the lowest cost and add it to closed opened.Remove(cell); closed.Add(cell); // if we found the current target then we have done our job if (cell == target) { // create the path by walking parents of final node path = getPathFromNodes(nodeMap[cell]).Select(node => node.id).ToList(); // then reverse it because we calculated the path from target to start path.Reverse(); return(path); } // determine if we add our neighbors to the traversal path foreach (var neighbor in grid.GetCell(cell).neighbors.Where(id => !closed.Contains(id))) { // if we have not opened this cell, or the path to this cell is shorter than previously found if (!opened.Contains(neighbor) || getPathFromNodes(nodeMap[cell]).Count + 1 < getPathFromNodes(nodeMap[neighbor]).Count) { // add the neighbor to the nodeMap, linking its parent to the node at cell nodeMap.Add(neighbor, new Node(neighbor, nodeMap[cell])); // add the neighbor to the final cost map using cellCost finalCostMap.Add(neighbor, cellCost(neighbor, sourceCostMap, targetCostMap, grid)); // if we haven't opened this neighbor already, open it if (!opened.Contains(neighbor)) { opened.Add(neighbor); } } } } Debug.LogError("Reached end of Astar traversal without finding target"); return(path); }