// 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: initializePathfindList
 // Description: Initialize the pathfind list
 // Parameters: DungeonLevel level , the level size is needed to
 //             initialize the pathfind heap
 public static void initializePathfindList(DungeonLevel level)
 {
     // If it isn't null and is not the right size, resize and initialize
     if (pathfindList != null && pathfindList.Length !=
         (level.getDungeonWidth() - 1) * (level.getDungeonHeight() - 1))
     {
         pathfindList = new PathfindTile[(level.getDungeonHeight() - 1) *
             (level.getDungeonWidth() - 1)];
         for (short i = 0; i < pathfindList.Length; i++)
         {
             pathfindList[i].fScore = Pathfinder.ARB_HIGH;
         }
         endTracker = 0;
     }
     // If it was null, create and initialize
     else
     {
         pathfindList = new PathfindTile[(level.getDungeonHeight() - 1) *
             (level.getDungeonWidth() - 1)];
         for (short i = 0; i < pathfindList.Length; i++)
         {
             pathfindList[i].fScore = Pathfinder.ARB_HIGH;
         }
         endTracker = 0;
     }
 }