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 test_win_action(self): g_rng.set_seed(2018) map_ = make_small_map(n_rooms=5, possible_door_states=["open"]) world = World.from_map(map_) for max_depth in range(1, 3): for rule in data.get_rules().values(): chain = sample_quest(world.state, rng=None, max_depth=max_depth, nb_retry=30, allow_partial_match=True, backward=True, rules_per_depth={0: [rule]}, exceptions=["r"]) assert len(chain) == max_depth, rule.name # Build the quest by providing the actions. actions = [c.action for c in chain] quest = Quest(actions) tmp_world = World.from_facts(chain[0].state.facts) state = tmp_world.state for action in actions: assert not state.is_applicable(quest.win_action) state.apply(action) assert state.is_applicable(quest.win_action) # Build the quest by only providing the winning conditions. quest = Quest(actions=None, winning_conditions=actions[-1].postconditions) tmp_world = World.from_facts(chain[0].state.facts) state = tmp_world.state for action in actions: assert not state.is_applicable(quest.win_action) state.apply(action) assert state.is_applicable(quest.win_action)
def test_generating_quests(self): g_rng.set_seed(2018) map_ = make_small_map(n_rooms=5, possible_door_states=["open"]) world = World.from_map(map_) def _rule_to_skip(rule): # Examine, look and inventory shouldn't be used for chaining. if rule.name.startswith("look"): return True if rule.name.startswith("inventory"): return True if rule.name.startswith("examine"): return True return False for max_depth in range(1, 3): for rule in KnowledgeBase.default().rules.values(): if _rule_to_skip(rule): continue options = ChainingOptions() options.backward = True options.max_depth = max_depth options.max_length = max_depth options.create_variables = True options.rules_per_depth = [[rule]] options.restricted_types = {"r"} chain = sample_quest(world.state, options) # Build the quest by providing the actions. actions = chain.actions assert len(actions) == max_depth, rule.name quest = Quest(win_events=[Event(actions)]) tmp_world = World.from_facts(chain.initial_state.facts) state = tmp_world.state for action in actions: assert not quest.is_winning(state) state.apply(action) assert quest.is_winning(state) # Build the quest by only providing the winning conditions. quest = Quest( win_events=[Event(conditions=actions[-1].postconditions)]) tmp_world = World.from_facts(chain.initial_state.facts) state = tmp_world.state for action in actions: assert not quest.is_winning(state) state.apply(action) assert quest.is_winning(state)
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 test_quest_winning_condition(): g_rng.set_seed(2018) map_ = make_small_map(n_rooms=5, possible_door_states=["open"]) world = World.from_map(map_) def _rule_to_skip(rule): # Examine, look and inventory shouldn't be used for chaining. if rule.name.startswith("look"): return True if rule.name.startswith("inventory"): return True if rule.name.startswith("examine"): return True return False for rule in KnowledgeBase.default().rules.values(): if _rule_to_skip(rule): continue options = ChainingOptions() options.backward = True options.max_depth = 1 options.create_variables = True options.rules_per_depth = [[rule]] options.restricted_types = {"r"} chain = sample_quest(world.state, options) assert len(chain.actions) > 0, rule.name event = Event(chain.actions) quest = Quest(win_events=[event]) # Set the initial state required for the quest. tmp_world = World.from_facts(chain.initial_state.facts) game = make_game_with(tmp_world, [quest], make_grammar({})) if tmp_world.player_room is None: # Randomly place the player in the world since # the action doesn't care about where the player is. tmp_world.set_player_room() game_name = "test_quest_winning_condition_" + rule.name.replace( "/", "_") with make_temp_directory(prefix=game_name) as tmpdir: game_file = _compile_game(game, path=tmpdir) env = textworld.start(game_file) env.reset() game_state, _, done = env.step("look") assert not done assert not game_state.won game_state, _, done = env.step(event.commands[0]) assert done assert game_state.won
def visualize(world: Union[Game, State, GameState, World], interactive: bool = False): """ Show the current state of the world. :param world: Object representing a game state to be visualized. :param interactive: Whether or not to visualize the state in the browser. :return: Image object of the visualization. """ try: import webbrowser from textworld.render.serve import get_html_template except ImportError: raise ImportError( 'Visualization dependencies not installed. Try running `pip install textworld[vis]`' ) if isinstance(world, Game): game = world state = load_state(game.world, game.infos) state["objective"] = game.objective elif isinstance(world, GameState): state = load_state_from_game_state(game_state=world) elif isinstance(world, World): state = load_state(world) elif isinstance(world, State): state = world world = World.from_facts(state.facts) state = load_state(world) else: raise ValueError("Don't know how to visualize: {!r}".format(world)) state["command"] = "" state["history"] = "" html = get_html_template(game_state=json.dumps(state)) tmpdir = maybe_mkdir(pjoin(tempfile.gettempdir(), "textworld")) fh, filename = tempfile.mkstemp(suffix=".html", dir=tmpdir, text=True) url = 'file://' + filename with open(filename, 'w') as f: f.write(html) img_graph = take_screenshot(url, id="world") img_inventory = take_screenshot(url, id="inventory") image = concat_images( img_inventory, img_graph, ) if interactive: try: webbrowser.open(url) finally: return image return image
def test_win_action(self): g_rng.set_seed(2018) map_ = make_small_map(n_rooms=5, possible_door_states=["open"]) world = World.from_map(map_) for max_depth in range(1, 3): for rule in data.get_rules().values(): options = ChainingOptions() options.backward = True options.max_depth = max_depth options.create_variables = True options.rules_per_depth = [[rule]] options.restricted_types = {"r"} chain = sample_quest(world.state, options) # Build the quest by providing the actions. actions = chain.actions if len(actions) != max_depth: print(chain) assert len(actions) == max_depth, rule.name quest = Quest(actions) tmp_world = World.from_facts(chain.initial_state.facts) state = tmp_world.state for action in actions: assert not state.is_applicable(quest.win_action) state.apply(action) assert state.is_applicable(quest.win_action) # Build the quest by only providing the winning conditions. quest = Quest(actions=None, winning_conditions=actions[-1].postconditions) tmp_world = World.from_facts(chain.initial_state.facts) state = tmp_world.state for action in actions: assert not state.is_applicable(quest.win_action) state.apply(action) assert state.is_applicable(quest.win_action)
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 load_state_from_game_state(game_state: GlulxGameState, format: str = 'png', limit_player_view: bool = False) -> dict: """ Generates serialization of game state. :param game_state: The current game state to visualize. :param format: The graph output format (png, svg, pdf, ...) :param limit_player_view: Whether to limit the player's view. Default: False. :return: The graph generated from this World """ game_infos = game_state.game_infos game_infos["objective"] = game_state.objective last_action = game_state.action # Create a world from the current state's facts. world = World.from_facts(game_state.state.facts) return load_state(world, game_infos, last_action, format, limit_player_view)
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 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]))
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 visualize(world: Union[Game, State, GlulxGameState, World], interactive: bool = False): """ Show the current state of the world. :param world: Object representing a game state to be visualized. :param interactive: Whether or not to visualize the state in the browser. :return: Image object of the visualization. """ if isinstance(world, Game): game = world state = load_state(game.world, game.infos) state["objective"] = "" if len(game.quests) > 0: state["objective"] = game.quests[0].desc elif isinstance(world, GlulxGameState): state = load_state_from_game_state(game_state=world) elif isinstance(world, World): state = load_state(world) elif isinstance(world, State): state = world world = World.from_facts(state.facts) state = load_state(world) else: raise ValueError("Don't know how to visualize: {!r}".format(world)) state["command"] = "" state["history"] = "" html = textworld.render.serve.get_html_template( game_state=json.dumps(state)) tmpdir = maybe_mkdir(pjoin(tempfile.gettempdir(), "textworld")) fh, filename = tempfile.mkstemp(suffix=".html", dir=tmpdir, text=True) url = 'file://' + filename with open(filename, 'w') as f: f.write(html) image = take_screenshot(url) if interactive: try: webbrowser.open(url) finally: return image return image
def test_quest_winning_condition(): g_rng.set_seed(2018) map_ = make_small_map(n_rooms=5, possible_door_states=["open"]) world = World.from_map(map_) for rule in data.get_rules().values(): chain = sample_quest(world.state, rng=None, max_depth=1, nb_retry=20, allow_partial_match=True, backward=True, rules_per_depth={0: [rule]}, exceptions=["r"]) assert len(chain) > 0, rule.name quest = Quest([c.action for c in chain]) # Set the initial state required for the quest. tmp_world = World.from_facts(chain[0].state.facts) game = make_game_with(tmp_world, [quest], make_grammar({})) if tmp_world.player_room is None: # Randomly place the player in the world since # the action doesn't care about where the player is. tmp_world.set_player_room() game_name = "test_quest_winning_condition_" + rule.name.replace( "/", "_") with make_temp_directory(prefix=game_name) as tmpdir: game_file = compile_game(game, game_name, games_folder=tmpdir) env = textworld.start(game_file) env.reset() game_state, _, done = env.step("look") assert not done assert not game_state.has_won game_state, _, done = env.step(quest.commands[0]) assert done assert game_state.has_won
def test_quest_winning_condition(): g_rng.set_seed(2018) map_ = make_small_map(n_rooms=5, possible_door_states=["open"]) world = World.from_map(map_) for rule in data.get_rules().values(): options = ChainingOptions() options.backward = True options.max_depth = 1 options.create_variables = True options.rules_per_depth = [[rule]] options.restricted_types = {"r"} chain = sample_quest(world.state, options) assert len(chain.actions) > 0, rule.name quest = Quest(chain.actions) # Set the initial state required for the quest. tmp_world = World.from_facts(chain.initial_state.facts) game = make_game_with(tmp_world, [quest], make_grammar({})) if tmp_world.player_room is None: # Randomly place the player in the world since # the action doesn't care about where the player is. tmp_world.set_player_room() game_name = "test_quest_winning_condition_" + rule.name.replace( "/", "_") with make_temp_directory(prefix=game_name) as tmpdir: game_file = compile_game(game, game_name, games_folder=tmpdir) env = textworld.start(game_file) env.reset() game_state, _, done = env.step("look") assert not done assert not game_state.has_won game_state, _, done = env.step(quest.commands[0]) assert done assert game_state.has_won
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