def gen_source_for_map(self, src_room: WorldRoom) -> str: source = "" src_room_id = src_room.id for src_exit, dest_room in src_room.exits.items(): dest_room_id = dest_room.id if src_exit in src_room.doors: door = src_room.doors[src_exit] dest_exit = [ k for k, v in dest_room.doors.items() if v == door ][0] template = "{src_exit} of {src} and {dest_exit} of {dest} is a door called {door}.\n" source += template.format(src_exit=src_exit, src=src_room_id, dest_exit=dest_exit, dest=dest_room_id, door=door.name) else: sig = Signature("{}_of".format(src_exit), ["r", "r"]) _, template = self.kb.inform7_predicates[sig] mapping = {'r': dest_room_id, "r'": src_room_id} source += template.format(**mapping) + ".\n" return source
def query_for_important_facts( actions: List[Action], facts: Optional[List[Proposition]] = None, varinfos: Optional[Dict[str, EntityInfo]] = None ) -> Optional[List[Proposition]]: """ Queries the user, asking which facts are important. Args: actions: Actions used to determine or extract relevant facts. facts: All facts existing at the end of the game. Returns: The list of facts that are required to win; or `None` if `facts` was not provided; or `None` if the user cancels. """ if facts is None: # No facts to choose from. return None present_facts = set(facts) all_postconditions = set( flatten(a.postconditions for a in actions if a is not None)) relevant_facts = sorted(all_postconditions & present_facts) def _get_name(var): if varinfos is not None and var.name in varinfos: if varinfos[var.name].name is not None: return varinfos[var.name].name return var.type # set up boxes checkboxes = [] for fact in relevant_facts: signature = Signature(fact.name, [_get_name(var) for var in fact.arguments]) fact_str = str(signature) cb = urwid.CheckBox(fact_str) checkboxes.append(cb) # run quest_querier = UrwidQuestQuerier(checkboxes) loop = urwid.MainLoop(quest_querier, [('popbg', 'white', 'dark blue')], pop_ups=True) loop.run() if quest_querier.action_cancelled: return None # don't return, even if the user selected items else: checked_facts = list( compress(relevant_facts, [cb.state for cb in checkboxes])) return checked_facts
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 all_assignments(self, node: _Node, rules: Iterable[Rule]) -> Iterable[_PartialAction]: """ Compute all possible assignments for instantiating the given rules. """ state = node.state at_p_r = None r = Placeholder("r", "r") if r not in self.fixed_mapping: # To make chaining more efficient, we fix the mapping of `r` to the current room, # i.e. at(P, r). This works since the player can only be at one place at a time. signature = Signature("at", ["P", "r"]) facts = list(state.facts_with_signature(signature)) if len(facts) > 0: assert len( facts ) == 1, "There should only be one `at(P, r)` proposition." at_p_r = facts[0] def allow_partial(ph): count = len(state.variables_of_type(ph.type)) return self.options.check_new_variable(state, ph.type, count) assignments = [] for rule in rules: fixed_mapping = self.fixed_mapping.copy() if self.backward: rule = rule.inverse() fixed_mapping = self.get_fixed_mapping(rule, at_p_r) for mapping in state.all_assignments(rule, fixed_mapping, self.create_variables, allow_partial): assignments.append(_PartialAction(node, rule, mapping)) # Keep everything in a deterministic order return sorted(assignments)
def add_extra_door_facts(world, world_facts, local_facts=None, where_fact=None): # adds to world_facts additional facts about door directions # and also about exits and door directions relative to the player if local_facts is not None if local_facts is not None: assert where_fact is not None door_facts = world.state.facts_with_signature( Signature('link', ('r', 'd', 'r'))) if where_fact: the_player = where_fact.arguments[0] player_location = where_fact.arguments[1] else: the_player, player_location = None, None # redundant, suppress warnings # for room in world.rooms: # print(room) # for e, p in room.exits.items(): # print('\t', e, p) for df in door_facts: assert len(df.arguments) == 3 r0, door, r1 = df.arguments direction = find_link_direction(world, r1, r0) new_fact = Proposition("{}_of".format(direction), (door, r1)) world_facts.append(new_fact) if local_facts is not None and r1 == player_location: local_facts.append(new_fact) local_facts.append( Proposition("{}_of".format(direction), (door, the_player))) # if world.state.is_fact(Proposition('free', (player_location, r1))): # local_facts.append(Proposition("{}_of".format(direction), ( # the_player, # Variable("exit_{}".format(direction), 'e')))) if world.state.is_fact(Proposition('closed', [door])): closed_fact = Proposition('closed', [door]) if closed_fact not in local_facts: local_facts.append(closed_fact)
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 filter_observables(world_facts: List[Proposition], verbose=False, game=None): fixups = defaultdict(set) if not world_facts: return None world_facts = reconstitute_facts(world_facts) # print("WORLD FACTS:") for fact in world_facts: # print('\t', fact) for v in fact.arguments: # print('\t\t{}:{}'.format(v.name, v.type)) if not v.name: v_count = len(fixups[v.type]) assert v not in fixups[v.type] if v.type == 'P' or v.type == 'I' or v.type == 'RECIPE' or v.type == 'MEAL': v.name = v.type if v_count == 0: fixups[v.type].add(v) else: v.name = '~{}_{}'.format(v.type, v_count) fixups[v.type].add(v) world = World.from_facts(world_facts) world_state = world.state if 'P' in world_state._vars_by_type: players = world_state.variables_of_type('P') assert len(players) == 1 # for p in players: # player = p # else: # player = None where_sig = Signature('at', ('P', 'r')) where_am_i = world_state.facts_with_signature(where_sig) assert len(where_am_i) == 1 where_fact = list(where_am_i)[0] the_player = where_fact.arguments[0] player_location = where_fact.arguments[1] # if verbose: # print("WORLD FACTS:") # for fact in world_facts: # print('\t', fact) # # print_fact(game, fact) # if verbose: # print("VARIABLES:") # for v in world_state.variables: # print('\t\t{}:{}'.format(v.name, v.type)) print(where_fact, world.player_room) facts_in_scope = world.get_facts_in_scope() observable_facts = [] for fact in facts_in_scope: # print("***\t\t", fact) if is_observable_relation(fact.name): if fact != where_fact: observable_facts.append(fact) else: # consider the player's current location to be directly observable observable_facts.append(fact) else: pass for e in world.player_room.exits: if world.state.is_fact( Proposition( 'free', (world.player_room.exits[e], where_fact.arguments[1]))): observable_facts.append( Proposition( "{}_of".format(e), ( Variable("exit_{}".format(e), 'e'), world.player_room # the_player ))) # REFACTORING: the following is now handled within add_extra_door_facts() # else: # probably a closed door # door_facts = world.state.facts_with_signature(Signature('link', ('r', 'd', 'r'))) # for df in door_facts: # if df.arguments[0] == player_location: # the_door = df.arguments[1] # observable_facts.append(Proposition("{}_of".format(e), ( # the_player, # the_door # ))) # if world.state.is_fact(Proposition('closed', [the_door])): # observable_facts.append(Proposition('closed', [the_door])) add_extra_door_facts(world, world_facts, local_facts=observable_facts, where_fact=where_fact) if verbose: print("++WORLD FACTS++:") for fact in world_facts: prettyprint_fact(fact, game=game) return observable_facts, player_location