def populate_room()

in textworld/generator/world.py [0:0]


    def populate_room(self, nb_objects: int, room: Variable,
                      rng: Optional[RandomState] = None,
                      object_types_probs: Optional[Dict[str, float]] = None) -> List[Proposition]:
        rng = g_rng.next() if rng is None else rng
        state = []
        types_counts = self.kb.types.count(self.state)

        inventory = Variable("I", "I")
        objects_holder = [inventory, room]

        locked_or_closed_objects = []
        lockable_objects = []
        for s in self.facts:
            # Look for containers and supporters to put stuff in/on them.
            if s.name == "at" and s.arguments[0].type in ["c", "s"] and s.arguments[1].name == room.name:
                objects_holder.append(s.arguments[0])

            # Look for containers and doors without a matching key.
            if s.name == "at" and s.arguments[0].type in ["c", "d"] and s.arguments[1].name == room.name:
                obj_propositions = [p.name for p in self.facts if s.arguments[0].name in p.names]
                if "match" not in obj_propositions and s.arguments[0] not in lockable_objects:
                    lockable_objects.append(s.arguments[0])

                    if "locked" in obj_propositions or "closed" in obj_propositions:
                        locked_or_closed_objects.append(s.arguments[0])

        object_id = 0
        while object_id < nb_objects:
            if len(locked_or_closed_objects) > 0:
                # Prioritize adding key if there are locked or closed things in the room.
                obj_type = "k"
            else:
                obj_type = self.kb.types.sample(parent_type='t', rng=rng, exceptions=["d", "r"],
                                                include_parent=False, probs=object_types_probs)

            if self.kb.types.is_descendant_of(obj_type, "o"):
                obj_name = get_new(obj_type, types_counts)
                obj = Variable(obj_name, obj_type)
                allowed_objects_holder = list(objects_holder)

                if obj_type == "k":
                    if len(locked_or_closed_objects) > 0:
                        # Look for a *locked* container or a door.
                        rng.shuffle(locked_or_closed_objects)
                        locked_or_closed_obj = locked_or_closed_objects.pop()
                        state.append(Proposition("match", [obj, locked_or_closed_obj]))
                        lockable_objects.remove(locked_or_closed_obj)

                        # Do not place the key in its own matching container.
                        if locked_or_closed_obj in allowed_objects_holder:
                            allowed_objects_holder.remove(locked_or_closed_obj)

                    elif len(lockable_objects) > 0:
                        # Look for a container or a door.
                        rng.shuffle(lockable_objects)
                        lockable_obj = lockable_objects.pop()
                        state.append(Proposition("match", [obj, lockable_obj]))
                    else:
                        continue  # Unuseful key is not allowed.

                elif obj_type == "f":
                    # HACK: manually add the edible property to food items.
                    state.append(Proposition("edible", [obj]))

                # Place the object somewhere.
                obj_holder = rng.choice(allowed_objects_holder)
                if self.kb.types.is_descendant_of(obj_holder.type, "s"):
                    state.append(Proposition("on", [obj, obj_holder]))
                elif self.kb.types.is_descendant_of(obj_holder.type, "c"):
                    state.append(Proposition("in", [obj, obj_holder]))
                elif self.kb.types.is_descendant_of(obj_holder.type, "I"):
                    state.append(Proposition("in", [obj, obj_holder]))
                elif self.kb.types.is_descendant_of(obj_holder.type, "r"):
                    state.append(Proposition("at", [obj, obj_holder]))
                else:
                    raise ValueError("Unknown type for object holder: {}".format(obj_holder))

            elif self.kb.types.is_descendant_of(obj_type, "s"):
                supporter_name = get_new(obj_type, types_counts)
                supporter = Variable(supporter_name, obj_type)
                state.append(Proposition("at", [supporter, room]))
                objects_holder.append(supporter)

            elif self.kb.types.is_descendant_of(obj_type, "c"):
                container_name = get_new(obj_type, types_counts)
                container = Variable(container_name, obj_type)
                state.append(Proposition("at", [container, room]))
                objects_holder.append(container)

                container_state = rng.choice(["open", "closed", "locked"])
                state.append(Proposition(container_state, [container]))

                lockable_objects.append(container)
                if container_state in ["locked", "closed"]:
                    locked_or_closed_objects.append(container)

            else:
                raise ValueError("Unknown object type: {}".format(obj_type))

            object_id += 1

        self.add_facts(state)
        return state