| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283 | from gym_minigrid.minigrid import *from gym_minigrid.register import registerclass Room:    def __init__(self,        top,        size,        entryDoorPos,        exitDoorPos    ):        self.top = top        self.size = size        self.entryDoorPos = entryDoorPos        self.exitDoorPos = exitDoorPosclass MultiRoomEnv(MiniGridEnv):    """    Environment with multiple rooms (subgoals)    """    def __init__(self,        minNumRooms,        maxNumRooms,        maxRoomSize=10    ):        assert minNumRooms > 0        assert maxNumRooms >= minNumRooms        assert maxRoomSize >= 4        self.minNumRooms = minNumRooms        self.maxNumRooms = maxNumRooms        self.maxRoomSize = maxRoomSize        self.rooms = []        super(MultiRoomEnv, self).__init__(            gridSize=25,            maxSteps=self.maxNumRooms * 20        )    def _genGrid(self, width, height):        roomList = []        # Choose a random number of rooms to generate        numRooms = self._randInt(self.minNumRooms, self.maxNumRooms+1)        while len(roomList) < numRooms:            curRoomList = []            entryDoorPos = (                self._randInt(0, width - 2),                self._randInt(0, width - 2)            )            # Recursively place the rooms            self._placeRoom(                numRooms,                roomList=curRoomList,                minSz=4,                maxSz=self.maxRoomSize,                entryDoorWall=2,                entryDoorPos=entryDoorPos            )            if len(curRoomList) > len(roomList):                roomList = curRoomList        # Store the list of rooms in this environment        assert len(roomList) > 0        self.rooms = roomList        # Randomize the starting agent position and direction        topX, topY = roomList[0].top        sizeX, sizeY = roomList[0].size        self.startPos = (            self._randInt(topX + 1, topX + sizeX - 2),            self._randInt(topY + 1, topY + sizeY - 2)        )        self.startDir = self._randInt(0, 4)        # Create the grid        grid = Grid(width, height)        wall = Wall()        prevDoorColor = None        # For each room        for idx, room in enumerate(roomList):            topX, topY = room.top            sizeX, sizeY = room.size            # Draw the top and bottom walls            for i in range(0, sizeX):                grid.set(topX + i, topY, wall)                grid.set(topX + i, topY + sizeY - 1, wall)            # Draw the left and right walls            for j in range(0, sizeY):                grid.set(topX, topY + j, wall)                grid.set(topX + sizeX - 1, topY + j, wall)            # If this isn't the first room, place the entry door            if idx > 0:                # Pick a door color different from the previous one                doorColors = set(COLOR_NAMES)                if prevDoorColor:                    doorColors.remove(prevDoorColor)                # Note: the use of sorting here guarantees determinism,                # This is needed because Python's set is not deterministic                doorColor = self._randElem(sorted(doorColors))                entryDoor = Door(doorColor)                grid.set(*room.entryDoorPos, entryDoor)                prevDoorColor = doorColor                prevRoom = roomList[idx-1]                prevRoom.exitDoorPos = room.entryDoorPos        # Place the final goal        while True:            self.goalPos = (                self._randInt(topX + 1, topX + sizeX - 1),                self._randInt(topY + 1, topY + sizeY - 1)            )            # Make sure the goal doesn't overlap with the agent            if self.goalPos != self.startPos:                grid.set(*self.goalPos, Goal())                break        self.mission = 'traverse the rooms to get to the goal'        return grid    def _placeRoom(        self,        numLeft,        roomList,        minSz,        maxSz,        entryDoorWall,        entryDoorPos    ):        # Choose the room size randomly        sizeX = self._randInt(minSz, maxSz+1)        sizeY = self._randInt(minSz, maxSz+1)        # The first room will be at the door position        if len(roomList) == 0:            topX, topY = entryDoorPos        # Entry on the right        elif entryDoorWall == 0:            topX = entryDoorPos[0] - sizeX + 1            y = entryDoorPos[1]            topY = self._randInt(y - sizeY + 2, y)        # Entry wall on the south        elif entryDoorWall == 1:            x = entryDoorPos[0]            topX = self._randInt(x - sizeX + 2, x)            topY = entryDoorPos[1] - sizeY + 1        # Entry wall on the left        elif entryDoorWall == 2:            topX = entryDoorPos[0]            y = entryDoorPos[1]            topY = self._randInt(y - sizeY + 2, y)        # Entry wall on the top        elif entryDoorWall == 3:            x = entryDoorPos[0]            topX = self._randInt(x - sizeX + 2, x)            topY = entryDoorPos[1]        else:            assert False, entryDoorWall        # If the room is out of the grid, can't place a room here        if topX < 0 or topY < 0:            return False        if topX + sizeX > self.gridSize or topY + sizeY >= self.gridSize:            return False        # If the room intersects with previous rooms, can't place it here        for room in roomList[:-1]:            nonOverlap = \                topX + sizeX < room.top[0] or \                room.top[0] + room.size[0] <= topX or \                topY + sizeY < room.top[1] or \                room.top[1] + room.size[1] <= topY            if not nonOverlap:                return False        # Add this room to the list        roomList.append(Room(            (topX, topY),            (sizeX, sizeY),            entryDoorPos,            None        ))        # If this was the last room, stop        if numLeft == 1:            return True        # Try placing the next room        for i in range(0, 8):            # Pick which wall to place the out door on            wallSet = set((0, 1, 2, 3))            wallSet.remove(entryDoorWall)            exitDoorWall = self._randElem(sorted(wallSet))            nextEntryWall = (exitDoorWall + 2) % 4            # Pick the exit door position            # Exit on right wall            if exitDoorWall == 0:                exitDoorPos = (                    topX + sizeX - 1,                    topY + self._randInt(1, sizeY - 1)                )            # Exit on south wall            elif exitDoorWall == 1:                exitDoorPos = (                    topX + self._randInt(1, sizeX - 1),                    topY + sizeY - 1                )            # Exit on left wall            elif exitDoorWall == 2:                exitDoorPos = (                    topX,                    topY + self._randInt(1, sizeY - 1)                )            # Exit on north wall            elif exitDoorWall == 3:                exitDoorPos = (                    topX + self._randInt(1, sizeX - 1),                    topY                )            else:                assert False            # Recursively create the other rooms            success = self._placeRoom(                numLeft - 1,                roomList=roomList,                minSz=minSz,                maxSz=maxSz,                entryDoorWall=nextEntryWall,                entryDoorPos=exitDoorPos            )            if success:                break        return Trueclass MultiRoomEnvN2S4(MultiRoomEnv):    def __init__(self):        super().__init__(            minNumRooms=2,            maxNumRooms=2,            maxRoomSize=4        )class MultiRoomEnvN6(MultiRoomEnv):    def __init__(self):        super().__init__(            minNumRooms=6,            maxNumRooms=6        )register(    id='MiniGrid-MultiRoom-N2-S4-v0',    entry_point='gym_minigrid.envs:MultiRoomEnvN2S4',    reward_threshold=1000.0)register(    id='MiniGrid-MultiRoom-N6-v0',    entry_point='gym_minigrid.envs:MultiRoomEnvN6',    reward_threshold=1000.0)
 |