unlock.py 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. """
  2. Copied and adapted from https://github.com/mila-iqia/babyai.
  3. Levels described in the Baby AI ICLR 2019 submission, with the `Unlock` instruction.
  4. """
  5. from minigrid.core.constants import COLOR_NAMES
  6. from minigrid.envs.babyai.core.roomgrid_level import RoomGridLevel
  7. from minigrid.envs.babyai.core.verifier import ObjDesc, OpenInstr, PickupInstr
  8. from minigrid.minigrid_env import Ball, Box, Key
  9. class Unlock(RoomGridLevel):
  10. """
  11. Unlock a door.
  12. Competencies: Maze, Open, Unlock. No unblocking.
  13. """
  14. def gen_mission(self):
  15. # Add a locked door to a random room
  16. id = self._rand_int(0, self.num_cols)
  17. jd = self._rand_int(0, self.num_rows)
  18. door, pos = self.add_door(id, jd, locked=True)
  19. locked_room = self.get_room(id, jd)
  20. # Add the key to a different room
  21. while True:
  22. ik = self._rand_int(0, self.num_cols)
  23. jk = self._rand_int(0, self.num_rows)
  24. if ik is id and jk is jd:
  25. continue
  26. self.add_object(ik, jk, "key", door.color)
  27. break
  28. # With 50% probability, ensure that the locked door is the only
  29. # door of that color
  30. if self._rand_bool():
  31. colors = list(filter(lambda c: c is not door.color, COLOR_NAMES))
  32. self.connect_all(door_colors=colors)
  33. else:
  34. self.connect_all()
  35. # Add distractors to all but the locked room.
  36. # We do this to speed up the reachability test,
  37. # which otherwise will reject all levels with
  38. # objects in the locked room.
  39. for i in range(self.num_cols):
  40. for j in range(self.num_rows):
  41. if i is not id or j is not jd:
  42. self.add_distractors(i, j, num_distractors=3, all_unique=False)
  43. # The agent must be placed after all the object to respect constraints
  44. while True:
  45. self.place_agent()
  46. start_room = self.room_from_pos(*self.agent_pos)
  47. # Ensure that we are not placing the agent in the locked room
  48. if start_room is locked_room:
  49. continue
  50. break
  51. self.check_objs_reachable()
  52. self.instrs = OpenInstr(ObjDesc(door.type, door.color))
  53. class UnlockLocal(RoomGridLevel):
  54. """
  55. Fetch a key and unlock a door
  56. (in the current room)
  57. """
  58. def __init__(self, distractors=False, **kwargs):
  59. self.distractors = distractors
  60. super().__init__(**kwargs)
  61. def gen_mission(self):
  62. door, _ = self.add_door(1, 1, locked=True)
  63. self.add_object(1, 1, "key", door.color)
  64. if self.distractors:
  65. self.add_distractors(1, 1, num_distractors=3)
  66. self.place_agent(1, 1)
  67. self.instrs = OpenInstr(ObjDesc(door.type))
  68. class KeyInBox(RoomGridLevel):
  69. """
  70. Unlock a door. Key is in a box (in the current room).
  71. """
  72. def __init__(self, **kwargs):
  73. super().__init__(**kwargs)
  74. def gen_mission(self):
  75. door, _ = self.add_door(1, 1, locked=True)
  76. # Put the key in the box, then place the box in the room
  77. key = Key(door.color)
  78. box = Box(self._rand_color(), key)
  79. self.place_in_room(1, 1, box)
  80. self.place_agent(1, 1)
  81. self.instrs = OpenInstr(ObjDesc(door.type))
  82. class UnlockPickup(RoomGridLevel):
  83. """
  84. Unlock a door, then pick up a box in another room
  85. """
  86. def __init__(self, distractors=False, **kwargs):
  87. self.distractors = distractors
  88. room_size = 6
  89. super().__init__(
  90. num_rows=1,
  91. num_cols=2,
  92. room_size=room_size,
  93. max_steps=8 * room_size**2,
  94. **kwargs
  95. )
  96. def gen_mission(self):
  97. # Add a random object to the room on the right
  98. obj, _ = self.add_object(1, 0, kind="box")
  99. # Make sure the two rooms are directly connected by a locked door
  100. door, _ = self.add_door(0, 0, 0, locked=True)
  101. # Add a key to unlock the door
  102. self.add_object(0, 0, "key", door.color)
  103. if self.distractors:
  104. self.add_distractors(num_distractors=4)
  105. self.place_agent(0, 0)
  106. self.instrs = PickupInstr(ObjDesc(obj.type, obj.color))
  107. class BlockedUnlockPickup(RoomGridLevel):
  108. """
  109. Unlock a door blocked by a ball, then pick up a box
  110. in another room
  111. """
  112. def __init__(self, **kwargs):
  113. room_size = 6
  114. super().__init__(
  115. num_rows=1,
  116. num_cols=2,
  117. room_size=room_size,
  118. max_steps=16 * room_size**2,
  119. **kwargs
  120. )
  121. def gen_mission(self):
  122. # Add a box to the room on the right
  123. obj, _ = self.add_object(1, 0, kind="box")
  124. # Make sure the two rooms are directly connected by a locked door
  125. door, pos = self.add_door(0, 0, 0, locked=True)
  126. # Block the door with a ball
  127. color = self._rand_color()
  128. self.grid.set(pos[0] - 1, pos[1], Ball(color))
  129. # Add a key to unlock the door
  130. self.add_object(0, 0, "key", door.color)
  131. self.place_agent(0, 0)
  132. self.instrs = PickupInstr(ObjDesc(obj.type))
  133. class UnlockToUnlock(RoomGridLevel):
  134. """
  135. Unlock a door A that requires to unlock a door B before
  136. """
  137. def __init__(self, **kwargs):
  138. room_size = 6
  139. super().__init__(
  140. num_rows=1,
  141. num_cols=3,
  142. room_size=room_size,
  143. max_steps=30 * room_size**2,
  144. **kwargs
  145. )
  146. def gen_mission(self):
  147. colors = self._rand_subset(COLOR_NAMES, 2)
  148. # Add a door of color A connecting left and middle room
  149. self.add_door(0, 0, door_idx=0, color=colors[0], locked=True)
  150. # Add a key of color A in the room on the right
  151. self.add_object(2, 0, kind="key", color=colors[0])
  152. # Add a door of color B connecting middle and right room
  153. self.add_door(1, 0, door_idx=0, color=colors[1], locked=True)
  154. # Add a key of color B in the middle room
  155. self.add_object(1, 0, kind="key", color=colors[1])
  156. obj, _ = self.add_object(0, 0, kind="ball")
  157. self.place_agent(1, 0)
  158. self.instrs = PickupInstr(ObjDesc(obj.type))