///populates random dungeon rooms with stuff, including placing player character, stairs, enemies
    void PopulateDungeon()
    {
        ///create dungeon controller that all entities will reference

        Instantiate(dungeonController, new Vector3(), transform.rotation); //places dungeon controller first to take advantage of automatic turn order tracking

        //Instantiate(playerObject, GetRandomRoomFromQueue().getCoords(), transform.rotation); //places player character in a random room

        dungeon_room targetRoom = GetRandomRoomFromQueue(); //pick a random room to place the stairs in

        if (createdRoomsQueue.Count >= 2)                   //if we can have stairs in separate room from Player (if we grab top room, there is another room after for player to go into)
        {
//            Debug.Log("Preventing Stairs appearing in player's room");
            tappedRoomsStack.Push(createdRoomsQueue.Dequeue()); //prevent the stairs from appearing in the same room as the player (we already grabbed the stairs room, now we're just keeping it separate from random rooms list)
        }
        //clear the tile that the stairs occupy
        Vector3 stairsPos   = targetRoom.getRandomTileInRoom(); //grab a random position in the room, TODO: remove that tile, and place the stairs tile in its place
        Vector2 topRightLoc = new Vector2(stairsPos.x + 0.25f, stairsPos.y + 0.25f);
        Vector2 botLeftLoc  = new Vector2(stairsPos.x - 0.25f, stairsPos.y - 0.25f);



        Collider2D collider = Physics2D.OverlapArea(topRightLoc, botLeftLoc, TileMonoBehavior.tileLayerMask);//build a collider at stairs position to see if there is already a tile there

        if (collider != null)
        {
            Destroy(collider.gameObject);
        }
        //place stairs into the dungeon
        Instantiate(stairsTilePrefab, stairsPos, transform.rotation);
        targetRoom = GetRandomRoomFromQueue();

        //playe player into the dungeon
        Vector3 playerPos = targetRoom.getRandomTileInRoom();

        while (playerPos.x == stairsPos.x && playerPos.y == stairsPos.y) //if player directly overlaps stairs, move player someplace else
        {
            playerPos = targetRoom.getRandomTileInRoom();
        }
        Instantiate(playerObject, playerPos, transform.rotation);

        if (tappedRoomsStack.Count > 0) //shift all of the removed elements back onto the queue, preparation for placing in rest of the dungeon
        {
            createdRoomsQueue.Enqueue(tappedRoomsStack.Pop());
        }
        //TODO: insert spectacular monster/item spawning algorithm here!
        int failCount = 0; //used to kill while loop after too many failed cases

        while (numberOfMonsters > 0 && (failCount < 10))
        {
            //pick a tile, any tile...
            TileMonoBehavior tileAtSpawnPos   = null;
            dungeon_room     monsterSpawnRoom = GetRandomRoomFromQueue();
            Vector3          monsterSpawnPos  = monsterSpawnRoom.getRandomTileInRoom();
            //check if tile already occupied
            topRightLoc = new Vector2(monsterSpawnPos.x + 0.25f, monsterSpawnPos.y + 0.25f); //build a collider to fetch the tile there
            botLeftLoc  = new Vector2(monsterSpawnPos.x - 0.25f, monsterSpawnPos.y - 0.25f);
            collider    = Physics2D.OverlapArea(topRightLoc, botLeftLoc, TileMonoBehavior.tileLayerMask);
            if (collider != null) //we find a tile there
            {
                tileAtSpawnPos = collider.gameObject.GetComponent <TileMonoBehavior>();
            }
            if (tileAtSpawnPos != null && !tileAtSpawnPos.IsOccupied()) //if we found a tile and it is not occupied, spawn a monster there
            {
                Debug.Log("Creating monster at " + monsterSpawnPos.x + "," + monsterSpawnPos.y);
                GameObject spawnedEnemy = (GameObject)Instantiate(basicMonster, monsterSpawnPos, transform.rotation); //place a monster there, connect it to the tile
                tileAtSpawnPos.ConnectToEntity(spawnedEnemy.GetComponent <Entity>());
                numberOfMonsters--;
                failCount = 0;
            }
            else
            {
                failCount++;
            }
        }
        if (failCount == 10)
        {
            Debug.Log("Failed to spawn all monsters, remaining monsters: " + numberOfMonsters);
        }
    }
    // Update is called once per frame
    void Update()
    {
        /**on each update, pick a random room from list, try to generate a new room relative to that room
         *  if no room in list (means we have exhausted all rooms to create around, or we have not created first room), give up on creating room
         *  after creating rooms, populate them with a player, a set of stairs, and any relevant entities
         **/
        if (roomCount < numberOfRooms)                                             ///create numberOfRooms rooms
        {
            if (roomCount == 0)                                                    //creating very first room
            {
                int          newSize = Random.Range(minRoomSize, maxRoomSize + 1); //size of new room
                dungeon_room newRoom = TryCreateRoom(new Vector3(transform.position.x, transform.position.y, TileMonoBehavior.tileZLayer), newSize, 0, Entity.MoveDirection.up);
                if (newRoom != null)                                               //if room successfully created
                {
                    createdRoomsQueue.Enqueue(newRoom);
                    roomCount++;
                }
                else
                {
                    roomCount = numberOfRooms; //forces Generator to stop generating
                    GracefullyExit();
                    return;
                }
            }
            else if (createdRoomsQueue.Peek() != null)           //not first element, and there is a next element to grab
            {
                dungeon_room oldRoom = GetRandomRoomFromQueue(); //picks an old room to generate new room relative to
                if (oldRoom == null)
                {
                    roomCount = numberOfRooms;
                    return;
                }
                dungeon_room newRoom  = null;                                       //the room we hope to create
                int          roomSize = Random.Range(minRoomSize, maxRoomSize + 1); //the size we want the new room to be

                float distance = Random.Range(minDisplacement, maxDisplacement + 1);

                Vector3 newRoomLocation                = new Vector3();
                Vector3 oldRoomLocation                = oldRoom.getCoords();
                Entity.MoveDirection direction         = (Entity.MoveDirection)Random.Range(0, 4); ///direction can be 0 up, 2 left, 1 down, 3 right
                Entity.MoveDirection originalDirection = direction;

                do ///try to create room at given direction, if it fails, keep trying with new direction until there are no more directions to pick
                {
                    switch (direction)
                    {
                    case Entity.MoveDirection.up:     //up
                    {
                        float relativePosition = Mathf.Ceil(oldRoom.getSize() / 2f) + distance + Mathf.Floor(roomSize / 2f);
                        newRoomLocation = new Vector3(oldRoomLocation.x, oldRoomLocation.y + relativePosition, 0);
                        break;
                    }

                    case Entity.MoveDirection.left:     //left
                    {
                        float relativePosition = Mathf.Floor(oldRoom.getSize() / 2f) + distance + Mathf.Ceil(roomSize / 2f);
                        newRoomLocation = new Vector3(oldRoomLocation.x - relativePosition, oldRoomLocation.y, 0);
                        break;
                    }

                    case Entity.MoveDirection.down:     //down
                    {
                        float relativePosition = Mathf.Floor(oldRoom.getSize() / 2f) + distance + Mathf.Ceil(roomSize / 2f);
                        newRoomLocation = new Vector3(oldRoomLocation.x, oldRoomLocation.y - relativePosition, 0);
                        break;
                    }

                    case Entity.MoveDirection.right:     //right
                    {
                        float relativePosition = Mathf.Ceil(oldRoom.getSize() / 2f) + distance + Mathf.Floor(roomSize / 2f);
                        //if size % 2 = 0, even, then nudge 1 back
                        newRoomLocation = new Vector3(oldRoomLocation.x + relativePosition, oldRoomLocation.y);
                        break;
                    }
                    }
                    ///default case, it tries to initialize room at 0,0,0
                    newRoom = TryCreateRoom(newRoomLocation, roomSize, distance, direction); //try to create the room at specified location
                    if (newRoom != null)                                                     //if room creation succeeded, store the room in list for later use
                    {
                        roomCount++;
                        createdRoomsQueue.Enqueue(newRoom);
                    }
                    else if (direction == Entity.MoveDirection.right)
                    {
                        //else keep trying new directions until all exhausted
                        direction = Entity.MoveDirection.up;
                    }
                    else
                    {
                        direction++;
                    }
                }while (newRoom == null && direction != originalDirection); ///stop iterating when we successfully create a room, or when we reach original direction

                if (newRoom != null)                                        //successfully created room, prepare for creating next room
                {
                    while (tappedRoomsStack.Count != 0)                     //move all previously invalidated dungeon rooms back into queue again
                    {
                        createdRoomsQueue.Enqueue(tappedRoomsStack.Pop());
                    }
                }
            }
            //reaching here, this is not first room, so there exists at least one room, but we can't make any more rooms, so stop and cleanup
            else //createdRooms.Peek() == 0, so no more rooms to pick from. We can't build dungeon, so give up.
            {
                roomCount = numberOfRooms; //forces Generator to stop generating
            }
        }
        else //we are finished creating rooms
        {
            PopulateDungeon();
            Destroy(this.gameObject);
        }
    }