public Path CreateCompletePath(GridClustered _GridClustered, Dictionary <Tile, Path> _AllFirstParts, Dictionary <Tile, Path> _AllLastParts) { // init path with the last part which connect the last bridge with the goal Path path = new Path(_AllLastParts[m_Bridge.End]); // Save the current bridge to reach Bridge bridgeToReach = m_Bridge; // move backward in the bridgeStep list BridgeStep step = this.m_Previous; // Each iteration, merge the right path before the current path while (step != null) { Cluster cluster = _GridClustered.GetClusterOfTile(bridgeToReach.Start); Bridge previousBridge = step.Bridge; Path partPath = bridgeToReach.GetPathToBridgeBeginningWith(previousBridge.End); path.MergeBefore(partPath.ReversedPath()); step = step.m_Previous; bridgeToReach = previousBridge; } path.MergeBefore(_AllFirstParts[bridgeToReach.Start]); return(path); }
public GridClustered CreateGridClustered(int _SizeClusterRows, int _SizeClusterColumns) { string pathFile = $@"{Application.persistentDataPath}/Maps/{m_FileName}"; GridClustered grid = new GridClustered(pathFile, m_GridRenderer, _SizeClusterRows, _SizeClusterColumns); return(grid); }
private void GenerateClusters(int _RowsSize, int _ColumnsSize) { if (m_GameGrid == null) { return; } m_GridClustered = new GridClustered(m_GameGrid, _RowsSize, _ColumnsSize); m_SizeClusterRows = _RowsSize; m_SizeClusterColumns = _ColumnsSize; }
/// <summary> /// Search a path with HPA algorithm /// </summary> /// <param name="_Start">Tile to start from</param> /// <param name="_End">Tile to reach</param> /// <param name="_ChronoInfos">Struct with times value to evaluate performance</param> /// <param name="_MaxSeconds">Max time allowed to search a solution. If value is negative, no time limit applied</param> /// <returns>the shortest path from start tile to end tile if it exists, null otherwise</returns> public static Path SearchHPAFromTo(GridClustered _GridClustered, Tile _Start, Tile _End, out ChronoInfos _ChronoInfos, float _MaxSeconds) { StartChrono(); if (_Start == null || !_Start.IsAccessible || _End == null || !_End.IsAccessible || _GridClustered == null) { _ChronoInfos = ChronoInfos.InfosNone; return(null); } Cluster startCluster = _GridClustered.GetClusterOfTile(_Start); Cluster endCluster = _GridClustered.GetClusterOfTile(_End); Path instantSolution = null; if (startCluster == endCluster && (instantSolution = startCluster.ComputeInternalPathFromTo(_Start, _End)) != null) { _ChronoInfos = StopChrono(_Start, _End, true); return(instantSolution); } List <BridgeStep> openList = new List <BridgeStep>(); CustomComparer <BridgeStep> comparer = new CustomComparer <BridgeStep>(false); HashSet <Bridge> closeSet = new HashSet <Bridge>(); // store all the possible bridges connected to the start tile with their path // populate the open list with these bridges as all possible first steps Dictionary <Tile, Path> allFirstParts = new Dictionary <Tile, Path>(); for (int i = 0; i < startCluster.Bridges.Count; i++) { Path path = startCluster.ComputeInternalPathFromTo(_Start, startCluster.Bridges[i].Start); if (path != null) { allFirstParts.Add(startCluster.Bridges[i].Start, path); BridgeStep stepToAdd = new BridgeStep(startCluster.Bridges[i], path.Weight); int indexInsertion = openList.BinarySearch(stepToAdd, comparer); if (indexInsertion < 0) { indexInsertion = ~indexInsertion; } openList.Insert(indexInsertion, stepToAdd); } } // store all the possible bridges connected to the end tile with their path Dictionary <Tile, Path> allLastParts = new Dictionary <Tile, Path>(); for (int i = 0; i < endCluster.Bridges.Count; i++) { Path path = endCluster.ComputeInternalPathFromTo(endCluster.Bridges[i].Start, _End); if (path != null) { allLastParts.Add(endCluster.Bridges[i].Start, path); } } while (openList.Count > 0) { if (_MaxSeconds > 0 && chrono.Elapsed.TotalSeconds > _MaxSeconds) { _ChronoInfos = StopChrono(_Start, _End, false); return(null); } BridgeStep stepToExtend = openList.Last(); removeFromOpenChrono -= chrono.ElapsedMilliseconds; openList.RemoveAt(openList.Count - 1); removeFromOpenChrono += chrono.ElapsedMilliseconds; // if the step is already marked as solution, then it's the shortest solution if (stepToExtend.ReachedGoal) { // recreate whole path createSolutionChrono -= chrono.ElapsedMilliseconds; Path solution = stepToExtend.CreateCompletePath(_GridClustered, allFirstParts, allLastParts); createSolutionChrono += chrono.ElapsedMilliseconds; _ChronoInfos = StopChrono(_Start, _End, true); return(solution); } Bridge bridgeToExtend = stepToExtend.Bridge; if (closeSet.Contains(bridgeToExtend)) { continue; } closeSet.Add(bridgeToExtend); // when reach a bridge with an end connected to the goal (check in the dictionary allLastParts) for the first time, mark it as one possible solution // with the mark, add also the weight of the last part which connect the end bridge and the goal // then, re-insert it in the open list at the right index. // if we try to extend a bridge already marked, then it's the shortest solution // if the bridge to extend is a bridge with the end connected to the goal cluster (in dictionary allLastParts) if (endCluster.Bridges.Exists(bridge => bridge.Start == bridgeToExtend.End) && allLastParts.ContainsKey(bridgeToExtend.End)) { // mark step as possible solution and add the weight of the right last part stepToExtend.MarkAsSolution(allLastParts[stepToExtend.Bridge.End].Weight); // find the right index to re-insert in open list // if we try to extend it again, it means that it's the shortest path to the goal int indexInsertion = openList.BinarySearch(stepToExtend, comparer); if (indexInsertion < 0) { indexInsertion = ~indexInsertion; } openList.Insert(indexInsertion, stepToExtend); } else { // Get the cluster from the bridgeToExtend End Cluster cluster = _GridClustered.GetClusterOfTile(bridgeToExtend.End); // Get the right reversed bridge Bridge reverseBridge = cluster.Bridges.Find(b => b.Start == bridgeToExtend.End); // loop through all the reversed bridge neighbors foreachNeighborsChrono -= chrono.ElapsedMilliseconds; foreach (Bridge neighbor in reverseBridge.Neighbors.Keys) { // if the bridge is already in close set, skip to next neighbor searchInCloseListChrono -= chrono.ElapsedMilliseconds; bool existInCloseList = closeSet.Contains(neighbor); searchInCloseListChrono += chrono.ElapsedMilliseconds; if (existInCloseList) { continue; } // create extension with neighbor extendPathChrono -= chrono.ElapsedMilliseconds; BridgeStep extension = stepToExtend.MakeExtensionWith(neighbor, reverseBridge.Neighbors[neighbor].Weight); extendPathChrono += chrono.ElapsedMilliseconds; searchInsertionChrono -= chrono.ElapsedMilliseconds; int indexInsertion = openList.BinarySearch(extension, comparer); if (indexInsertion < 0) { indexInsertion = ~indexInsertion; } searchInsertionChrono += chrono.ElapsedMilliseconds; insertToOpenListChrono -= chrono.ElapsedMilliseconds; openList.Insert(indexInsertion, extension); insertToOpenListChrono += chrono.ElapsedMilliseconds; } foreachNeighborsChrono += chrono.ElapsedMilliseconds; } } // No path found in limited time _ChronoInfos = StopChrono(_Start, _End, false); return(null); }
public Cluster(int _AnchorRow, int _AnchorColumn, int _Rows, int _Columns, GridClustered _OwnerGrid) : this(_AnchorRow, _AnchorColumn, _Rows, _Columns) { m_OwnerGrid = _OwnerGrid; }