// Name: pathfind // Description: Takes several parameters and returns a struct // representing the results of processing that data with // the A* search algorithm. This method attempts to find // a best path to the end node from the start node, // utilizing data available to it from the Monster and // DungeonLevel references // Parameters: Monster monster , a reference to a monster where // pathfinding data specific to that monster is mined // DungeonLevel level , a reference to a DungeonLevel so // that critical information about its layers, in regards to // pathfinding, can be mined // short startXCoord , // short startYCoord , the x and y-coordinate on the // DungeonLayer of the DungeonLevel that the entity is // beginning to pathfind from // short endXCoord , // short endYCoord , the x and y-coordinate on the // DungeonLayer of the DungeonLevel that the entity is // attempting to find a path to // short searchDistance , how far the pathfinder will search // before breaking with either a noPath or a "kinda" path. // The default is 0, or search the entire searchspace // bool guessPath , if true, the pathfinder will try to // return a path to a location near the goal, or if the // pathfinder exits early because of a searchDistance limit, // will return with a path "going toward" the goal. The // default is off (false) // byte algToUse , -1 is Djikstra's algorithm. This is // just a bad choice. 1 is greedy best-first, which is // optimal in the case of known very short paths, as it is // fastest and its inaccuracy is ruled out in short paths. // 0 is A*, which is the fastest longer-distance algorithm // to use, and is also the default // Returns: An instance of a PathfindData struct that carries both the // length of the calculated path, and the direction in which // the first step of the path begins public static PathfindData pathfind(Monster monster, DungeonLevel level, short startXCoord, short startYCoord, short endXCoord, short endYCoord, short searchDistance = 0, bool guesspath = false, byte algorithmToUse = 0) { // Determine if the map we're searching on is larger in some way // than the searchspace previously defined if (Pathfinder.searchSpace == null || Pathfinder.searchSpace.GetLength(0) < level.getDungeonHeight() || Pathfinder.searchSpace.GetLength(1) < level.getDungeonWidth()) { Pathfinder.searchSpace = new short[level.getDungeonHeight(), level.getDungeonWidth(), NUM_OF_ELEMENTS]; } else { clearSearchSpace(); } // Initialize the static end coordinates currentEndXCoord = endXCoord; currentEndYCoord = endYCoord; // Set the start and end nodes in the searchSpace searchSpace[startYCoord, startXCoord, NODE_TYPE_INDEX] = START_NODE; searchSpace[endYCoord, endXCoord, NODE_TYPE_INDEX] = END_NODE; Pathfinder.level = level; Pathfinder.monster = monster; // Initialize the pathfinding heap array NodeHeap.initializePathfindList(level); // Create the first tile, to represent the start tile. The F-Score // is a G-Score of 0 (start node), and the full heuristic PathfindTile currentTile = new PathfindTile(startYCoord, startXCoord, /*0 +*/ calcHeuristic(startYCoord, startXCoord)); #if OPTIM Console.WriteLine(calcHeuristic((short)10,(short)10)); #endif // Do while we are not currently exploring the end node and there is // more in the list do { // Expand the node to explore its neighbors expandNode(currentTile); // Add the tile to the closed list searchSpace[currentTile.yCoord, currentTile.xCoord, LIST_INDEX] = CLOSED_LIST; // Pull the root tile, which should be the most optimal tile // to explore next currentTile = NodeHeap.pullRoot(); #if DEBUG Console.WriteLine(currentTile.fScore); //NodeHeap.printNodeHeap(); //printSearchspace(); #endif } while (searchSpace[currentTile.yCoord, currentTile.xCoord, NODE_TYPE_INDEX] != END_NODE && !NodeHeap.isHeapEmpty()); // If we found the end node, then calculate a path back if (searchSpace[currentTile.yCoord, currentTile.xCoord, NODE_TYPE_INDEX] == END_NODE) { #if DEBUG path = new char[ level.getDungeonHeight() , level.getDungeonWidth()]; for (int i = 0; i < path.GetLength(0); i++) { for (int j = 0; j < path.GetLength(1); j++) { path[i, j] = '.'; } } #endif pathLength = 0; while (searchSpace[currentTile.yCoord, currentTile.xCoord, NODE_TYPE_INDEX] != START_NODE) { lastTile = currentTile; #if DEBUG path[lastTile.yCoord,lastTile.xCoord] = 'O'; if (searchSpace[currentTile.yCoord, currentTile.xCoord, NODE_TYPE_INDEX] == END_NODE) { path[lastTile.yCoord, lastTile.xCoord] = 'E'; } #endif temp = searchSpace[currentTile.yCoord, currentTile.xCoord, PARENT_INDEX_X]; currentTile.yCoord = searchSpace[currentTile.yCoord, currentTile.xCoord, PARENT_INDEX_Y]; currentTile.xCoord = temp; #if DEBUG if (searchSpace[currentTile.yCoord, currentTile.xCoord, NODE_TYPE_INDEX] == START_NODE) { path[currentTile.yCoord, currentTile.xCoord] = 'S'; } #endif pathLength++; } return new PathfindData( Pathfinder.calcDirection(currentTile.xCoord, currentTile.yCoord, lastTile.xCoord, lastTile.yCoord), pathLength); } // Temp code for compilation return new PathfindData((byte)Direction.NORTH, 0); }
// Name: expandNode // Description: Does most of the heavy lifting of the algorithm. Takes // a node and pushes all the viable neighbors into the // sorted open list complete with calculated F-Score, as // well as updating the 3D array with those nodes and their // information // Parameters: PathfindTile node , the node to be expanded private static void expandNode(PathfindTile node) { // For each direction, we must check that a node was not already // explored, then that it is walkable, and then finally add it to // the open list // NORTH if (searchSpace[node.yCoord - 1, node.xCoord, LIST_INDEX] == NOT_LISTED && monster.isWalkable( level.dungeonLayer.getTile(node.xCoord, (short)(node.yCoord - 1)))) { // Calculcate and preserve the H and G scores for the new node tempH = (short)(calcHeuristic((short)(node.yCoord - 1) , (short)(node.xCoord))); tempG = isCardOrDiag(node.xCoord,node.yCoord, node.xCoord, (short)(node.yCoord - 1)) ? (short)(searchSpace[node.yCoord, node.xCoord, G_SCORE_INDEX] + G_SCORE_CARD_CONSTANT) : (short)(searchSpace[node.yCoord, node.xCoord, G_SCORE_INDEX] + G_SCORE_DIAG_CONSTANT); // Add node to heap NodeHeap.pushNode(new PathfindTile((short)(node.yCoord - 1), node.xCoord, (short)(tempH + tempG))); // Add to open list searchSpace[node.yCoord - 1, node.xCoord, LIST_INDEX] = OPEN_LIST; // Update scores searchSpace[node.yCoord - 1, node.xCoord, H_SCORE_INDEX] = tempH; searchSpace[node.yCoord - 1, node.xCoord, G_SCORE_INDEX] = tempG; // Update parent searchSpace[node.yCoord - 1, node.xCoord, PARENT_INDEX_X] = node.xCoord; searchSpace[node.yCoord - 1, node.xCoord, PARENT_INDEX_Y] = node.yCoord; } // If the tile is in the closed list, it means it is definitely // walkable. What we need to do now is determine if from this new // node, are we able to make the route shorter based on the new // G-Score? The heuristic would obviously already have been computed // for this node, so only the G-Score needs to be re-evaluated else if (searchSpace[node.yCoord - 1, node.xCoord, LIST_INDEX] == CLOSED_LIST) { // Calculate what the new G-Score would be tempG = isCardOrDiag(node.xCoord,node.yCoord, node.xCoord, (short)(node.yCoord - 1)) ? (short)(searchSpace[node.yCoord, node.xCoord, G_SCORE_INDEX] + G_SCORE_CARD_CONSTANT) : (short)(searchSpace[node.yCoord, node.xCoord, G_SCORE_INDEX] + G_SCORE_DIAG_CONSTANT); // If the new G-Score is better than what it was before, then // update the node, add it back to the open list, and carry on if (tempG < searchSpace[node.yCoord - 1, node.xCoord, G_SCORE_INDEX]) { // Update G-Score searchSpace[node.yCoord - 1, node.xCoord, G_SCORE_INDEX] = tempG; // Update parent searchSpace[node.yCoord - 1, node.xCoord, PARENT_INDEX_X] = node.xCoord; searchSpace[node.yCoord - 1, node.xCoord, PARENT_INDEX_Y] = node.yCoord; // Add to open list searchSpace[node.yCoord - 1, node.xCoord, LIST_INDEX] = OPEN_LIST; // Add node to heap NodeHeap.pushNode(new PathfindTile((short)(node.yCoord - 1), node.xCoord, (short)(searchSpace[node.yCoord - 1, node.xCoord, H_SCORE_INDEX] + tempG))); } } // NORTH EAST if (searchSpace[node.yCoord - 1, node.xCoord + 1, LIST_INDEX] == NOT_LISTED && monster.isWalkable( level.dungeonLayer.getTile((short)(node.xCoord + 1), (short)(node.yCoord - 1)))) { tempH = (short)(calcHeuristic((short)(node.yCoord - 1) , (short)(node.xCoord + 1))); tempG = isCardOrDiag(node.xCoord,node.yCoord, (short)(node.xCoord + 1), (short)(node.yCoord - 1)) ? (short)(searchSpace[node.yCoord, node.xCoord, G_SCORE_INDEX] + G_SCORE_CARD_CONSTANT) : (short)(searchSpace[node.yCoord, node.xCoord, G_SCORE_INDEX] + G_SCORE_DIAG_CONSTANT); NodeHeap.pushNode(new PathfindTile((short)(node.yCoord - 1), (short)(node.xCoord + 1), (short)(tempH + tempG))); searchSpace[node.yCoord - 1, node.xCoord + 1, LIST_INDEX] = OPEN_LIST; searchSpace[node.yCoord - 1, node.xCoord + 1, H_SCORE_INDEX] = tempH; searchSpace[node.yCoord - 1, node.xCoord + 1, G_SCORE_INDEX] = tempG; searchSpace[node.yCoord - 1, node.xCoord + 1, PARENT_INDEX_X] = node.xCoord; searchSpace[node.yCoord - 1, node.xCoord + 1, PARENT_INDEX_Y] = node.yCoord; } else if (searchSpace[node.yCoord - 1, node.xCoord + 1, LIST_INDEX] == CLOSED_LIST) { tempG = isCardOrDiag(node.xCoord,node.yCoord, (short)(node.xCoord + 1), (short)(node.yCoord - 1)) ? (short)(searchSpace[node.yCoord, node.xCoord, G_SCORE_INDEX] + G_SCORE_CARD_CONSTANT) : (short)(searchSpace[node.yCoord, node.xCoord, G_SCORE_INDEX] + G_SCORE_DIAG_CONSTANT); if (tempG < searchSpace[node.yCoord - 1, node.xCoord + 1, G_SCORE_INDEX]) { searchSpace[node.yCoord - 1, node.xCoord + 1, G_SCORE_INDEX] = tempG; searchSpace[node.yCoord - 1, node.xCoord + 1, PARENT_INDEX_X] = node.xCoord; searchSpace[node.yCoord - 1, node.xCoord + 1, PARENT_INDEX_Y] = node.yCoord; searchSpace[node.yCoord - 1, node.xCoord + 1, LIST_INDEX] = OPEN_LIST; NodeHeap.pushNode(new PathfindTile((short)(node.yCoord - 1), (short)(node.xCoord + 1), (short)(searchSpace[node.yCoord - 1, node.xCoord + 1, H_SCORE_INDEX] + tempG))); } } // EAST if (searchSpace[node.yCoord, node.xCoord + 1, LIST_INDEX] == NOT_LISTED && monster.isWalkable( level.dungeonLayer.getTile((short)(node.xCoord + 1), node.yCoord))) { tempH = (short)(calcHeuristic((short)(node.yCoord) , (short)(node.xCoord + 1))); tempG = isCardOrDiag(node.xCoord,node.yCoord, (short)(node.xCoord + 1), node.yCoord) ? (short)(searchSpace[node.yCoord, node.xCoord, G_SCORE_INDEX] + G_SCORE_CARD_CONSTANT) : (short)(searchSpace[node.yCoord, node.xCoord, G_SCORE_INDEX] + G_SCORE_DIAG_CONSTANT); NodeHeap.pushNode(new PathfindTile((short)(node.yCoord), (short)(node.xCoord + 1), (short)(tempH + tempG))); searchSpace[node.yCoord, node.xCoord + 1, LIST_INDEX] = OPEN_LIST; searchSpace[node.yCoord, node.xCoord + 1, H_SCORE_INDEX] = tempH; searchSpace[node.yCoord, node.xCoord + 1, G_SCORE_INDEX] = tempG; searchSpace[node.yCoord, node.xCoord + 1, PARENT_INDEX_X] = node.xCoord; searchSpace[node.yCoord, node.xCoord + 1, PARENT_INDEX_Y] = node.yCoord; } else if (searchSpace[node.yCoord, node.xCoord + 1, LIST_INDEX] == CLOSED_LIST) { tempG = isCardOrDiag(node.xCoord,node.yCoord, (short)(node.xCoord + 1), node.yCoord) ? (short)(searchSpace[node.yCoord, node.xCoord, G_SCORE_INDEX] + G_SCORE_CARD_CONSTANT) : (short)(searchSpace[node.yCoord, node.xCoord, G_SCORE_INDEX] + G_SCORE_DIAG_CONSTANT); if (tempG < searchSpace[node.yCoord, node.xCoord + 1, G_SCORE_INDEX]) { searchSpace[node.yCoord, node.xCoord + 1, G_SCORE_INDEX] = tempG; searchSpace[node.yCoord, node.xCoord + 1, PARENT_INDEX_X] = node.xCoord; searchSpace[node.yCoord, node.xCoord + 1, PARENT_INDEX_Y] = node.yCoord; searchSpace[node.yCoord, node.xCoord + 1, LIST_INDEX] = OPEN_LIST; NodeHeap.pushNode(new PathfindTile((short)(node.yCoord), (short)(node.xCoord + 1), (short)(searchSpace[node.yCoord, node.xCoord + 1, H_SCORE_INDEX] + tempG))); } } // SOUTH EAST if (searchSpace[node.yCoord + 1, node.xCoord + 1, LIST_INDEX] == NOT_LISTED && monster.isWalkable( level.dungeonLayer.getTile((short)(node.xCoord + 1), (short)(node.yCoord + 1 )))) { tempH = (short)(calcHeuristic((short)(node.yCoord + 1) , (short)(node.xCoord + 1))); tempG = isCardOrDiag(node.xCoord,node.yCoord, (short)(node.xCoord + 1), (short)(node.yCoord + 1)) ? (short)(searchSpace[node.yCoord, node.xCoord, G_SCORE_INDEX] + G_SCORE_CARD_CONSTANT) : (short)(searchSpace[node.yCoord, node.xCoord, G_SCORE_INDEX] + G_SCORE_DIAG_CONSTANT); NodeHeap.pushNode(new PathfindTile((short)(node.yCoord + 1), (short)(node.xCoord + 1), (short)(tempH + tempG))); searchSpace[node.yCoord + 1, node.xCoord + 1, LIST_INDEX] = OPEN_LIST; searchSpace[node.yCoord + 1, node.xCoord + 1, H_SCORE_INDEX] = tempH; searchSpace[node.yCoord + 1, node.xCoord + 1, G_SCORE_INDEX] = tempG; searchSpace[node.yCoord + 1, node.xCoord + 1, PARENT_INDEX_X] = node.xCoord; searchSpace[node.yCoord + 1, node.xCoord + 1, PARENT_INDEX_Y] = node.yCoord; } else if (searchSpace[node.yCoord + 1, node.xCoord + 1, LIST_INDEX] == CLOSED_LIST) { tempG = isCardOrDiag(node.xCoord,node.yCoord, (short)(node.xCoord + 1), (short)(node.yCoord + 1)) ? (short)(searchSpace[node.yCoord, node.xCoord, G_SCORE_INDEX] + G_SCORE_CARD_CONSTANT) : (short)(searchSpace[node.yCoord, node.xCoord, G_SCORE_INDEX] + G_SCORE_DIAG_CONSTANT); if (tempG < searchSpace[node.yCoord + 1, node.xCoord + 1, G_SCORE_INDEX]) { searchSpace[node.yCoord + 1, node.xCoord + 1, G_SCORE_INDEX] = tempG; searchSpace[node.yCoord + 1, node.xCoord + 1, PARENT_INDEX_X] = node.xCoord; searchSpace[node.yCoord + 1, node.xCoord + 1, PARENT_INDEX_Y] = node.yCoord; searchSpace[node.yCoord + 1, node.xCoord + 1, LIST_INDEX] = OPEN_LIST; NodeHeap.pushNode(new PathfindTile((short)(node.yCoord + 1), (short)(node.xCoord + 1), (short)(searchSpace[node.yCoord + 1, node.xCoord + 1, H_SCORE_INDEX] + tempG))); } } // SOUTH if (searchSpace[node.yCoord + 1, node.xCoord, LIST_INDEX] == NOT_LISTED && monster.isWalkable( level.dungeonLayer.getTile(node.xCoord, (short)(node.yCoord + 1)))) { tempH = (short)(calcHeuristic((short)(node.yCoord + 1) , (short)(node.xCoord))); tempG = isCardOrDiag(node.xCoord,node.yCoord, node.xCoord, (short)(node.yCoord + 1)) ? (short)(searchSpace[node.yCoord, node.xCoord, G_SCORE_INDEX] + G_SCORE_CARD_CONSTANT) : (short)(searchSpace[node.yCoord, node.xCoord, G_SCORE_INDEX] + G_SCORE_DIAG_CONSTANT); NodeHeap.pushNode(new PathfindTile((short)(node.yCoord + 1), node.xCoord, (short)(tempH + tempG))); searchSpace[node.yCoord + 1, node.xCoord, LIST_INDEX] = OPEN_LIST; searchSpace[node.yCoord + 1, node.xCoord, H_SCORE_INDEX] = tempH; searchSpace[node.yCoord + 1, node.xCoord, G_SCORE_INDEX] = tempG; searchSpace[node.yCoord + 1, node.xCoord, PARENT_INDEX_X] = node.xCoord; searchSpace[node.yCoord + 1, node.xCoord, PARENT_INDEX_Y] = node.yCoord; } else if (searchSpace[node.yCoord + 1, node.xCoord, LIST_INDEX] == CLOSED_LIST) { tempG = isCardOrDiag(node.xCoord,node.yCoord, node.xCoord, (short)(node.yCoord + 1)) ? (short)(searchSpace[node.yCoord, node.xCoord, G_SCORE_INDEX] + G_SCORE_CARD_CONSTANT) : (short)(searchSpace[node.yCoord, node.xCoord, G_SCORE_INDEX] + G_SCORE_DIAG_CONSTANT); if (tempG < searchSpace[node.yCoord + 1, node.xCoord, G_SCORE_INDEX]) { searchSpace[node.yCoord + 1, node.xCoord, G_SCORE_INDEX] = tempG; searchSpace[node.yCoord + 1, node.xCoord, PARENT_INDEX_X] = node.xCoord; searchSpace[node.yCoord + 1, node.xCoord, PARENT_INDEX_Y] = node.yCoord; searchSpace[node.yCoord + 1, node.xCoord, LIST_INDEX] = OPEN_LIST; NodeHeap.pushNode(new PathfindTile((short)(node.yCoord + 1), node.xCoord, (short)(searchSpace[node.yCoord + 1, node.xCoord, H_SCORE_INDEX] + tempG))); } } // SOUTH WEST if (searchSpace[node.yCoord + 1, node.xCoord - 1, LIST_INDEX] == NOT_LISTED && monster.isWalkable( level.dungeonLayer.getTile((short)(node.xCoord - 1), (short)(node.yCoord + 1)))) { tempH = (short)(calcHeuristic((short)(node.yCoord + 1) , (short)(node.xCoord - 1))); tempG = isCardOrDiag(node.xCoord,node.yCoord, (short)(node.xCoord - 1), (short)(node.yCoord + 1)) ? (short)(searchSpace[node.yCoord, node.xCoord, G_SCORE_INDEX] + G_SCORE_CARD_CONSTANT) : (short)(searchSpace[node.yCoord, node.xCoord, G_SCORE_INDEX] + G_SCORE_DIAG_CONSTANT); NodeHeap.pushNode(new PathfindTile((short)(node.yCoord + 1), (short)(node.xCoord - 1), (short)(tempH + tempG))); searchSpace[node.yCoord + 1, node.xCoord - 1, LIST_INDEX] = OPEN_LIST; searchSpace[node.yCoord + 1, node.xCoord - 1, H_SCORE_INDEX] = tempH; searchSpace[node.yCoord + 1, node.xCoord - 1, G_SCORE_INDEX] = tempG; searchSpace[node.yCoord + 1, node.xCoord - 1, PARENT_INDEX_X] = node.xCoord; searchSpace[node.yCoord + 1, node.xCoord - 1, PARENT_INDEX_Y] = node.yCoord; } else if (searchSpace[node.yCoord + 1, node.xCoord - 1, LIST_INDEX] == CLOSED_LIST) { tempG = isCardOrDiag(node.xCoord,node.yCoord, (short)(node.xCoord - 1), (short)(node.yCoord + 1)) ? (short)(searchSpace[node.yCoord, node.xCoord, G_SCORE_INDEX] + G_SCORE_CARD_CONSTANT) : (short)(searchSpace[node.yCoord, node.xCoord, G_SCORE_INDEX] + G_SCORE_DIAG_CONSTANT); if (tempG < searchSpace[node.yCoord + 1, node.xCoord - 1, G_SCORE_INDEX]) { searchSpace[node.yCoord + 1, node.xCoord - 1, G_SCORE_INDEX] = tempG; searchSpace[node.yCoord + 1, node.xCoord - 1, PARENT_INDEX_X] = node.xCoord; searchSpace[node.yCoord + 1, node.xCoord - 1, PARENT_INDEX_Y] = node.yCoord; searchSpace[node.yCoord + 1, node.xCoord - 1, LIST_INDEX] = OPEN_LIST; NodeHeap.pushNode(new PathfindTile((short)(node.yCoord + 1), (short)(node.xCoord - 1), (short)(searchSpace[node.yCoord + 1, node.xCoord - 1, H_SCORE_INDEX] + tempG))); } } // WEST if (searchSpace[node.yCoord, node.xCoord - 1, LIST_INDEX] == NOT_LISTED && monster.isWalkable( level.dungeonLayer.getTile((short)(node.xCoord - 1), node.yCoord))) { tempH = (short)(calcHeuristic((short)(node.yCoord) , (short)(node.xCoord - 1))); tempG = isCardOrDiag(node.xCoord,node.yCoord, (short)(node.xCoord - 1), node.yCoord) ? (short)(searchSpace[node.yCoord, node.xCoord, G_SCORE_INDEX] + G_SCORE_CARD_CONSTANT) : (short)(searchSpace[node.yCoord, node.xCoord, G_SCORE_INDEX] + G_SCORE_DIAG_CONSTANT); NodeHeap.pushNode(new PathfindTile((short)(node.yCoord), (short)(node.xCoord - 1), (short)(tempH + tempG))); searchSpace[node.yCoord, node.xCoord - 1, LIST_INDEX] = OPEN_LIST; searchSpace[node.yCoord, node.xCoord - 1, H_SCORE_INDEX] = tempH; searchSpace[node.yCoord, node.xCoord - 1, G_SCORE_INDEX] = tempG; searchSpace[node.yCoord, node.xCoord - 1, PARENT_INDEX_X] = node.xCoord; searchSpace[node.yCoord, node.xCoord - 1, PARENT_INDEX_Y] = node.yCoord; } else if (searchSpace[node.yCoord, node.xCoord - 1, LIST_INDEX] == CLOSED_LIST) { tempG = isCardOrDiag(node.xCoord,node.yCoord, (short)(node.xCoord - 1), node.yCoord) ? (short)(searchSpace[node.yCoord, node.xCoord, G_SCORE_INDEX] + G_SCORE_CARD_CONSTANT) : (short)(searchSpace[node.yCoord, node.xCoord, G_SCORE_INDEX] + G_SCORE_DIAG_CONSTANT); if (tempG < searchSpace[node.yCoord, node.xCoord - 1, G_SCORE_INDEX]) { searchSpace[node.yCoord, node.xCoord - 1, G_SCORE_INDEX] = tempG; searchSpace[node.yCoord, node.xCoord - 1, PARENT_INDEX_X] = node.xCoord; searchSpace[node.yCoord, node.xCoord - 1, PARENT_INDEX_Y] = node.yCoord; searchSpace[node.yCoord, node.xCoord - 1, LIST_INDEX] = OPEN_LIST; NodeHeap.pushNode(new PathfindTile((short)(node.yCoord), (short)(node.xCoord - 1), (short)(searchSpace[node.yCoord, node.xCoord - 1, H_SCORE_INDEX] + tempG))); } } // NORTH WEST if (searchSpace[node.yCoord - 1, node.xCoord - 1, LIST_INDEX] == NOT_LISTED && monster.isWalkable( level.dungeonLayer.getTile((short)(node.xCoord - 1), (short)(node.yCoord - 1)))) { tempH = (short)(calcHeuristic((short)(node.yCoord - 1) , (short)(node.xCoord - 1))); tempG = isCardOrDiag(node.xCoord,node.yCoord, (short)(node.xCoord - 1), (short)(node.yCoord - 1)) ? (short)(searchSpace[node.yCoord, node.xCoord, G_SCORE_INDEX] + G_SCORE_CARD_CONSTANT) : (short)(searchSpace[node.yCoord, node.xCoord, G_SCORE_INDEX] + G_SCORE_DIAG_CONSTANT); NodeHeap.pushNode(new PathfindTile((short)(node.yCoord - 1), (short)(node.xCoord - 1), (short)(tempH + tempG))); searchSpace[node.yCoord - 1, node.xCoord - 1, LIST_INDEX] = OPEN_LIST; searchSpace[node.yCoord - 1, node.xCoord - 1, H_SCORE_INDEX] = tempH; searchSpace[node.yCoord - 1, node.xCoord - 1, G_SCORE_INDEX] = tempG; searchSpace[node.yCoord - 1, node.xCoord - 1, PARENT_INDEX_X] = node.xCoord; searchSpace[node.yCoord - 1, node.xCoord - 1, PARENT_INDEX_Y] = node.yCoord; } else if (searchSpace[node.yCoord - 1, node.xCoord - 1, LIST_INDEX] == CLOSED_LIST) { tempG = isCardOrDiag(node.xCoord,node.yCoord, (short)(node.xCoord - 1), (short)(node.yCoord - 1)) ? (short)(searchSpace[node.yCoord, node.xCoord, G_SCORE_INDEX] + G_SCORE_CARD_CONSTANT) : (short)(searchSpace[node.yCoord, node.xCoord, G_SCORE_INDEX] + G_SCORE_DIAG_CONSTANT); if (tempG < searchSpace[node.yCoord - 1, node.xCoord - 1, G_SCORE_INDEX]) { searchSpace[node.yCoord - 1, node.xCoord - 1, G_SCORE_INDEX] = tempG; searchSpace[node.yCoord - 1, node.xCoord - 1, PARENT_INDEX_X] = node.xCoord; searchSpace[node.yCoord - 1, node.xCoord - 1, PARENT_INDEX_Y] = node.yCoord; searchSpace[node.yCoord - 1, node.xCoord - 1, LIST_INDEX] = OPEN_LIST; NodeHeap.pushNode(new PathfindTile((short)(node.yCoord - 1), (short)(node.xCoord - 1), (short)(searchSpace[node.yCoord - 1, node.xCoord - 1, H_SCORE_INDEX] + tempG))); } } }
// Name: pushNode // Description: Push a node to the heap. The strategy is pushing it to // the end of the list, then perculating it up until its // parent is rightfully smaller than it is // Parameters: PathfindTile newTile , the tile to be pushed to the heap public static void pushNode(PathfindTile newTile) { // Put the new tile at the end of the list. It will be perculated // up in a smidge pathfindList[endTracker] = newTile; // Update the official end of the list endTracker++; // Perculate the new node up perculationNode = (short)(endTracker - 1); // Continue to perculate up while this method returns that // perculation must continue while (perculateUp((short)(perculationNode))) { } }