// 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;
     }
 }
        // 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: Main (unit test)
        // Description: This is the unit test of the pathfinder. It will be
        //              used to exhaustively test the features of the pathfinder
        //              to ensure that not only does it work correctly with
        //              optimal input data, but handles gracefully bad input
        //              data, and does it all in an extremely efficient, 
        //              optimized, sexy-speedy manner
        static void Main(string[] args)
        {
            // Define constants for the size of the window so that window-
            //dependant things can be easily updated
            const int WINDOW_WIDTH = 80;
            const int WINDOW_HEIGHT = 55;
#if GUI
            // Display an initializing message to the console
            Console.WriteLine("Initilizing game window...");
            // Create the new libtcod output window. This needs to be done only
            // once, but before anything else. The first value is the width in
            // cells the window is, the second is the height in cells, and the
            // third is the name of the window
            TCODConsole.initRoot(WINDOW_WIDTH, WINDOW_HEIGHT,
                "Hello World!");
            // Set the maximum graphical update speed. This is important to
            // massively reduce CPU use with unnecessary updates
            TCODSystem.setFps(30);
            // Set the default background color of the root console with black
            TCODConsole.root.setBackgroundColor(TCODColor.black);
            // Clear is a function that overwrites every cell in the window with
            // a plain, empty cell of the color dictated by setBackgroundColor()
            TCODConsole.root.clear();
            // Flush writes the graphical data that is pending to the screen.
            // Any graphics updates are not shown to the screen until flush is
            // called. Try to minimize this call
            TCODConsole.flush();
            TCODKey Key = TCODConsole.checkForKeypress();
#endif
            // Create dungeon objects eventually to be used for pathfinding test
            Monster monster = new Monster();
            // Set the bit for isPlayer in the bitfield
            monster.setFlag(Monster.AttributeFlags.isPlayer);
            DungeonLevel dungeon = new DungeonLevel(TCODConsole.root);
            dungeon.addMonsterToDungeon(monster);


            // PATHFINDING TESTS
#if TEST
            Stopwatch st = new Stopwatch();
            for (int i = 0; i < 500000; i++)
            {
                st.Start();
#endif
                //Console.WriteLine(
                pathfind(monster, dungeon, monster.XCoord, monster.YCoord,
                (short)30,
                (short)40);//.directionOfPath);
#if TEST
                st.Stop();
            }
            Console.WriteLine(st.ElapsedMilliseconds/500000.0);
#endif
                // PATHFINDING TESTS
#if DEBUG
            for (int i = 0; i < path.GetLength(0); i++)
            {
                for (int j = 0; j < path.GetLength(1); j++)
                {
                    Console.Write(path[i,j]);
                }
            }
            Console.WriteLine("Search Space:");
            printSearchspace();
            NodeHeap.printNodeHeap();
#endif
#if GUI
            // While the user has not closed the window and while the user has
            // not pressed escape, do stuff
            while (!TCODConsole.isWindowClosed())
            {
                dungeon.printToScreen();
                TCODConsole.flush();
                dungeon.doAction();
            }
#endif
        }