public HashSet <RoomNode> GetConnectedRoom(RoomNode room)
        {
            HashSet <RoomNode> hset = new HashSet <RoomNode>();

            for (int i = 0; i < room.gridList.Count; ++i)
            {
                var grid = room.gridList[i];
                AddNearRoomToHSet(hset, grid);
            }
            return(hset);
        }
        //Get all empty grid beyond the room
        List <Grid> GetOutsideEmptyGrid(RoomNode room)
        {
            List <Grid> list = new List <Grid>();

            for (int i = 0; i < room.gridList.Count; ++i)
            {
                var grid = room.gridList[i];
                AddEmptyGridToList(list, grid);
            }
            return(list);
        }
        void PlaceShopRoom()
        {
            List <Type> pools = generateConfig.shopRoomPools;
            RoomNode    room  = null;

            HashSet <RoomType> avoidConnectTo = new HashSet <RoomType>()
            {
                RoomType.Init,
                RoomType.Reward,
                RoomType.Shop,
                RoomType.Boss,
            };

            for (int cnt = 0; cnt < generateConfig.shopRoomCount; ++cnt)
            {
                int rnd = UnityEngine.Random.Range(0, pools.Count);
                room          = (RoomNode)Activator.CreateInstance(pools[rnd]);
                room.roomType = RoomType.Shop;

                List <Grid> connectableGrids = GetConnectableGrids();
                for (int i = 0; i < connectableGrids.Count; ++i)
                {
                    var gridIndex = connectableGrids[i].index;
                    if (room.Place(gridIndex.x, gridIndex.y, this, true, avoidConnectTo))
                    {
                        ++curGenerateInfo.shopRoomCount;
                        usedGrid += room.gridList.Count;
                        roomList.Add(room);
                        room.SetPosition(room.gridList[0].position);
                        room.RepositionDoors();
                        room.CalculateTransportPos();
                    }

                    if (generateConfig.shopRoomCount <= curGenerateInfo.shopRoomCount)
                    {
                        break;
                    }
                }
            }

            if (generateConfig.shopRoomCount > curGenerateInfo.shopRoomCount)
            {
                Debug.LogError("Generate Shop Room less than " + generateConfig.shopRoomCount);
            }
        }
        int GenerateAt(int x, int y, int depth)
        {
            if (!IsValidIndex(x, y))
            {
                return(0);
            }

            if (usedGrid >= maxUseGrid)
            {
                return(0);
            }

            //if too deep
            if (depth > generateConfig.randomCutAtDeep && Random(1, depth) < generateConfig.cutParam)
            {
                return(1);
            }

            Grid grid = grids[x, y];

            if (grid.steped)
            {
                return(0);
            }
            grid.steped = true;

            if (grid.owner == null)
            {
                RoomGenerateInfo info = RandomFightRoom();
                if (info.ty != null)
                {
                    RoomNode room = (RoomNode)Activator.CreateInstance(info.ty);
                    room.roomType = info.roomType;
                    if (room.Place(x, y, this))
                    {
                        ++curGenerateInfo.normalRoomCount;
                        usedGrid += room.gridList.Count;
                        roomList.Add(room);
                        room.SetPosition(room.gridList[0].position);
                        room.RepositionDoors();
                        room.CalculateTransportPos();
                    }
                }
            }

            //4 direction
            var dirOffset = GenDirList();

            if (1 == GenerateAt(x + dirOffset[0].x, y + dirOffset[0].y, depth + 1))
            {
                return(1);
            }
            if (1 == GenerateAt(x + dirOffset[1].x, y + dirOffset[1].y, depth + 1))
            {
                return(1);
            }
            if (1 == GenerateAt(x + dirOffset[2].x, y + dirOffset[2].y, depth + 1))
            {
                return(1);
            }
            if (1 == GenerateAt(x + dirOffset[3].x, y + dirOffset[3].y, depth + 1))
            {
                return(1);
            }

            return(0);
        }
        //Place a hidden room that can reduce the other 2 rooms' "Graph Distance"
        void PlaceHiddenRoom()
        {
            List <Type> pools = generateConfig.hiddenRoomPools;

            if (pools.Count < 1)
            {
                return;
            }

            RoomNode room = null;
            int      rnd  = UnityEngine.Random.Range(0, pools.Count);

            room          = (RoomNode)Activator.CreateInstance(pools[rnd]);
            room.roomType = RoomType.Hidden;

            HashSet <RoomType> avoidConnectTo = new HashSet <RoomType>()
            {
                RoomType.Boss,
            };

            CalculateRoomDistance();
            int         canReduceLength  = 0;
            List <Grid> connectableGrids = GetConnectableGrids();

            for (int i = 0; i < connectableGrids.Count; ++i)
            {
                var gridIndex = connectableGrids[i].index;
                var tmpRoom   = (RoomNode)Activator.CreateInstance(pools[rnd]);
                if (tmpRoom.Place(gridIndex.x, gridIndex.y, this, false, avoidConnectTo))
                {
                    var        hset  = GetConnectedRoom(tmpRoom);
                    RoomNode[] rooms = new RoomNode[hset.Count];
                    hset.CopyTo(rooms);

                    if (room.gridList.Count <= 0)
                    {
                        room = tmpRoom;

                        for (int fromRoom = 0; fromRoom < rooms.Length; ++fromRoom)
                        {
                            for (int toRoom = fromRoom + 1; toRoom < rooms.Length; ++toRoom)
                            {
                                canReduceLength = Mathf.Max(canReduceLength, roomDistanceMap[fromRoom, toRoom]);
                            }
                        }
                    }
                    else
                    {
                        int tmpCanreduce = 0;
                        for (int fromRoom = 0; fromRoom < rooms.Length; ++fromRoom)
                        {
                            for (int toRoom = fromRoom + 1; toRoom < rooms.Length; ++toRoom)
                            {
                                tmpCanreduce = Mathf.Max(tmpCanreduce, roomDistanceMap[fromRoom, toRoom]);
                            }
                        }

                        if (tmpCanreduce > canReduceLength)
                        {
                            room.Revert();
                            room            = tmpRoom;
                            canReduceLength = tmpCanreduce;
                        }
                        else
                        {
                            tmpRoom.Revert();
                        }
                    }
                }
            }

            if (room.gridList.Count > 0)
            {
                room.roomType = RoomType.Hidden;
                ++curGenerateInfo.hiddenRoomCount;
                usedGrid += room.gridList.Count;
                roomList.Add(room);
                room.SetPosition(room.gridList[0].position);
                room.RepositionDoors();
                room.CalculateTransportPos();
            }
            else
            {
                Debug.LogError("Generate Hidden Room failed");
            }
        }
        void PlaceSuperHiddenRoom()
        {
            RoomNode    bossRoom = GetBossRoom();
            List <Type> pools    = generateConfig.spHiddenRoomPools;

            if (pools.Count < 1)
            {
                return;
            }
            RoomNode room = null;

            int rnd = UnityEngine.Random.Range(0, pools.Count);

            room = (RoomNode)Activator.CreateInstance(pools[rnd]);

            HashSet <RoomType> avoidConnectTo = new HashSet <RoomType>()
            {
                RoomType.Reward,
                RoomType.Shop,
                RoomType.Hidden,
                RoomType.Boss,
            };

            float       maxDis           = 0f;
            List <Grid> connectableGrids = GetConnectableGrids();

            //make it 0~n : Far from boss room to Near boss room
            connectableGrids.Sort((a, b) =>
            {
                float disA = Vector3.Distance(bossRoom.gridList[0].position, a.position);
                float disB = Vector3.Distance(bossRoom.gridList[0].position, b.position);

                maxDis = Mathf.Max(maxDis, disA);
                maxDis = Mathf.Max(maxDis, disB);

                if (disA < disB)
                {
                    return(1);
                }
                if (disA == disB)
                {
                    return(0);
                }
                return(-1);
            });

            for (int i = 0; i < connectableGrids.Count; ++i)
            {
                var gridIndex = connectableGrids[i].index;
                var tmpRoom   = (RoomNode)Activator.CreateInstance(pools[rnd]);
                if (tmpRoom.Place(gridIndex.x, gridIndex.y, this, true))
                {
                    if (room.gridList.Count <= 0)
                    {
                        room = tmpRoom;
                    }
                    else
                    {
                        int   rndDis = Random(0, (int)maxDis);
                        float disA   = Vector3.Distance(bossRoom.gridList[0].position, tmpRoom.gridList[0].position);
                        if (rndDis > disA)
                        {
                            room.Revert();
                            room = tmpRoom;
                        }
                    }
                }
            }

            if (room.gridList.Count > 0)
            {
                room.roomType = RoomType.SuperHidden;
                ++curGenerateInfo.spHiddenRoomCount;
                usedGrid += room.gridList.Count;
                roomList.Add(room);
                room.SetPosition(room.gridList[0].position);
                room.RepositionDoors();
                room.CalculateTransportPos();
            }
            else
            {
                Debug.LogError("Generate SPHidden Room failed");
            }
        }