goto.py 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. """
  2. Copied and adapted from https://github.com/mila-iqia/babyai.
  3. Levels described in the Baby AI ICLR 2019 submission, with the `Go to` instruction.
  4. """
  5. from __future__ import annotations
  6. from minigrid.envs.babyai.core.levelgen import LevelGen
  7. from minigrid.envs.babyai.core.roomgrid_level import RejectSampling, RoomGridLevel
  8. from minigrid.envs.babyai.core.verifier import GoToInstr, ObjDesc
  9. class GoToRedBallGrey(RoomGridLevel):
  10. """
  11. Go to the red ball, single room, with distractors.
  12. The distractors are all grey to reduce perceptual complexity.
  13. This level has distractors but doesn't make use of language.
  14. """
  15. def __init__(self, room_size=8, num_dists=7, **kwargs):
  16. self.num_dists = num_dists
  17. super().__init__(num_rows=1, num_cols=1, room_size=room_size, **kwargs)
  18. def gen_mission(self):
  19. self.place_agent()
  20. obj, _ = self.add_object(0, 0, "ball", "red")
  21. dists = self.add_distractors(num_distractors=self.num_dists, all_unique=False)
  22. for dist in dists:
  23. dist.color = "grey"
  24. # Make sure no unblocking is required
  25. self.check_objs_reachable()
  26. self.instrs = GoToInstr(ObjDesc(obj.type, obj.color))
  27. class GoToRedBall(RoomGridLevel):
  28. """
  29. Go to the red ball, single room, with distractors.
  30. This level has distractors but doesn't make use of language.
  31. """
  32. def __init__(self, room_size=8, num_dists=7, **kwargs):
  33. self.num_dists = num_dists
  34. super().__init__(num_rows=1, num_cols=1, room_size=room_size, **kwargs)
  35. def gen_mission(self):
  36. self.place_agent()
  37. obj, _ = self.add_object(0, 0, "ball", "red")
  38. self.add_distractors(num_distractors=self.num_dists, all_unique=False)
  39. # Make sure no unblocking is required
  40. self.check_objs_reachable()
  41. self.instrs = GoToInstr(ObjDesc(obj.type, obj.color))
  42. class GoToRedBallNoDists(GoToRedBall):
  43. """
  44. Go to the red ball. No distractors present.
  45. """
  46. def __init__(self, **kwargs):
  47. super().__init__(room_size=8, num_dists=0, **kwargs)
  48. class GoToObj(RoomGridLevel):
  49. """
  50. Go to an object, inside a single room with no doors, no distractors
  51. """
  52. def __init__(self, room_size=8, **kwargs):
  53. super().__init__(num_rows=1, num_cols=1, room_size=room_size, **kwargs)
  54. def gen_mission(self):
  55. self.place_agent()
  56. objs = self.add_distractors(num_distractors=1)
  57. obj = objs[0]
  58. self.instrs = GoToInstr(ObjDesc(obj.type, obj.color))
  59. class GoToLocal(RoomGridLevel):
  60. """
  61. Go to an object, inside a single room with no doors, no distractors
  62. """
  63. def __init__(self, room_size=8, num_dists=8, **kwargs):
  64. self.num_dists = num_dists
  65. super().__init__(num_rows=1, num_cols=1, room_size=room_size, **kwargs)
  66. def gen_mission(self):
  67. self.place_agent()
  68. objs = self.add_distractors(num_distractors=self.num_dists, all_unique=False)
  69. self.check_objs_reachable()
  70. obj = self._rand_elem(objs)
  71. self.instrs = GoToInstr(ObjDesc(obj.type, obj.color))
  72. class GoTo(RoomGridLevel):
  73. """
  74. Go to an object, the object may be in another room. Many distractors.
  75. """
  76. def __init__(
  77. self,
  78. room_size=8,
  79. num_rows=3,
  80. num_cols=3,
  81. num_dists=18,
  82. doors_open=False,
  83. **kwargs,
  84. ):
  85. self.num_dists = num_dists
  86. self.doors_open = doors_open
  87. super().__init__(
  88. num_rows=num_rows, num_cols=num_cols, room_size=room_size, **kwargs
  89. )
  90. def gen_mission(self):
  91. self.place_agent()
  92. self.connect_all()
  93. objs = self.add_distractors(num_distractors=self.num_dists, all_unique=False)
  94. self.check_objs_reachable()
  95. obj = self._rand_elem(objs)
  96. self.instrs = GoToInstr(ObjDesc(obj.type, obj.color))
  97. # If requested, open all the doors
  98. if self.doors_open:
  99. self.open_all_doors()
  100. class GoToImpUnlock(RoomGridLevel):
  101. """
  102. Go to an object, which may be in a locked room.
  103. Competencies: Maze, GoTo, ImpUnlock
  104. No unblocking.
  105. """
  106. def gen_mission(self):
  107. # Add a locked door to a random room
  108. id = self._rand_int(0, self.num_cols)
  109. jd = self._rand_int(0, self.num_rows)
  110. door, pos = self.add_door(id, jd, locked=True)
  111. locked_room = self.get_room(id, jd)
  112. # Add the key to a different room
  113. while True:
  114. ik = self._rand_int(0, self.num_cols)
  115. jk = self._rand_int(0, self.num_rows)
  116. if ik is id and jk is jd:
  117. continue
  118. self.add_object(ik, jk, "key", door.color)
  119. break
  120. self.connect_all()
  121. # Add distractors to all but the locked room.
  122. # We do this to speed up the reachability test,
  123. # which otherwise will reject all levels with
  124. # objects in the locked room.
  125. for i in range(self.num_cols):
  126. for j in range(self.num_rows):
  127. if i is not id or j is not jd:
  128. self.add_distractors(i, j, num_distractors=2, all_unique=False)
  129. # The agent must be placed after all the object to respect constraints
  130. while True:
  131. self.place_agent()
  132. start_room = self.room_from_pos(*self.agent_pos)
  133. # Ensure that we are not placing the agent in the locked room
  134. if start_room is locked_room:
  135. continue
  136. break
  137. self.check_objs_reachable()
  138. # Add a single object to the locked room
  139. # The instruction requires going to an object matching that description
  140. (obj,) = self.add_distractors(id, jd, num_distractors=1, all_unique=False)
  141. self.instrs = GoToInstr(ObjDesc(obj.type, obj.color))
  142. class GoToSeq(LevelGen):
  143. """
  144. Sequencing of go-to-object commands.
  145. Competencies: Maze, GoTo, Seq
  146. No locked room.
  147. No locations.
  148. No unblocking.
  149. """
  150. def __init__(self, room_size=8, num_rows=3, num_cols=3, num_dists=18, **kwargs):
  151. super().__init__(
  152. room_size=room_size,
  153. num_rows=num_rows,
  154. num_cols=num_cols,
  155. num_dists=num_dists,
  156. action_kinds=["goto"],
  157. locked_room_prob=0,
  158. locations=False,
  159. unblocking=False,
  160. **kwargs,
  161. )
  162. class GoToRedBlueBall(RoomGridLevel):
  163. """
  164. Go to the red ball or to the blue ball.
  165. There is exactly one red or blue ball, and some distractors.
  166. The distractors are guaranteed not to be red or blue balls.
  167. Language is not required to solve this level.
  168. """
  169. def __init__(self, room_size=8, num_dists=7, **kwargs):
  170. self.num_dists = num_dists
  171. super().__init__(num_rows=1, num_cols=1, room_size=room_size, **kwargs)
  172. def gen_mission(self):
  173. self.place_agent()
  174. dists = self.add_distractors(num_distractors=self.num_dists, all_unique=False)
  175. # Ensure there is only one red or blue ball
  176. for dist in dists:
  177. if dist.type == "ball" and (dist.color == "blue" or dist.color == "red"):
  178. raise RejectSampling("can only have one blue or red ball")
  179. color = self._rand_elem(["red", "blue"])
  180. obj, _ = self.add_object(0, 0, "ball", color)
  181. # Make sure no unblocking is required
  182. self.check_objs_reachable()
  183. self.instrs = GoToInstr(ObjDesc(obj.type, obj.color))
  184. class GoToDoor(RoomGridLevel):
  185. """
  186. Go to a door
  187. (of a given color, in the current room)
  188. No distractors, no language variation
  189. """
  190. def __init__(self, **kwargs):
  191. super().__init__(room_size=7, **kwargs)
  192. def gen_mission(self):
  193. objs = []
  194. for _ in range(4):
  195. door, _ = self.add_door(1, 1)
  196. objs.append(door)
  197. self.place_agent(1, 1)
  198. obj = self._rand_elem(objs)
  199. self.instrs = GoToInstr(ObjDesc("door", obj.color))
  200. class GoToObjDoor(RoomGridLevel):
  201. """
  202. Go to an object or door
  203. (of a given type and color, in the current room)
  204. """
  205. def __init__(self, **kwargs):
  206. super().__init__(room_size=8, **kwargs)
  207. def gen_mission(self):
  208. self.place_agent(1, 1)
  209. objs = self.add_distractors(1, 1, num_distractors=8, all_unique=False)
  210. for _ in range(4):
  211. door, _ = self.add_door(1, 1)
  212. objs.append(door)
  213. self.check_objs_reachable()
  214. obj = self._rand_elem(objs)
  215. self.instrs = GoToInstr(ObjDesc(obj.type, obj.color))