Beispiel #1
0
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 = textworld.agents.WalkthroughAgent()
        textworld.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 = textworld.agents.WalkthroughAgent()
        textworld.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 = textworld.agents.WalkthroughAgent()
        textworld.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 = textworld.agents.WalkthroughAgent()
        textworld.play(output_folder + ".ulx", agent=agent, silent=True)
Beispiel #2
0
    def test_registering_zmachine_game(self):
        with make_temp_directory() as tmpdir:
            options = textworld.GameOptions()
            options.path = tmpdir
            options.seeds = 1234
            options.file_ext = ".z8"
            gamefile, game = textworld.make(options)
            os.remove(gamefile.replace(
                ".z8", ".json"))  # Simulate an non-TextWorld Z-Machine game.
            env_options = EnvInfos(extras=["walkthrough"])

            env_id = textworld.gym.register_game(gamefile,
                                                 env_options,
                                                 name="test-zmachine")
            env = gym.make(env_id)
            obs, infos = env.reset()
            assert len(infos) == len(env_options)

            for cmd in game.metadata["walkthrough"]:
                obs, score, done, infos = env.step(cmd)

            assert done
            assert score == 1

            env.close()
Beispiel #3
0
def test_limit_wrapper():
    # Make a game for testing purposes.
    max_episode_steps = 7

    num_nodes = 3
    num_items = 10
    options = textworld.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 = textworld.generator.make_game(options)

    game_name = "test_limit_wrapper"
    with make_temp_directory(prefix=game_name) as tmpdir:
        options.path = tmpdir
        game_file = compile_game(game, options)

        env = textworld.start(game_file)
        env = Limit(env, max_episode_steps)
        state = env.reset()

        done = False
        assert state["moves"] == 0
        for no_step in range(1, max_episode_steps + 1):
            assert not done
            state, score, done = env.step("wait")
            assert state["moves"] == no_step

        assert done
Beispiel #4
0
def test_filter_wrapper():
    # Make a game for testing purposes.
    num_nodes = 3
    num_items = 10
    options = textworld.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 = textworld.generator.make_game(options)

    game_name = "test_filter_wrapper"
    with make_temp_directory(prefix=game_name) as tmpdir:
        options.path = tmpdir
        game_file = compile_game(game, options)

        env = textworld.start(game_file)
        env_options = EnvInfos()
        for attr in env_options.__slots__:
            if attr == "extras":
                continue  # Skip since it's not a boolean attribute.

            setattr(env_options, attr, True)

        assert len(env_options) == len(env_options.__slots__) - 1
        assert len(env_options) == len(env_options.basics)

        env = Filter(env, env_options)
        _, infos = env.reset()

        for attr in env_options.basics:
            assert attr in infos
Beispiel #5
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, textworld.start, game_file)
Beispiel #6
0
    def new_quest_using_commands(self, commands: List[str]) -> Quest:
        """ Creates a new quest using predefined text commands.

        This launches a `textworld.play` session to execute provided commands.

        Args:
            commands: Text commands.

        Returns:
            The resulting quest.
        """
        with make_temp_directory() as tmpdir:
            try:
                game_file = self.compile(pjoin(tmpdir, "record_quest.ulx"))
                recorder = Recorder()
                agent = textworld.agents.WalkthroughAgent(commands)
                textworld.play(game_file,
                               agent=agent,
                               wrapper=recorder,
                               silent=True)
            except textworld.agents.WalkthroughDone:
                pass  # Quest is done.

        # Skip "None" actions.
        actions = [action for action in recorder.actions if action is not None]
        return Quest(actions=actions)
