def test_match(): rule = Rule.parse( "go :: at(P, r) & $link(r, d, r') & $free(r, r') & $free(r', r) -> at(P, r')" ) mapping = { Placeholder.parse("P"): Variable.parse("P"), Placeholder.parse("r"): Variable.parse("r1: r"), Placeholder.parse("r'"): Variable.parse("r2: r"), Placeholder.parse("d"): Variable.parse("d"), } action = Action.parse( "go :: at(P, r1: r) & $link(r1: r, d, r2: r) & $free(r1: r, r2: r) & $free(r2: r, r1: r) -> at(P, r2: r)" ) assert rule.match(action) == mapping # Order shouldn't matter action = Action.parse( "go :: $link(r1: r, d, r2: r) & $free(r1: r, r2: r) & $free(r2: r, r1: r) & at(P, r1: r) -> at(P, r2: r)" ) assert rule.match(action) == mapping action = Action.parse( "go :: at(P, r1: r) & $link(r1: r, d, r2: r) & $free(r2: r, r1: r) & $free(r1: r, r2: r) -> at(P, r2: r)" ) assert rule.match(action) == mapping # Predicate matches can't conflict action = Action.parse( "go :: at(P, r1: r) & $link(r1: r, d, r2: r) & $free(r2: r, r1: r) & $free(r1: r, r2: r) -> at(P, r3: r)" ) assert rule.match(action) == None
def test_going_through_door(): P = Variable("P", "P") room = Variable("room", "r") kitchen = Variable("kitchen", "r") state = State(KnowledgeBase.default().logic) state.add_facts([ Proposition("at", [P, room]), Proposition("north_of", [kitchen, room]), Proposition("free", [kitchen, room]), Proposition("free", [room, kitchen]), Proposition("south_of", [room, kitchen]) ]) options = ChainingOptions() options.backward = True options.max_depth = 3 options.max_length = 3 options.subquests = True options.create_variables = True options.rules_per_depth = [ [KnowledgeBase.default().rules["take/c"], KnowledgeBase.default().rules["take/s"]], KnowledgeBase.default().rules.get_matching("go.*"), [KnowledgeBase.default().rules["open/d"]], ] chains = list(get_chains(state, options)) assert len(chains) == 18
def test_get_visible_objects_in(): P = Variable("P") room = Variable("room", "r") chest = Variable("chest", "c") obj = Variable("obj", "o") # Closed chest. facts = [Proposition("at", [P, room]), Proposition("at", [chest, room]), Proposition("in", [obj, chest]), Proposition("closed", [chest])] world = World.from_facts(facts) objects = world.get_visible_objects_in(world.player_room) assert obj in world.objects assert obj not in objects # Open chest. facts = [Proposition("at", [P, room]), Proposition("at", [chest, room]), Proposition("in", [obj, chest]), Proposition("open", [chest])] world = World.from_facts(facts) objects = world.get_visible_objects_in(world.player_room) assert obj in world.objects assert obj in objects
def build_state(locked_door=False): # Set up a world with two rooms and a few objecs. P = Variable("P") I = Variable("I") bedroom = Variable("bedroom", "r") kitchen = Variable("kitchen", "r") rusty_key = Variable("rusty key", "k") small_key = Variable("small key", "k") wooden_door = Variable("wooden door", "d") chest = Variable("chest", "c") cabinet = Variable("cabinet", "c") robe = Variable("robe", "o") state = State(KnowledgeBase.default().logic, [ Proposition("at", [P, bedroom]), Proposition("south_of", [kitchen, bedroom]), Proposition("north_of", [bedroom, kitchen]), Proposition("link", [bedroom, wooden_door, kitchen]), Proposition("link", [kitchen, wooden_door, bedroom]), Proposition("locked" if locked_door else "closed", [wooden_door]), Proposition("in", [rusty_key, I]), Proposition("match", [rusty_key, chest]), Proposition("locked", [chest]), Proposition("at", [chest, kitchen]), Proposition("in", [small_key, chest]), Proposition("match", [small_key, cabinet]), Proposition("locked", [cabinet]), Proposition("at", [cabinet, bedroom]), Proposition("in", [robe, cabinet]), ]) return state
def test_state(): state = State() P = Variable.parse("P") kitchen = Variable.parse("kitchen: r") study = Variable.parse("study: r") stove = Variable.parse("stove: o") at_kitchen = Proposition.parse("at(P, kitchen: r)") in_kitchen = Proposition.parse("in(stove: o, kitchen: r)") at_study = Proposition.parse("at(P, study: r)") assert not state.is_fact(at_kitchen) assert not state.is_fact(in_kitchen) assert not state.is_fact(at_study) assert len(state.variables) == 0 assert len(state.variables_of_type("P")) == 0 assert len(state.variables_of_type("r")) == 0 assert len(state.variables_of_type("o")) == 0 state.add_fact(at_kitchen) state.add_fact(in_kitchen) assert state.is_fact(at_kitchen) assert state.is_fact(in_kitchen) assert not state.is_fact(at_study) assert set(state.variables) == {P, kitchen, stove} assert state.variables_of_type("P") == {P} assert state.variables_of_type("r") == {kitchen} assert state.variables_of_type("o") == {stove} state.remove_fact(at_kitchen) assert not state.is_fact(at_kitchen) assert state.is_fact(in_kitchen) assert not state.is_fact(at_study) assert set(state.variables) == {kitchen, stove} assert len(state.variables_of_type("P")) == 0 assert state.variables_of_type("r") == {kitchen} assert state.variables_of_type("o") == {stove} state.remove_fact(in_kitchen) assert not state.is_fact(at_kitchen) assert not state.is_fact(in_kitchen) assert not state.is_fact(at_study) assert len(state.variables) == 0 assert len(state.variables_of_type("P")) == 0 assert len(state.variables_of_type("r")) == 0 assert len(state.variables_of_type("o")) == 0 state.add_fact(at_study) assert not state.is_fact(at_kitchen) assert not state.is_fact(in_kitchen) assert state.is_fact(at_study) assert set(state.variables) == {P, study} assert state.variables_of_type("P") == {P} assert state.variables_of_type("r") == {study} assert len(state.variables_of_type("o")) == 0
def test_serialization_deserialization(): rule = KnowledgeBase.default().rules["go/east"] mapping = { Placeholder("r'"): Variable("room1", "r"), Placeholder("r"): Variable("room2"), } mapping.update(KnowledgeBase.default().types.constants_mapping) action = rule.instantiate(mapping) infos = action.serialize() action2 = Action.deserialize(infos) assert action == action2
def test_serialization_deserialization(): rule = data.get_rules()["go/east"] mapping = { Placeholder("r'"): Variable("room1", "r"), Placeholder("r"): Variable("room2"), } mapping.update(data.get_types().constants_mapping) action = rule.instantiate(mapping) infos = action.serialize() action2 = Action.deserialize(infos) assert action == action2
def main(): args = parse_args() P = Variable("P") # I = Variable("I") room = Variable("room", "r") kitchen = Variable("kitchen", "r") state = [ Proposition("at", [P, room]), Proposition("north_of", [kitchen, room]), Proposition("free", [kitchen, room]), Proposition("free", [room, kitchen]), Proposition("south_of", [room, kitchen]) ] # Sample quests. rng = np.random.RandomState(args.seed) chains = [] # rules_per_depth = {0: [data.get_rules()["take/c"], data.get_rules()["take/s"]], # 1: [data.get_rules()["open/c"]], # } rules_per_depth = { 0: [data.get_rules()["eat"]], 1: data.get_rules().get_matching("take/s.*"), 2: data.get_rules().get_matching("go.*"), 3: [data.get_rules()["open/d"]], 4: [data.get_rules()["unlock/d"]], 5: data.get_rules().get_matching("take/s.*", "take/c.*") } for i in range(args.nb_quests): chain = textworld.logic.sample_quest(state, rng, max_depth=args.quest_length, allow_partial_match=True, exceptions=[], rules_per_depth=rules_per_depth, backward=True) chains.append(chain[::-1]) print_chains(chains, verbose=args.verbose) actions_tree = build_tree_from_chains(chains) # Convert tree to networkx graph/tree filename = "sample_tree.svg" G, labels = actions_tree.to_networkx() if len(G) > 0: tree = nx.bfs_tree(G, actions_tree.no) save_graph_to_svg(tree, labels, filename, backward=True) else: try: os.remove(filename) except: pass
def test_backward_chaining(): P = Variable("P", "P") room = Variable("room", "r") kitchen = Variable("kitchen", "r") state = State([ Proposition("at", [P, room]), Proposition("north_of", [kitchen, room]), Proposition("south_of", [room, kitchen]), ]) rules_per_depth = { 0: [data.get_rules()["take/c"], data.get_rules()["take/s"]], 1: [data.get_rules()["open/c"]] } tree_of_possible = chaining.get_chains(state, max_depth=2, allow_partial_match=True, exceptions=['d'], rules_per_depth=rules_per_depth, backward=True) chains = list(tree_of_possible.traverse_preorder(subquests=True)) assert len(chains) == 3 for chain in chains: for depth, action in enumerate(chain): assert action.action.name in [ rule.name for rule in rules_per_depth[depth] ] rules_per_depth = { 0: [data.get_rules()["put"]], 1: [data.get_rules()["go/north"]], 2: [data.get_rules()["take/c"]] } tree_of_possible = chaining.get_chains(state, max_depth=3, allow_partial_match=True, exceptions=['d'], rules_per_depth=rules_per_depth, backward=True) chains = list(tree_of_possible.traverse_preorder(subquests=True)) assert len(chains) == 3 for chain in chains: for depth, action in enumerate(chain): assert action.action.name in [ rule.name for rule in rules_per_depth[depth] ]
def test_get_objects_in_inventory(): P = Variable("P") I = Variable("I") room = Variable("room", "r") obj = Variable("obj", "o") # Closed chest. facts = [Proposition("at", [P, room]), Proposition("in", [obj, I])] world = World.from_facts(facts) objects = world.get_objects_in_inventory() assert obj in world.objects assert obj in objects
def test_populate_with(): # setup P = Variable('P') I = Variable('I') room = Variable('room', 'r') facts = [Proposition('at', [P, room])] world = World.from_facts(facts) # test obj = Variable('obj', 'o') world.populate_with(objects=[obj]) assert obj in world.objects assert (Proposition('at', [obj, room]) in world.facts or Proposition('in', [obj, I]) in world.facts)
def create_variable(self, state, ph, type_counts): """Create a new variable of the given type.""" count = type_counts[ph.type] if not self.options.check_new_variable(state, ph.type, count): return None name = "{}_{}".format(ph.type, count) var = Variable(name, ph.type) while state.has_variable(var): name += "'" var = Variable(name, ph.type) type_counts[ph.type] += 1 return var
def test_going_through_door(): P = Variable("P", "P") room = Variable("room", "r") kitchen = Variable("kitchen", "r") state = State() state.add_facts([ Proposition("at", [P, room]), Proposition("north_of", [kitchen, room]), Proposition("free", [kitchen, room]), Proposition("free", [room, kitchen]), Proposition("south_of", [room, kitchen]) ]) # Sample quests. chains = [] rules_per_depth = { 0: [data.get_rules()["take/c"], data.get_rules()["take/s"]], 1: data.get_rules().get_matching("go.*"), 2: [data.get_rules()["open/d"]] } tree_of_possible = chaining.get_chains(state, max_depth=3, allow_partial_match=True, exceptions=[], rules_per_depth=rules_per_depth, backward=True) chains = list(tree_of_possible.traverse_preorder(subquests=True)) # chaining.print_chains(chains) # 1. take/c(P, room, c_0, o_0, I) # 2. take/c(P, room, c_0, o_0, I) -> go/north(P, r_0, room) # 3. take/c(P, room, c_0, o_0, I) -> go/north(P, r_0, room) -> open/d(P, r_0, d_0, room) # 4. take/c(P, room, c_0, o_0, I) -> go/south(P, kitchen, room) # 5. take/c(P, room, c_0, o_0, I) -> go/south(P, kitchen, room) -> open/d(P, kitchen, d_0, room) # 6. take/c(P, room, c_0, o_0, I) -> go/east(P, r_0, room) # 7. take/c(P, room, c_0, o_0, I) -> go/east(P, r_0, room) -> open/d(P, r_0, d_0, room) # 8. take/c(P, room, c_0, o_0, I) -> go/west(P, r_0, room) # 9. take/c(P, room, c_0, o_0, I) -> go/west(P, r_0, room) -> open/d(P, r_0, d_0, room) # 10. take/s(P, room, s_0, o_0, I) # 11. take/s(P, room, s_0, o_0, I) -> go/north(P, r_0, room) # 12. take/s(P, room, s_0, o_0, I) -> go/north(P, r_0, room) -> open/d(P, r_0, d_0, room) # 13. take/s(P, room, s_0, o_0, I) -> go/south(P, kitchen, room) # 14. take/s(P, room, s_0, o_0, I) -> go/south(P, kitchen, room) -> open/d(P, kitchen, d_0, room) # 15. take/s(P, room, s_0, o_0, I) -> go/east(P, r_0, room) # 16. take/s(P, room, s_0, o_0, I) -> go/east(P, r_0, room) -> open/d(P, r_0, d_0, room) # 17. take/s(P, room, s_0, o_0, I) -> go/west(P, r_0, room) # 18. take/s(P, room, s_0, o_0, I) -> go/west(P, r_0, room) -> open/d(P, r_0, d_0, room) assert len(chains) == 18
def new(self, type: str, name: Optional[str] = None, desc: Optional[str] = None) -> Union[WorldEntity, WorldRoom]: """ Creates new entity given its type. Args: type: The type of the entity. name: The name of the entity. desc: The description of the entity. Returns: The newly created entity. * If the `type` is `'r'`, then a `WorldRoom` object is returned. * Otherwise, a `WorldEntity` is returned. """ var_id = type if not data.get_types().is_constant(type): var_id = get_new(type, self._types_counts) var = Variable(var_id, type) if type == "r": entity = WorldRoom(var, name, desc) self.rooms.append(entity) else: entity = WorldEntity(var, name, desc) self._entities[var_id] = entity return entity
def _convert_to_needs_relation(proposition): if not proposition.name.startswith("needs_"): return proposition return Proposition("needs", [proposition.arguments[0], Variable(proposition.name.split("needs_")[-1], "STATE")])
def inventory_proposition(observation, objectVars, inventoryVar): updated_props = set() inventory = observation['inventory'] for item in inventory: key = item['type'] updated_props.add( Proposition("in", [Variable.parse(key), inventoryVar])) return updated_props
def _convert_variable(variable): if variable.name == "agent1": return Variable("P") elif variable.name.split("_", 1)[0] in [ "apple", "tomato", "potato", "bread", "lettuce", "egg" ]: return Variable(variable.name, "f") elif variable.name.split("_", 1)[0] in [ "garbagecan", "cabinet", "container", "fridge", "microwave", "sink" ]: return Variable(variable.name, "c") elif variable.name.split("_", 1)[0] in ["tabletop", "stoveburner"]: return Variable(variable.name, "s") elif variable.name.split("_", 1)[0] in [ "bowl", "pot", "plate", "mug", "fork", "knife", "pan", "spoon" ]: return Variable(variable.name, "o") elif variable.type == "location": return Variable(variable.name, "r") elif variable.type == "receptacle": return Variable(variable.name, "c") elif variable.type in ["otype", "rtype"]: return variable print("Unknown variable:", variable) return variable
def test_logic_parsing(): P = Variable("P", "P") kitchen = Variable("kitchen", "r") egg = Variable("egg", "f") assert Variable.parse("P") == P assert Variable.parse("kitchen: r") == kitchen at_kitchen = Proposition("at", [P, kitchen]) in_kitchen = Proposition("in", [egg, kitchen]) raw_egg = Proposition("raw", [egg]) cooked_egg = Proposition("cooked", [egg]) assert Proposition.parse("at(P, kitchen: r)") == at_kitchen assert Signature.parse("at(P, r)") == at_kitchen.signature cook_egg = Action("cook", [at_kitchen, in_kitchen, raw_egg], [at_kitchen, in_kitchen, cooked_egg]) assert Action.parse( "cook :: $at(P, kitchen: r) & $in(egg: f, kitchen: r) & raw(egg: f) -> cooked(egg: f)" ) == cook_egg P = Placeholder("P", "P") r = Placeholder("r", "r") d = Placeholder("d", "d") rp = Placeholder("r'", "r") assert Placeholder.parse("P") == P assert Placeholder.parse("r") == r assert Placeholder.parse("d") == d assert Placeholder.parse("r'") == rp at_r = Predicate("at", [P, r]) link = Predicate("link", [r, d, rp]) unlocked = Predicate("unlocked", [d]) at_rp = Predicate("at", [P, rp]) assert Predicate.parse("link(r, d, r')") == link go = Rule("go", [at_r, link, unlocked], [link, unlocked, at_rp]) assert Rule.parse( "go :: at(P, r) & $link(r, d, r') & $unlocked(d) -> at(P, r')") == go # Make sure the types match in the whole expression assert_raises(ValueError, Rule.parse, "take :: $at(P, r) & $in(c, r) & in(o: k, c) -> in(o, I)")
def get_human_readable_fact(self, fact: Proposition) -> Proposition: def _get_name(info): return info.name if info.name else info.id arguments = [ Variable(_get_name(self.entity_infos[var.name]), var.type) for var in fact.arguments ] return Proposition(fact.name, arguments)
def test_automatically_positioning_rooms(): P = Variable("P") r1 = Variable("Room1", "r") r2 = Variable("Room2", "r") d = Variable("door", "d") facts = [Proposition("at", [P, r1])] world = World.from_facts(facts) assert len(world.rooms) == 1 assert len(world.find_room_by_id(r1.name).exits) == 0 world.add_fact(Proposition("link", [r1, d, r2])) assert len(world.rooms) == 2 r1_entity = world.find_room_by_id(r1.name) r2_entity = world.find_room_by_id(r2.name) assert len(r1_entity.exits) == 1 assert len(r2_entity.exits) == 1 assert list(r1_entity.exits.keys())[0] == reverse_direction(list(r2_entity.exits.keys())[0])
def test_type_hierarchy(): assert list(a.ancestors) == [] assert list(a.supertypes) == [a] assert list(a.descendants) == [b, c, d] assert list(a.subtypes) == [a, b, c, d] assert list(b.ancestors) == [a] assert list(b.supertypes) == [b, a] assert list(b.descendants) == [d] assert list(b.subtypes) == [b, d] assert list(c.ancestors) == [a] assert list(c.supertypes) == [c, a] assert list(c.descendants) == [d] assert list(c.subtypes) == [c, d] assert list(d.ancestors) == [b, c, a] assert list(d.supertypes) == [d, b, c, a] assert list(d.descendants) == [] assert list(d.subtypes) == [d] va = Variable.parse("a") assert va.is_a(a) assert not va.is_a(b) assert not va.is_a(c) assert not va.is_a(d) vb = Variable.parse("b") assert vb.is_a(a) assert vb.is_a(b) assert not vb.is_a(c) assert not vb.is_a(d) vc = Variable.parse("c") assert vc.is_a(a) assert not vc.is_a(b) assert vc.is_a(c) assert not vc.is_a(d) vd = Variable.parse("d") assert vd.is_a(a) assert vd.is_a(b) assert vd.is_a(c) assert vd.is_a(d)
def test_backward_chaining(): P = Variable("P", "P") room = Variable("room", "r") kitchen = Variable("kitchen", "r") state = State(KnowledgeBase.default().logic, [ Proposition("at", [P, room]), Proposition("north_of", [kitchen, room]), Proposition("south_of", [room, kitchen]), ]) options = ChainingOptions() options.backward = True options.max_depth = 2 options.max_length = 2 options.subquests = True options.create_variables = True options.rules_per_depth = [ [ KnowledgeBase.default().rules["take/c"], KnowledgeBase.default().rules["take/s"] ], [KnowledgeBase.default().rules["open/c"]], ] options.restricted_types = {"d"} chains = list(get_chains(state, options)) assert len(chains) == 3 options = ChainingOptions() options.backward = True options.max_depth = 3 options.max_length = 3 options.subquests = True options.create_variables = True options.rules_per_depth = [ [KnowledgeBase.default().rules["put"]], [KnowledgeBase.default().rules["go/north"]], [KnowledgeBase.default().rules["take/c"]], ] options.restricted_types = {"d"} chains = list(get_chains(state, options)) assert len(chains) == 3
def _atom2proposition(atom): if isinstance(atom, fast_downward.translate.pddl.conditions.Atom): if atom.predicate == "=": return None return Proposition( atom.predicate, [Variable(arg, name2type[arg]) for arg in atom.args]) elif isinstance(atom, fast_downward.translate.pddl.f_expression.Assign): if atom.fluent.symbol == "total-cost": return None #name = "{}_{}".format(atom.fluent.symbol, atom.expression.value) name = "{}".format(atom.expression.value) return Proposition( name, [Variable(arg, name2type[arg]) for arg in atom.fluent.args])
def test_mementos_memoization(): # Variable-free proposition. fact = Proposition("name") assert Proposition("name") is fact assert Proposition(name="name") is fact assert Proposition("name", []) is fact assert Proposition("name", arguments=[]) is fact assert Proposition(name="name", arguments=[]) is fact assert Proposition("name2") is not fact # General proposition. variables = [Variable("var_1"), Variable("var_2")] fact2 = Proposition("name", variables) assert fact2 is not fact assert Proposition("name", variables) is fact2 assert Proposition("name", arguments=variables) is fact2 assert Proposition(name="name", arguments=variables) is fact2 assert Proposition("name2", variables) is not fact2 assert Proposition("name", variables[:1]) is not fact2 # Missing a variable. assert Proposition("name", variables[::-1]) is not fact2 # Variable are reversed. # Type-free signature. sig = Signature("name") assert Signature("name") is sig assert Signature("name", []) is sig assert Signature("name", types=[]) is sig assert Signature(name="name", types=[]) is sig # General signature. types = ["type_A", "type_B"] sig2 = Signature("name", types) assert sig2 is not sig assert Signature("name", types) is sig2 assert Signature("name", types=types) is sig2 assert Signature(name="name", types=types) is sig2 assert Signature("name", types[:1]) is not sig2 # Missing a variable. assert Signature("name", types[::-1]) is not sig2 # Variable are reversed.
def test_count(self): rng = np.random.RandomState(1234) types_counts = {t: rng.randint(2, 10) for t in self.types.variables} state = State() for t in self.types.variables: v = Variable(get_new(t, types_counts), t) state.add_fact(Proposition("dummy", [v])) counts = self.types.count(state) for t in self.types.variables: assert counts[t] == types_counts[t], (counts[t], types_counts[t])
def test_used_names_is_updated(verbose=False): # Make generation throughout the framework reproducible. g_rng.set_seed(1234) # Generate a map that's shape in a cross with room0 in the middle. P = Variable('P') r = Variable('r_0', 'r') k1 = Variable('k_1', 'k') k2 = Variable('k_2', 'k') c1 = Variable('c_1', 'c') c2 = Variable('c_2', 'c') facts = [ Proposition('at', [P, r]), Proposition('at', [k1, r]), Proposition('at', [k2, r]), Proposition('at', [c1, r]), Proposition('at', [c2, r]), Proposition('match', [k1, c1]), Proposition('match', [k2, c2]) ] world = World.from_facts(facts) world.set_player_room() # Set start room to the middle one. world.populate_room(10, world.player_room) # Add objects to the starting room. # Generate the world representation. grammar = textworld.generator.make_grammar({}, rng=np.random.RandomState(42)) game = textworld.generator.make_game_with(world, [], grammar) for entity_infos in game.infos.values(): if entity_infos.name is None: continue assert entity_infos.name in grammar.used_names
def maybe_instantiate_variables(rule, mapping, state, max_types_counts=None): types_counts = KnowledgeBase.default().types.count(state) # Instantiate variables if needed try: for ph in rule.placeholders: if mapping.get(ph) is None: name = get_new(ph.type, types_counts, max_types_counts) mapping[ph] = Variable(name, ph.type) except NotEnoughNounsError: return None return rule.instantiate(mapping)
def from_map(cls, map: networkx.Graph) -> "World": """ Args: map: Graph defining the structure of the world. """ world = cls() names = [ d.get("name", "r_{}".format(i)) for i, (n, d) in enumerate(map.nodes.items()) ] rooms = OrderedDict( (n, Variable(names[i], "r")) for i, n in enumerate(map.nodes())) world.add_facts(graph2state(map, rooms)) return world
def _update(self) -> None: """ Update the internal representation of the world. This method will create new entities based on facts. It should be called whenever backing facts are changed. """ self._entities = OrderedDict() # Clear entities. self.player = self._get_entity(Variable("P")) self.inventory = self._get_entity(Variable("I")) self._player_room = None self._process_rooms() self._process_objects() self._rooms = [ entity for entity in self._entities.values() if isinstance(entity, WorldRoom) ] self._objects = [ entity for entity in self._entities.values() if isinstance(entity, WorldObject) ] self._entities_per_type = defaultdict(list) for entity in self._entities.values(): self._entities_per_type[entity.type].append(entity)
def test_cannot_automatically_positioning_rooms(): P = Variable("P") r0 = Variable("Room0", "r") r1 = Variable("Room1", "r") r2 = Variable("Room2", "r") r3 = Variable("Room3", "r") r4 = Variable("Room4", "r") r5 = Variable("Room5", "r") d = Variable("door", "d") facts = [Proposition("at", [P, r0])] facts.extend(connect(r0, 'north', r1)) facts.extend(connect(r0, 'east', r2)) facts.extend(connect(r0, 'south', r3)) facts.extend(connect(r0, 'west', r4)) world = World.from_facts(facts) npt.assert_raises(NoFreeExitError, world.add_fact, Proposition("link", [r0, d, r5]))