def test_making_a_custom_game(): with make_temp_directory(prefix="test_tw-make") as tmpdir: output_folder = pjoin(tmpdir, "gen_games") game_file = pjoin(output_folder, "game_1234.ulx") command = [ "tw-make", "custom", "--seed", "1234", "--output", game_file ] assert check_call(command) == 0 assert os.path.isdir(output_folder) assert os.path.isfile(game_file) # Solve the game using WalkthroughAgent. agent = tw_textlabs.agents.WalkthroughAgent() tw_textlabs.play(game_file, agent=agent, silent=True) with make_temp_directory(prefix="test_tw-make") as tmpdir: output_folder = pjoin(tmpdir, "gen_games") game_file = pjoin(output_folder, "game_1234") # Default extension is .ulx command = [ "tw-make", "custom", "--seed", "1234", "--output", game_file ] assert check_call(command) == 0 assert os.path.isdir(output_folder) assert os.path.isfile(game_file + ".ulx") # Solve the game using WalkthroughAgent. agent = tw_textlabs.agents.WalkthroughAgent() tw_textlabs.play(game_file + ".ulx", agent=agent, silent=True) with make_temp_directory(prefix="test_tw-make") as tmpdir: output_folder = pjoin(tmpdir, "gen_games", "") command = [ "tw-make", "custom", "--seed", "1234", "--output", output_folder ] assert check_call(command) == 0 assert os.path.isdir(output_folder) game_file = glob.glob(pjoin(output_folder, "*.ulx"))[0] # Solve the game using WalkthroughAgent. agent = tw_textlabs.agents.WalkthroughAgent() tw_textlabs.play(game_file, agent=agent, silent=True) with make_temp_directory(prefix="test_tw-make") as tmpdir: output_folder = pjoin(tmpdir, "gen_games") command = [ "tw-make", "custom", "--seed", "1234", "--output", output_folder ] assert check_call(command) == 0 assert os.path.isfile(output_folder + ".ulx") # Solve the game using WalkthroughAgent. agent = tw_textlabs.agents.WalkthroughAgent() tw_textlabs.play(output_folder + ".ulx", agent=agent, silent=True)
def test_quest_winning_condition_go(): M = tw_textlabs.GameMaker() # R1 -- R2 -- R3 R1 = M.new_room("West room") R2 = M.new_room("Center room") R3 = M.new_room("East room") M.set_player(R1) M.connect(R1.east, R2.west) M.connect(R2.east, R3.west) M.set_quest_from_commands(["go east", "go east"]) game = M.build() game_name = "test_quest_winning_condition_go" with make_temp_directory(prefix=game_name) as tmpdir: game_file = _compile_game(game, path=tmpdir) env = tw_textlabs.start(game_file) env.reset() game_state, _, done = env.step("go east") assert not done assert not game_state.has_won game_state, _, done = env.step("go east") assert done assert game_state.has_won
def test_make_lab_game_from_level(): seed = "3311063" level = 22 with make_temp_directory(prefix="test_tw-make-lab") as tmpdir: output_folder = pjoin(tmpdir, "gen_games") game_file = pjoin(output_folder, "challenge_game%d_%s.ulx" % (level, seed)) command = [ "tw-make-lab", "challenge", "--seed", seed, "--max_search_steps", "2000", "--output", game_file, "--challenge", "tw-lab_game-level%d" % (level) ] print(' '.join(command)) try: assert check_call(command) == 0 except CalledProcessError as e: print(e.output) assert os.path.isdir(output_folder) assert os.path.isfile(game_file) # Solve the game using WalkthroughAgent. print("Solving game") agent = tw_textlabs.agents.WalkthroughAgent() stats = tw_textlabs.play(game_file, agent=agent, silent=True) assert (stats['score'] == 1)
def test_make_custom_lab_game(): seed = "32423" with make_temp_directory(prefix="test_tw-make-lab") as tmpdir: output_folder = pjoin(tmpdir, "gen_games") game_file = pjoin(output_folder, "game_%s.ulx" % (seed)) command = [ "tw-make-lab", "custom", "--seed", seed, "--output", game_file, "--surface_mode", "medium", "--merge_serial_actions", "--merge_parallel_actions", "--max_quest_length", "13", "--max_search_steps", "2000", "--lab_config_path", str(fpath) ] print(' '.join(command)) try: assert check_call(command) == 0 except CalledProcessError as e: print(e.output) assert os.path.isdir(output_folder) assert os.path.isfile(game_file) # Solve the game using WalkthroughAgent. agent = tw_textlabs.agents.WalkthroughAgent() stats = tw_textlabs.play(game_file, agent=agent, silent=True) assert (stats['score'] == 1)
def test_html_viewer(): # Integration test for visualization service num_nodes = 3 num_items = 10 options = tw_textlabs.GameOptions() options.seeds = 1234 options.nb_rooms = num_nodes options.nb_objects = num_items options.quest_length = 3 options.grammar.theme = "house" options.grammar.include_adj = True game = tw_textlabs.generator.make_game(options) game_name = "test_html_viewer_wrapper" with make_temp_directory(prefix=game_name) as tmpdir: options.path = tmpdir game_file = compile_game(game, options) env = tw_textlabs.start(game_file) env = HtmlViewer(env, open_automatically=False, port=8080) env.reset() # Cause rendering to occur. # options.binary_location = "/bin/chromium" driver = get_webdriver() driver.get("http://127.0.0.1:8080") nodes = driver.find_elements_by_class_name("node") assert len(nodes) == num_nodes items = driver.find_elements_by_class_name("item") objects = [obj for obj in game.world.objects if obj.type != "I"] assert len(items) == len(objects) env.close() driver.close()
def test_playing_a_game(): with make_temp_directory(prefix="test_tw-play") as tmpdir: options = tw_textlabs.GameOptions() options.path = tmpdir options.nb_rooms = 5 options.nb_objects = 10 options.quest_length = 5 options.quest_breadth = 4 options.seeds = 1234 game_file, _ = tw_textlabs.make(options) command = [ "tw-play", "--max-steps", "100", "--mode", "random", game_file ] assert check_call(command) == 0 command = [ "tw-play", "--max-steps", "100", "--mode", "random-cmd", game_file ] assert check_call(command) == 0 command = [ "tw-play", "--max-steps", "100", "--mode", "walkthrough", game_file ] assert check_call(command) == 0
def test_missing_game_infos_file(): with make_temp_directory() as tmpdir: game_file = pjoin(tmpdir, "tmp.ulx") with open(game_file, "w"): pass # Empty file npt.assert_raises(MissingGameInfosError, tw_textlabs.start, game_file)
def new_event_using_commands(self, commands: List[str]) -> Event: """ Creates a new event using predefined text commands. This launches a `tw_textlabs.play` session to execute provided commands. Args: commands: Text commands. Returns: The resulting event. """ with make_temp_directory() as tmpdir: try: game_file = self.compile(pjoin(tmpdir, "record_event.ulx")) recorder = Recorder() agent = tw_textlabs.agents.WalkthroughAgent(commands) tw_textlabs.play(game_file, agent=agent, wrapper=recorder, silent=True) except tw_textlabs.agents.WalkthroughDone: pass # Quest is done. # Skip "None" actions. actions = [action for action in recorder.actions if action is not None] event = Event(actions=actions) return event
def test(self) -> None: """ Test the game being built. This launches a `tw_textlabs.play` session. """ with make_temp_directory() as tmpdir: game_file = self.compile(pjoin(tmpdir, "test_game.ulx")) tw_textlabs.play(game_file)
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 = tw_textlabs.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(event.commands[0]) assert done assert game_state.has_won
def test_take_all_and_variants(): M = tw_textlabs.GameMaker() # Empty room. room = M.new_room("room") M.set_player(room) game = M.build() game_name = "test_take_all_and_variants" with make_temp_directory(prefix=game_name) as tmpdir: game_file = _compile_game(game, path=tmpdir) env = tw_textlabs.start(game_file) env.reset() variants_to_test = itertools.product(["take", "get", "pick up"], ["all", "everything", "each"]) for command in variants_to_test: game_state, _, done = env.step(" ".join(command)) assert game_state.feedback.strip( ) == "You have to be more specific!" # Multiple objects to take. red_ball = M.new(type="o", name="red ball") blue_ball = M.new(type="o", name="blue ball") room.add(red_ball, blue_ball) game = M.build() game_name = "test_take_all_and_variants2" with make_temp_directory(prefix=game_name) as tmpdir: game_file = _compile_game(game, path=tmpdir) env = tw_textlabs.start(game_file) env.enable_extra_info("inventory") env.reset() game_state, _, done = env.step("take all ball") assert "red ball:" in game_state.feedback assert "blue ball:" in game_state.feedback assert "red ball" in game_state.inventory assert "blue ball" in game_state.inventory
def set_quest_from_commands(self, commands: List[str], ask_for_state: bool = False) -> Quest: """ Defines the game's quest using predefined text commands. This launches a `tw_textlabs.play` session. Args: commands: Text commands. ask_for_state: If true, the user will be asked to specify which set of facts of the final state are should be true in order to consider the quest as completed. Returns: The resulting quest. """ with make_temp_directory() as tmpdir: try: game_file = self.compile(pjoin(tmpdir, "record_quest.ulx")) recorder = Recorder() agent = tw_textlabs.agents.WalkthroughAgent(commands) tw_textlabs.play(game_file, agent=agent, wrapper=recorder, silent=True) except tw_textlabs.agents.WalkthroughDone: pass # Quest is done. # Skip "None" actions. actions = [action for action in recorder.actions if action is not None] # Ask the user which quests have important state, if this is set # (if not, we assume the last action contains all the relevant facts) winning_facts = None if ask_for_state and recorder.last_game_state is not None: winning_facts = [ user_query.query_for_important_facts( actions=recorder.actions, facts=recorder.last_game_state.state.facts, varinfos=self._working_game.infos) ] event = Event(actions=actions, conditions=winning_facts) self.quests = [Quest(win_events=[event])] # Calling build will generate the description for the quest. self.build() return self.quests[-1]
def make_and_play_game(level, lab_game_options): game = make_game_from_level(level, lab_game_options) if game: with make_temp_directory(prefix="test_tw-make") as tmpdir: output_folder = Path(tmpdir) / "gen_games" game_file = output_folder / ("%s.ulx" % (game.metadata["uuid"])) lab_game_options.path = game_file game_file = tw_textlabs.generator.compile_game( game, lab_game_options) # Solve the game using WalkthroughAgent. agent = tw_textlabs.agents.WalkthroughAgent() stats = tw_textlabs.play(game_file, agent=agent, silent=True) game.metadata.update({'quest_desc': game.main_quest.desc}) game.metadata.update(stats) return game
def test_making_game_is_reproducible_with_seed(): with make_temp_directory(prefix="test_render_wrapper") as tmpdir: options = tw_textlabs.GameOptions() options.path = tmpdir options.nb_rooms = 2 options.nb_objects = 20 options.quest_length = 3 options.quest_breadth = 3 options.seeds = 123 game_file1, game1 = tw_textlabs.make(options) options2 = options.copy() game_file2, game2 = tw_textlabs.make(options2) assert game_file1 == game_file2 assert game1 == game2 # Make sure they are not the same Python objects. assert id(game1) != id(game2)
def test_extract_entities(): with make_temp_directory(prefix="test_tw-extract") as tmpdir: options = tw_textlabs.GameOptions() options.path = tmpdir options.nb_rooms = 5 options.nb_objects = 10 options.quest_length = 5 options.quest_breadth = 4 options.seeds = 1234 game_file, _ = tw_textlabs.make(options) outfile = pjoin(tmpdir, "entities.txt") command = ["tw-extract", "entities", game_file, "--output", outfile] stdout = check_output(command).decode() assert os.path.isfile(outfile) nb_entities = len(open(outfile).readlines()) assert "Extracted {}".format(nb_entities) in stdout
def test_making_challenge_game(): with make_temp_directory(prefix="test_tw-challenge") as tmpdir: for challenge in tw_textlabs.challenges.CHALLENGES: env_id = "tw-{}-level1".format(challenge) output_folder = pjoin(tmpdir, "gen_games") game_file = pjoin(output_folder, env_id + ".ulx") command = [ "tw-make", "challenge", env_id, "--seed", "1234", "--output", game_file ] assert check_call(command) == 0 assert os.path.isdir(output_folder) assert os.path.isfile(game_file) # Solve the game using WalkthroughAgent. agent = tw_textlabs.agents.WalkthroughAgent() tw_textlabs.play(game_file, agent=agent, silent=True)
def test_sample_quests(): with make_temp_directory(prefix="test_sample_quests") as tmpdir: game_file = pjoin(tmpdir, "game.ulx") command = [ "tw-make", "custom", "--seed", "20181004", "--output", game_file ] check_output(command).decode() script = pjoin(SCRIPTS_PATH, "sample_quests.py") command = [ "python", script, "--nb-quests", "10", "--quest-length", "10", "--quest-breadth", "5", "--output", tmpdir, game_file ] stdout = check_output(command).decode() assert len(stdout) > 0 assert os.path.isfile(pjoin(tmpdir, "sample_world.png")) assert os.path.isfile(pjoin(tmpdir, "sample_tree.svg")) assert os.path.isfile(pjoin(tmpdir, "sample_graph.svg"))
def test_check_generated_game(): NB_GAMES = 3 script = pjoin(SCRIPTS_PATH, "check_generated_games.py") with make_temp_directory(prefix="test_check_generated_game") as tmpdir: for i in range(NB_GAMES): command = [ "tw-make", "custom", "--seed", str(i), "--output", tmpdir ] check_output(command).decode() game_files = [ pjoin(tmpdir, f) for f in os.listdir(tmpdir) if f.endswith(".ulx") ] assert len(game_files) == NB_GAMES command = ["python", script] + game_files stdout = check_output(command).decode() for file in game_files: assert "Testing " + file in stdout
def test_logger(): rng = np.random.RandomState(1234) game_logger = GameLogger() for _ in range(10): options = tw_textlabs.GameOptions() options.nb_rooms = 5 options.nb_objects = 10 options.quest_length = 3 options.quest_breadth = 3 options.seeds = rng.randint(65635) game = tw_textlabs.generator.make_game(options) game_logger.collect(game) with make_temp_directory(prefix="tw_textlabs_tests") as tests_folder: filename = pjoin(tests_folder, "game_logger.pkl") game_logger.save(filename) game_logger2 = GameLogger.load(filename) assert game_logger is not game_logger2 assert game_logger.stats() == game_logger2.stats()
def test_making_game_with_names_to_exclude(): g_rng.set_seed(42) with make_temp_directory(prefix="test_render_wrapper") as tmpdir: options = tw_textlabs.GameOptions() options.path = tmpdir options.nb_rooms = 2 options.nb_objects = 20 options.quest_length = 3 options.quest_breadth = 3 options.seeds = 123 game_file1, game1 = tw_textlabs.make(options) options2 = options.copy() game1_objects_names = [ info.name for info in game1.infos.values() if info.name is not None ] options2.grammar.names_to_exclude = game1_objects_names game_file2, game2 = tw_textlabs.make(options2) game2_objects_names = [ info.name for info in game2.infos.values() if info.name is not None ] assert len(set(game1_objects_names) & set(game2_objects_names)) == 0
def test_game_ended_when_no_quest(self): M = GameMaker() room = M.new_room() M.set_player(room) item = M.new(type="o") room.add(item) game = M.build() game_name = "test_game_ended_when_no_quest" with make_temp_directory(prefix=game_name) as tmpdir: options = tw_textlabs.GameOptions() options.path = tmpdir game_file = tw_textlabs.generator.compile_game(game, options) env = tw_textlabs.start(game_file) env.activate_state_tracking() game_state = env.reset() assert not game_state.game_ended game_state, _, done = env.step("look") assert not done assert not game_state.game_ended
def test_making_a_game(play_the_game=False): rng_map = np.random.RandomState(1234) map_ = tw_textlabs.generator.make_small_map(1, rng_map) world = World.from_map(map_) world.set_player_room() # First room generated (i.e. the only one). rng_objects = np.random.RandomState(123) nb_objects = 10 world.populate(nb_objects, rng=rng_objects) rng_quest = np.random.RandomState(124) quest = make_quest(world, quest_length=5, rng=rng_quest) # Define the grammar we'll use. rng_grammar = np.random.RandomState(1234) grammar_flags = { "theme": "house", "include_adj": False, "only_last_action": True, "blend_instructions": True, "blend_descriptions": True, "refer_by_name_only": True, "instruction_extension": [], } grammar = tw_textlabs.generator.make_grammar(grammar_flags, rng=rng_grammar) # Generate the world representation. game = tw_textlabs.generator.make_game_with(world, [quest], grammar) with make_temp_directory(prefix="test_render_wrapper") as tmpdir: options = tw_textlabs.GameOptions() options.path = tmpdir game_file = compile_game(game, options) if play_the_game: tw_textlabs.play(game_file)
def test_disambiguation_questions(): M = tw_textlabs.GameMaker() room = M.new_room("room") M.set_player(room) tasty_apple = M.new(type="o", name="tasty apple") tasty_orange = M.new(type="o", name="tasty orange") room.add(tasty_apple, tasty_orange) game = M.build() game_name = "test_names_disambiguation" with make_temp_directory(prefix=game_name) as tmpdir: game_file = _compile_game(game, path=tmpdir) env = tw_textlabs.start(game_file) env.enable_extra_info("description") env.enable_extra_info("inventory") game_state = env.reset() previous_inventory = game_state.inventory previous_description = game_state.description game_state, _, _ = env.step("take tasty") assert "?" in game_state.feedback # Disambiguation question. # When there is a question in Inform7, the next string sent to the game # will be considered as the answer. We now make sure that asking for # extra information like `description` or `inventory` before answering # the question works. assert game_state.description == previous_description assert game_state.inventory == previous_inventory # Now answering the question. game_state, _, _ = env.step("apple") assert "That's not a verb I recognise." not in game_state.feedback assert "tasty orange" not in game_state.inventory assert "tasty apple" in game_state.inventory assert "tasty apple" not in game_state.description
def test_playing_generated_games(): NB_GAMES = 10 rng = np.random.RandomState(1234) for i in range(NB_GAMES): # Sample game specs. world_size = rng.randint(1, 10) nb_objects = rng.randint(0, 20) quest_length = rng.randint(2, 5) quest_breadth = rng.randint(3, 7) game_seed = rng.randint(0, 65365) with make_temp_directory(prefix="test_play_generated_games") as tmpdir: options = tw_textlabs.GameOptions() options.path = tmpdir options.nb_rooms = world_size options.nb_objects = nb_objects options.quest_length = quest_length options.quest_breadth = quest_breadth options.seeds = game_seed game_file, game = tw_textlabs.make(options) # Solve the game using WalkthroughAgent. agent = tw_textlabs.agents.WalkthroughAgent() tw_textlabs.play(game_file, agent=agent, silent=True) # Play the game using RandomAgent and make sure we can always finish the # game by following the winning policy. env = tw_textlabs.start(game_file) agent = tw_textlabs.agents.RandomCommandAgent() agent.reset(env) env.compute_intermediate_reward() env.seed(4321) game_state = env.reset() max_steps = 100 reward = 0 done = False for step in range(max_steps): command = agent.act(game_state, reward, done) game_state, reward, done = env.step(command) if done: msg = "Finished before playing `max_steps` steps because of command '{}'.".format( command) if game_state.has_won: msg += " (winning)" assert game_state._game_progression.winning_policy is None if game_state.has_lost: msg += " (losing)" assert game_state._game_progression.winning_policy is None print(msg) break # Make sure the game can still be solved. winning_policy = game_state._game_progression.winning_policy assert len(winning_policy) > 0 assert game_state.state.is_sequence_applicable(winning_policy)
def test_names_disambiguation(): M = tw_textlabs.GameMaker() room = M.new_room("room") M.set_player(room) apple = M.new(type="o", name="apple") orange = M.new(type="o", name="orange") tasty_apple = M.new(type="o", name="tasty apple") tasty_orange = M.new(type="o", name="tasty orange") room.add(apple, orange, tasty_apple, tasty_orange) game = M.build() game_name = "test_names_disambiguation" with make_temp_directory(prefix=game_name) as tmpdir: game_file = _compile_game(game, path=tmpdir) env = tw_textlabs.start(game_file) env.enable_extra_info("description") env.enable_extra_info("inventory") env.reset() game_state, _, done = env.step("take tasty apple") assert "tasty apple" in game_state.inventory game_state, _, done = env.step("take tasty orange") assert "tasty orange" in game_state.inventory env.reset() game_state, _, done = env.step("take orange") assert "tasty orange" not in game_state.inventory assert "orange" in game_state.inventory game_state, _, done = env.step("take tasty") assert "?" in game_state.feedback # Disambiguation question. game_state, _, done = env.step("apple") assert "tasty orange" not in game_state.inventory assert "tasty apple" in game_state.inventory assert "tasty apple" not in game_state.description # Actions with two arguments. M = tw_textlabs.GameMaker() roomA = M.new_room("roomA") roomB = M.new_room("roomB") roomC = M.new_room("roomC") M.set_player(roomA) path = M.connect(roomA.east, roomB.west) gateway = M.new_door(path, name="gateway") path = M.connect(roomA.west, roomC.east) rectangular_gateway = M.new_door(path, name="rectangular gateway") keycard = M.new(type="k", name="keycard") rectangular_keycard = M.new(type="k", name="rectangular keycard") roomA.add(keycard, rectangular_keycard) M.add_fact("match", keycard, gateway) M.add_fact("match", rectangular_keycard, rectangular_gateway) M.add_fact("locked", gateway) M.add_fact("locked", rectangular_gateway) game = M.build() game_name = "test_names_disambiguation" with make_temp_directory(prefix=game_name) as tmpdir: game_file = _compile_game(game, path=tmpdir) env = tw_textlabs.start(game_file) env.enable_extra_info("description") env.enable_extra_info("inventory") env.reset() game_state, _, done = env.step("take keycard") assert "keycard" in game_state.inventory game_state, _, done = env.step( "take keycard") # Already in your inventory. assert "rectangular keycard" not in game_state.inventory game_state, _, done = env.step("take rectangular keycard") assert "rectangular keycard" in game_state.inventory game_state, _, done = env.step( "unlock gateway with rectangular keycard") assert "That doesn't seem to fit the lock." in game_state.command_feedback game_state, _, done = env.step("unlock gateway with keycard") game_state, _, done = env.step("open gateway") game_state, _, done = env.step("go east") assert "-= Roomb =-" in game_state.description game_state, _, done = env.step("go west") game_state, _, done = env.step( "unlock rectangular gateway with keycard") assert "That doesn't seem to fit the lock." in game_state.command_feedback game_state, _, done = env.step( "unlock rectangular gateway with rectangular keycard") game_state, _, done = env.step("open rectangular gateway") game_state, _, done = env.step("go west") assert "-= Roomc =-" in game_state.description # Test invariance of the order in which ambiguous object names are defined. # First define "type G safe" then a "safe". M = tw_textlabs.GameMaker() garage = M.new_room("garage") M.set_player(garage) key = M.new(type="k", name="key") typeG_safe = M.new(type="c", name="type G safe") safe = M.new(type="c", name="safe") safe.add(key) garage.add(safe, typeG_safe) M.add_fact("open", safe) game = M.build() game_name = "test_names_disambiguation" with make_temp_directory(prefix=game_name) as tmpdir: game_file = _compile_game(game, path=tmpdir) env = tw_textlabs.start(game_file) env.enable_extra_info("inventory") game_state = env.reset() game_state, _, done = env.step("take key from safe") assert "key" in game_state.inventory # First define "safe" then "type G safe". M = tw_textlabs.GameMaker() garage = M.new_room("garage") M.set_player(garage) key = M.new(type="k", name="key") safe = M.new(type="c", name="safe") typeG_safe = M.new(type="c", name="type G safe") safe.add(key) garage.add(safe, typeG_safe) M.add_fact("open", safe) game = M.build() game_name = "test_names_disambiguation" with make_temp_directory(prefix=game_name) as tmpdir: game_file = _compile_game(game, path=tmpdir) env = tw_textlabs.start(game_file) env.enable_extra_info("inventory") game_state = env.reset() game_state, _, done = env.step("take key from safe") assert "key" in game_state.inventory
def test_cannot_win_or_lose_a_quest_twice(): g_rng.set_seed(2018) M = tw_textlabs.GameMaker() # Create a 'bedroom' room. R1 = M.new_room("bedroom") R2 = M.new_room("kitchen") M.set_player(R1) path = M.connect(R1.east, R2.west) path.door = M.new(type='d', name='wooden door') path.door.add_property("open") carrot = M.new(type='f', name='carrot') lettuce = M.new(type='f', name='lettuce') M.inventory.add(carrot) M.inventory.add(lettuce) # Add a closed chest in R2. chest = M.new(type='c', name='chest') chest.add_property("open") R2.add(chest) # The goals event_carrot_in_closed_chest = Event(conditions={ M.new_fact("in", carrot, chest), M.new_fact("closed", chest) }) event_drop_carrot_R1 = Event(conditions={M.new_fact("at", carrot, R1)}) event_drop_carrot_R2 = Event(conditions={M.new_fact("at", carrot, R2)}) quest1 = Quest(win_events=[event_carrot_in_closed_chest], fail_events=[event_drop_carrot_R1, event_drop_carrot_R2]) event_lettuce_in_closed_chest = Event(conditions={ M.new_fact("in", lettuce, chest), M.new_fact("closed", chest) }) event_drop_lettuce_R1 = Event(conditions={M.new_fact("at", lettuce, R1)}) event_drop_lettuce_R2 = Event(conditions={M.new_fact("at", lettuce, R2)}) quest2 = Quest(win_events=[event_lettuce_in_closed_chest], fail_events=[event_drop_lettuce_R1, event_drop_lettuce_R2]) M.quests = [quest1, quest2] game = M.build() game_name = "test_cannot_win_or_lose_a_quest_twice" with make_temp_directory(prefix=game_name) as tmpdir: game_file = _compile_game(game, path=tmpdir) env = tw_textlabs.start(game_file) # Make sure we do not rely on the quest progression to # determine if the game was lost. assert not env._compute_intermediate_reward # Complete quest1 then fail it. env.reset() game_state, score, done = env.step("go east") assert score == 0 game_state, score, done = env.step("insert carrot into chest") assert score == 0 game_state, score, done = env.step("close chest") assert score == 1 assert not done game_state, score, done = env.step("open chest") # Re-completing quest1 doesn't award more points. game_state, score, done = env.step("close chest") assert score == 1 assert not done game_state, score, done = env.step("open chest") game_state, score, done = env.step("take carrot from chest") game_state, score, done = env.step("drop carrot") assert score == 1 assert not done # Then fail quest2. game_state, score, done = env.step("drop lettuce") assert done assert game_state.has_lost assert not game_state.has_won env.reset() game_state, score, done = env.step("go east") game_state, score, done = env.step("insert carrot into chest") game_state, score, done = env.step("insert lettuce into chest") game_state, score, done = env.step("close chest") assert score == 2 assert done assert not game_state.has_lost assert game_state.has_won
def test_quest_with_multiple_winning_and_losing_conditions(): g_rng.set_seed(2018) M = tw_textlabs.GameMaker() # Create a 'bedroom' room. R1 = M.new_room("bedroom") R2 = M.new_room("kitchen") M.set_player(R1) path = M.connect(R1.east, R2.west) path.door = M.new(type='d', name='wooden door') path.door.add_property("open") carrot = M.new(type='f', name='carrot') lettuce = M.new(type='f', name='lettuce') M.inventory.add(carrot) M.inventory.add(lettuce) # Add a closed chest in R2. chest = M.new(type='c', name='chest') chest.add_property("open") R2.add(chest) # The goal quest = Quest( win_events=[ Event(conditions={ M.new_fact("in", carrot, chest), M.new_fact("closed", chest) }), Event(conditions={M.new_fact("eaten", lettuce)}) ], fail_events=[ Event(conditions={ M.new_fact("in", lettuce, chest), M.new_fact("closed", chest) }), Event(conditions={M.new_fact("eaten", carrot)}) ]) M.quests = [quest] game = M.build() game_name = "test_quest_with_multiple_winning_and_losing_conditions" with make_temp_directory(prefix=game_name) as tmpdir: game_file = _compile_game(game, path=tmpdir) env = tw_textlabs.start(game_file) # Make sure we do not rely on the quest progression to # determine if the game was lost. assert not env._compute_intermediate_reward # Failing - 1 env.reset() game_state, _, done = env.step("eat carrot") assert done assert game_state.has_lost assert not game_state.has_won # Failing - 2 env.reset() game_state, _, done = env.step("go east") assert not done game_state, _, done = env.step("insert lettuce into chest") assert not done game_state, _, done = env.step("close chest") assert done assert game_state.has_lost assert not game_state.has_won # Failing - 1 env.reset() game_state, _, done = env.step("eat lettuce") assert done assert not game_state.has_lost assert game_state.has_won # Winning - 2 env.reset() game_state, _, done = env.step("go east") assert not done game_state, _, done = env.step("insert carrot into chest") assert not done game_state, _, done = env.step("close chest") assert done assert not game_state.has_lost assert game_state.has_won
mdesc = M.new_lab_entity('mdsc') lab.add(mdesc) quest_gen_options.ent_desc_map[mat.var.name].append(mdesc.var.name) # Add operations and their descriptors ent_type = 'tlq_op' n_max_descs = quest_gen_options.max_descs_per_ent[ent_type] ops = [M.new_tlq_op(dynamic_define=True) for i in range(n_ops)] for op in ops: lab.add(op) n_descs = quest_gen_options.quest_rng.randint(0, (n_max_descs + 1)) for j in range(n_descs): odesc = M.new_lab_entity('odsc') lab.add(odesc) quest_gen_options.ent_desc_map[op.var.name].append(odesc.var.name) #oven = M.new_lab_entity('sa', name='oven') #lab.add(oven) quest = M.generate_quest_surface_pair(quest_gen_options) game = M.build() pg = ProcessGraph() pg.from_tw_actions(quest.actions) pg.draw() with make_temp_directory(prefix="test_tw-make") as tmpdir: output_folder = Path(tmpdir) / "gen_games" game_file = Path(output_folder) / ("%s.ulx" % (lab_game_options.uuid)) game_file = tw_textlabs.generator.compile_game(game, lab_game_options) # Solve the game using WalkthroughAgent. # test_game_walkthrough_agent(game_file)
def compile_inform7_game(source: str, output: str, verbose: bool = False) -> None: with make_temp_directory(prefix="tmp_inform") as project_folder: filename, ext = os.path.splitext(output) story_filename = filename + ".ni" # Save story file. with open(story_filename, 'w') as f: f.write(source) # Create the file structure needed by Inform7. source_folder = pjoin(project_folder, "Source") build_folder = pjoin(project_folder, "Build") if not os.path.isdir(source_folder): os.makedirs(source_folder) shutil.copy(story_filename, pjoin(source_folder, "story.ni")) # Write mandatory uuid.txt file open(pjoin(project_folder, "uuid.txt"), 'w').close() # Build Inform7 -> Inform6 -> game INFORM_HOME = os.environ.get("INFORM_HOME", I7_DEFAULT_PATH) ni = pjoin(INFORM_HOME, "share", "inform7", "Compilers", "ni") i6 = pjoin(INFORM_HOME, "share", "inform7", "Compilers", "inform6") i7_internal = pjoin(INFORM_HOME, "share", "inform7", "Internal") # Compile story file. cmd = [ ni, "--internal", i7_internal, "--format={}".format(ext), "--project", project_folder ] if verbose: print("Running: {}".format(" ".join(cmd))) try: stdout = subprocess.check_output(cmd, stderr=subprocess.STDOUT) except subprocess.CalledProcessError as exc: msg = "" msg += "\n-== ni =-\nFAIL: {}\n{}========\n".format( exc.returncode, exc.output.decode()) msg += "*** Usually this means a compilation error.\n" if ext == ".z8": msg += "*** Maybe the game is too big for a .z8 file. Try using .ulx instead.\n" msg += "*** See {} for more information.\n".format(story_filename) raise CouldNotCompileGameError(msg) else: if verbose: print("-= ni =-\n{}========\n".format(stdout.decode())) # Compile inform6 code. i6_input_filename = pjoin(build_folder, "auto.inf") i6_options = "-" # i6_options += "k" # Debug file, maybe useful to extract vocab? if str2bool(os.environ.get("TEXTWORLD_I6_DEBUG", False)): i6_options += "D" # Debug mode, enables Inform7 testing commands. i6_options += "E2wS" i6_options += "G" if ext == ".ulx" else "v8" i6_options += "F0" # Use extra memory rather than temporary files. cmd = [i6, i6_options, i6_input_filename, output] if verbose: print("Running: {}".format(" ".join(cmd))) try: stdout = subprocess.check_output(cmd, stderr=subprocess.STDOUT) except subprocess.CalledProcessError as exc: msg = "" msg += "\n-= i6 =-\nFAIL: {}\n{}========\n".format( exc.returncode, exc.output.decode()) msg += "*** Usually this means a compilation error.\n" if ext == ".z8": msg += "*** Maybe the game is too big for a .z8 file. Try using .ulx instead.\n" msg += "*** See {} for more information.\n".format(story_filename) raise CouldNotCompileGameError(msg) else: if verbose: print("-= i6 =-\n{}========\n".format(stdout.decode()))