Beispiel #7
0
    def new_event_using_commands(self, commands: List[str]) -> Event:
        """ Creates a new event using predefined text commands.

        This launches a `textworld.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 = textworld.agents.WalkthroughAgent(commands)
                textworld.play(game_file,
                               agent=agent,
                               wrappers=[recorder],
                               silent=True)
            except textworld.agents.WalkthroughDone:
                pass  # Quest is done.

        # Skip "None" actions.
        actions, commands = zip(*[(a, c)
                                  for a, c in zip(recorder.actions, commands)
                                  if a is not None])
        event = Event(actions=actions, commands=commands)
        return event
def test_making_game_with_names_to_exclude():
    g_rng.set_seed(42)

    with make_temp_directory(prefix="test_render_wrapper") as tmpdir:
        game_file1, game1 = textworld.make(2,
                                           20,
                                           3,
                                           3, {"names_to_exclude": []},
                                           seed=123,
                                           games_dir=tmpdir)

        game1_objects_names = [
            info.name for info in game1.infos.values() if info.name is not None
        ]
        game_file2, game2 = textworld.make(
            2,
            20,
            3,
            3, {"names_to_exclude": game1_objects_names},
            seed=123,
            games_dir=tmpdir)
        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
Beispiel #9
0
def test_record_quest_from_commands(play_the_game=False):
    M = GameMaker()

    # The goal
    commands = ["go east", "insert ball into chest"]

    # 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")

    ball = M.new(type='o', name='ball')
    M.inventory.add(ball)

    # Add a closed chest in R2.
    chest = M.new(type='c', name='chest')
    chest.add_property("open")
    R2.add(chest)

    M.set_quest_from_commands(commands)
    game = M.build()

    with make_temp_directory(
            prefix="test_record_quest_from_commands") as tmpdir:
        game_file = _compile_game(game, folder=tmpdir)

        if play_the_game:
            textworld.play(game_file)
        else:
            agent = textworld.agents.WalkthroughAgent(commands)
            textworld.play(game_file, agent=agent, silent=True)
Beispiel #10
0
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 = textworld.GameOptions()
            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 = textworld.make(options, path=tmpdir)

            # Solve the game using WalkthroughAgent.
            agent = textworld.agents.WalkthroughAgent()
            textworld.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 = textworld.start(game_file)

            agent = textworld.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 len(game_state._game_progression.winning_policy) == 0

                    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_making_a_game_without_a_quest(play_the_game=False):
    rng_map = np.random.RandomState(1234)
    map_ = textworld.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(1234)
    nb_objects = 10
    world.populate(nb_objects, rng=rng_objects)

    quests = []

    # 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 = textworld.generator.make_grammar(grammar_flags, rng=rng_grammar)

    # Generate the world representation.
    game = textworld.generator.make_game_with(world, quests, grammar)

    with make_temp_directory(prefix="test_render_wrapper") as tmpdir:
        options = textworld.GameOptions()
        options.path = tmpdir
        game_file = compile_game(game, options)

        if play_the_game:
            textworld.play(game_file)
Beispiel #12
0
def test_disambiguation_questions():
    M = textworld.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 = textworld.start(game_file, EnvInfos(description=True, inventory=True))

        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_batch_sync():
    batch_size = 5
    with make_temp_directory() as tmpdir:
        options = textworld.GameOptions()
        options.path = tmpdir
        options.seeds = 1234
        options.file_ext = ".ulx"
        gamefile1, game = textworld.make(options)
        options.file_ext = ".z8"
        gamefile2, game = textworld.make(options)

        env_options = EnvInfos(inventory=True, description=True,
                               admissible_commands=True,
                               extras=["walkthrough"])
        env_id = textworld.gym.register_games([gamefile1, gamefile2],
                                              request_infos=env_options,
                                              batch_size=batch_size,
                                              name="test-batch",
                                              asynchronous=False)
        env = gym.make(env_id)

        obs, infos = env.reset()
        assert len(obs) == batch_size
        assert len(set(obs)) == 1  # All the same game.
        assert len(infos) == len(env_options)
        for values in infos.values():
            assert len(values) == batch_size

        for cmds in infos.get("extra.walkthrough"):
            obs, scores, dones, infos = env.step(cmds)

        env.close()

        assert all(dones)
        assert all(score == 1 for score in scores)
Beispiel #14
0
def test_html_viewer():
    # Integration test for visualization service
    num_nodes = 3
    num_items = 10
    options = textworld.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 = textworld.generator.make_game(options)

    game_name = "test_html_viewer_wrapper"
    with make_temp_directory(prefix=game_name) as tmpdir:
        game_file = compile_game(game, path=tmpdir)

        env = textworld.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()
Beispiel #15
0
def test_quest_winning_condition_go():
    M = textworld.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, game_name, games_folder=tmpdir)

        env = textworld.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
Beispiel #16
0
def test_playing_a_game():
    for ext in [".ulx", ".z8"]:
        with make_temp_directory(prefix="test_tw-play") as tmpdir:
            options = textworld.GameOptions()
            options.file_ext = ext
            options.path = tmpdir
            options.nb_rooms = 5
            options.nb_objects = 10
            options.quest_length = 5
            options.quest_breadth = 2
            options.seeds = 1234
            game_file, _ = textworld.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
Beispiel #17
0
def test_names_disambiguation():
    M = textworld.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, game_name, games_folder=tmpdir)
        env = textworld.start(game_file)
        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
Beispiel #18
0
    def record_quest(self, ask_for_state: bool = False) -> Quest:
        """ Defines the game's quest by recording the commands.

        This launches a `textworld.play` session.

        Args:
            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:
            game_file = self.compile(pjoin(tmpdir, "record_quest"))
            recorder = Recorder()
            textworld.play(game_file, wrapper=recorder)

        # 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)

        self._quests = [Quest(actions=actions, winning_conditions=winning_facts)]
        # Calling build will generate the description for the quest.
        self.build()

        return self._quests[0]
Beispiel #19
0
def test_batch_env():
    batch_size = 4
    max_episode_steps = 13
    with make_temp_directory() as tmpdir:
        options = textworld.GameOptions()
        options.path = tmpdir
        options.seeds = 1234
        options.file_ext = ".ulx"
        game_file1, game1 = textworld.make(options)
        options.seeds = 4321
        options.file_ext = ".z8"
        game_file2, game2 = textworld.make(options)

        env_options = EnvInfos(inventory=True, description=True,
                               admissible_commands=True)
        env_id = textworld.gym.register_games([game_file1, game_file1, game_file2, game_file2],
                                              request_infos=env_options,
                                              batch_size=batch_size,
                                              max_episode_steps=max_episode_steps,
                                              name="test-auto-reset",
                                              asynchronous=True,
                                              auto_reset=True)
        env = gym.make(env_id)
        env.reset()
        # env.close()
        del env
        print("OKAY")
def test_batch():
    batch_size = 5
    with make_temp_directory() as tmpdir:
        options = textworld.GameOptions()
        options.path = tmpdir
        options.seeds = 1234
        gamefile, game = textworld.make(options)

        env_options = EnvInfos(inventory=True,
                               description=True,
                               admissible_commands=True)
        env_id = textworld.gym.register_games([gamefile],
                                              env_options,
                                              name="test-batch")
        env_id = textworld.gym.make_batch(env_id, batch_size)
        env = gym.make(env_id)

        obs, infos = env.reset()
        assert len(obs) == batch_size
        assert len(set(obs)) == 1  # All the same game.
        assert len(infos) == len(env_options)
        for values in infos.values():
            assert len(values) == batch_size

        for cmd in game.main_quest.commands:
            obs, scores, dones, infos = env.step([cmd] * batch_size)

        env.close()

        assert all(dones)
        assert all(score == 1 for score in scores)
Beispiel #21
0
def test_html_viewer():
    # Integration test for visualization service
    num_nodes = 3
    num_items = 10
    g_rng.set_seed(1234)
    grammar_flags = {"theme": "house", "include_adj": True}
    game = textworld.generator.make_game(world_size=num_nodes,
                                         nb_objects=num_items,
                                         quest_length=3,
                                         grammar_flags=grammar_flags)

    game_name = "test_html_viewer_wrapper"
    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 = 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()
Beispiel #22
0
def test_third_party():
    with make_temp_directory(prefix="test_tw-make_third_party") as tmpdir:
        challenge_py = pjoin(tmpdir, "my_challenge.py")
        with open(challenge_py, "w") as f:
            f.write(
                textwrap.dedent("""\
            import argparse
            from typing import Mapping, Optional

            import textworld
            from textworld.challenges import register

            from textworld import Game, GameOptions


            def build_argparser(parser=None):
                parser = parser or argparse.ArgumentParser()

                group = parser.add_argument_group('This challenge settings')
                group.add_argument("--nb-locations", required=True, type=int,
                                   help="Number of locations in the game.")

                return parser


            def make_game(settings: Mapping[str, str], options: Optional[GameOptions] = None) -> Game:
                options = options or GameOptions
                options.nb_rooms = settings["nb_locations"]
                game = textworld.generator.make_game(options)
                return game


            # Register this new challenge.
            register(name="my-challenge",
                    desc="Generate new challenge game",
                    make=make_game,
                    add_arguments=build_argparser)
            """))

        NB_LOCATIONS = 3

        output_folder = pjoin(tmpdir, "gen_games")
        game_file = pjoin(output_folder, "game_1234.ulx")
        command = [
            "tw-make", "--third-party", challenge_py, "my-challenge", "--seed",
            "1234", "--output", game_file, "--silent"
        ]
        try:
            check_call(command)
        except CalledProcessError as e:
            assert e.returncode == 2  # Missing the --nb-locations argument.
        else:
            assert False, "tw-make should have failed."

        command += ["--nb-locations", str(NB_LOCATIONS)]
        assert check_call(command) == 0

        game = textworld.Game.load(game_file.replace(".ulx", ".json"))
        assert len(game.world.rooms) == NB_LOCATIONS
Beispiel #23
0
    def test(self) -> None:
        """ Test the game being built.

        This launches a `textworld.play` session.
        """
        with make_temp_directory() as tmpdir:
            game_file = self.compile(pjoin(tmpdir, "test_game.ulx"))
            textworld.play(game_file)
    def test_missing_game_infos_file(self):
        with make_temp_directory() as tmpdir:
            for ext, env_class in [(".ulx", GitGlulxEnv), (".z8", JerichoEnv)]:
                gamefile = pjoin(tmpdir, "tmp" + ext)
                with open(gamefile, "w"):
                    pass  # Empty file

                env = TWInform7(env_class())
                npt.assert_raises(MissingGameInfosError, env.load, gamefile)
Beispiel #25
0
def test_extract_vocab_theme():
    with make_temp_directory(prefix="test_extract_vocab_theme") as tmpdir:
        outfile = pjoin(tmpdir, "vocab.txt")
        command = [
            "tw-extract", "vocab", "--theme", "house", "--output", outfile
        ]
        stdout = check_output(command).decode()
        assert os.path.isfile(outfile)
        assert int(re.findall(r"Found (\d+)", stdout)[0]) > 0
Beispiel #26
0
    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 `textworld.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 = textworld.agents.WalkthroughAgent(commands)
                textworld.play(game_file,
                               agent=agent,
                               wrappers=[recorder],
                               silent=True)
            except textworld.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)
            ]
        if len(commands) != len(actions):
            unrecognized_commands = [
                c for c, a in zip(commands, recorder.actions) if a is None
            ]
            raise QuestError(
                "Some of the actions were unrecognized: {}".format(
                    unrecognized_commands))

        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 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 test_game_with_infinite_max_score():
    M = textworld.GameMaker()
    museum = M.new_room("Museum")

    statue = M.new(type="o", name="golden statue")
    pedestal = M.new(type="s", name="pedestal")

    pedestal.add(statue)
    museum.add(pedestal)

    M.set_player(museum)

    M.quests = [
        Quest(win_events=[
            Event(conditions=[M.new_fact('in', statue, M.inventory)]),
        ],
              reward=10,
              optional=True,
              repeatable=True),
        Quest(win_events=[
            Event(conditions=[M.new_fact('at', statue, museum)]),
        ],
              reward=0)
    ]
    M.set_walkthrough(["take statue from pedestal", "look", "drop statue"])

    game = M.build()
    game_name = "test_game_with_infinite_max_score"
    with make_temp_directory(prefix=game_name) as tmpdir:
        game_file = _compile_game(game, path=tmpdir)
        env = textworld.start(game_file)
        state = env.reset()
        state.max_score == np.inf  # Score increases for each turn the player hold the statue.

        state, score, done = env.step("look")
        assert not done
        assert score == 0

        state, score, done = env.step("take statue")
        assert score == 10

        state, score, done = env.step("wait")
        assert score == 20

        state, score, done = env.step("score")
        assert score == 20
        assert "You have so far scored 20 points," in state.feedback

        state, score, done = env.step("wait")
        assert score == 30

        state, score, done = env.step("drop statue")
        assert done
        assert score == 30

        assert "a total of 30 points," in state.feedback
def test_play_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(1, 10)
        game_seed = rng.randint(0, 65365)
        grammar_flags = {}  # Default grammar.

        with make_temp_directory(prefix="test_play_generated_games") as tmpdir:
            game_file, game = textworld.make(world_size, nb_objects, quest_length, grammar_flags,
                                             seed=game_seed, games_dir=tmpdir)

            # Solve the game using WalkthroughAgent.
            agent = textworld.agents.WalkthroughAgent()
            textworld.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 = textworld.start(game_file)

            agent = textworld.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."
                    if game_state.has_won:
                        msg += " (winning)"
                        assert game_state._game_progression.winning_policy == []

                    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_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_depth = 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 = textworld.GameOptions()
            options.path = tmpdir
            options.nb_rooms = world_size
            options.nb_objects = nb_objects
            options.chaining.max_depth = quest_depth
            options.chaining.max_breadth = quest_breadth
            options.seeds = game_seed
            game_file, game = textworld.make(options)

            # Solve the game using WalkthroughAgent.
            agent = textworld.agents.WalkthroughAgent()
            textworld.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 = textworld.start(game_file)
            env.infos.policy_commands = True
            env.infos.game = True

            agent = textworld.agents.RandomCommandAgent()
            agent.reset(env)

            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:
                    assert game_state._winning_policy is None
                    game_state, reward, done = env.reset(), 0, False

                # Make sure the game can still be solved.
                winning_policy = game_state._winning_policy
                assert len(winning_policy) > 0
                assert game_state._game_progression.state.is_sequence_applicable(
                    winning_policy)