Beispiel #1
0
    def test_is_game_completed(self):
        game_progress = GameProgression(self.game)

        for action in self.quest.actions:
            assert not game_progress.done
            game_progress.update(action)

        assert game_progress.done
Beispiel #2
0
def _apply_command(command: str, game_progression: GameProgression, inform7: Inform7Game) -> None:
    """ Apply a text command to a game_progression object.
    """
    valid_commands = inform7.gen_commands_from_actions(game_progression.valid_actions)
    for action, cmd in zip(game_progression.valid_actions, valid_commands):
        if command == cmd:
            game_progression.update(action)
            return

    raise ValueError("Not a valid command: {}. Expected: {}".format(command, valid_commands))
Beispiel #3
0
    def test_winning_policy(self):
        # Test following the winning policy derived from the quests.
        game_progress = GameProgression(self.game)
        for action in game_progress.winning_policy:
            assert not game_progress.done
            game_progress.update(action)

        assert game_progress.done
        assert game_progress.completed
        assert not game_progress.failed
        assert game_progress.winning_policy is None
Beispiel #4
0
    def reset(self):
        self._prev_state = None
        self.state = GameState()
        self._game_progression = GameProgression(self._game, track_quests=True)
        self._last_action = None
        self._previous_winning_policy = None
        self._current_winning_policy = self._game_progression.winning_policy
        self._moves = 0

        self.state.raw = DEFAULT_OBSERVATION
        self.state.feedback = DEFAULT_OBSERVATION
        self._gather_infos()
        return self.state
Beispiel #5
0
    def reset(self):
        self._prev_state = None
        self.state = GameState()
        track_quests = (self.infos.intermediate_reward or self.infos.policy_commands)
        self._game_progression = GameProgression(self._game, track_quests=track_quests)
        self._last_action = None
        self._previous_winning_policy = None
        self._current_winning_policy = self._game_progression.winning_policy
        self._moves = 0

        self.state.raw = DEFAULT_OBSERVATION
        self.state.feedback = DEFAULT_OBSERVATION
        self._gather_infos()
        return self.state
Beispiel #6
0
    def reset(self):
        self.state = self._wrapped_env.reset()
        if not self.tracking:
            return self.state  # State tracking not needed.

        self._send('tw-trace-actions')  # Turn on print for Inform7 action events.
        track_quests = (self.infos.intermediate_reward or self.infos.policy_commands)
        self._game_progression = GameProgression(self._game, track_quests=track_quests)
        self._last_action = None
        self._previous_winning_policy = None
        self._current_winning_policy = self._game_progression.winning_policy
        self._moves = 0

        self._gather_infos()
        return self.state
    def init(self,
             output: str,
             game: Game,
             state_tracking: bool = False,
             compute_intermediate_reward: bool = False):
        """
        Initialize the game state and set tracking parameters.
        The tracking parameters, state_tracking and compute_intermediate_reward,
        are computationally expensive, so are disabled by default.

        :param output: Introduction text displayed when a game starts.
        :param game: The glulx game to run
        :param state_tracking: Whether to use state tracking
        :param compute_intermediate_reward: Whether to compute the intermediate reward
        """
        output = _strip_input_prompt_symbol(output)
        _, output = _detect_i7_events_debug_tags(output)
        self._extra_infos, output = _detect_extra_infos(output)

        super().init(output)
        self._game = game
        self._game_progression = GameProgression(game,
                                                 track_quests=state_tracking)
        self._inform7 = Inform7Game(game)
        self._state_tracking = state_tracking
        self._compute_intermediate_reward = compute_intermediate_reward and len(
            game.quests) > 0
        self._objective = game.objective
        self._score = 0
        self._max_score = self._game.max_score
Beispiel #8
0
    def test_game_without_a_quest(self):
        M = GameMaker()

        room = M.new_room()
        M.set_player(room)
        item = M.new(type="o")
        room.add(item)

        game = M.build()
        game_progress = GameProgression(game)
        assert not game_progress.done

        # Simulate action that doesn't change the world.
        action = game_progress.valid_actions[0]
        game_progress.update(action)
        assert not game_progress.done
Beispiel #9
0
    def test_game_with_infinite_max_score(self):
        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 golden statue from pedestal", "look", "drop statue"])

        game = M.build()
        assert game.max_score == np.inf

        inform7 = Inform7Game(game)
        game_progress = GameProgression(game)
        assert len(game_progress.quest_progressions) == len(game.quests)

        # Following the actions associated to the last quest actually corresponds
        # to solving the whole game.
        for action in game_progress.winning_policy:
            assert not game_progress.done
            game_progress.update(action)

        assert game_progress.done
        assert not game_progress.quest_progressions[
            0].completed  # Repeatable quests can never be completed.
        assert game_progress.quest_progressions[
            1].completed  # Mandatory quest.

        # Solve the game while completing the optional quests.
        game_progress = GameProgression(game)
        for command in [
                "take golden statue from pedestal", "look", "look",
                "drop golden statue"
        ]:
            _apply_command(command, game_progress, inform7)

        progressions = game_progress.quest_progressions
        assert not progressions[0].done  # Repeatable quests can never be done.
        assert progressions[
            0].nb_completions == 3  # They could have been completed a number of times, though.
        assert progressions[1].done
        assert game_progress.score == 30
Beispiel #10
0
    def test_completed(self):
        game = GameProgression(self.game)
        for action in self.eventA.actions + self.eventC.actions:
            assert not game.done
            game.update(action)

        assert not game.done
        remaining_actions = self.eventB.actions[1:]  # skipping "open door".
        assert game.winning_policy == remaining_actions

        for action in self.eventB.actions:
            assert not game.done
            game.update(action)

        assert game.done
        assert game.completed
        assert not game.failed
        assert game.winning_policy is None
Beispiel #11
0
    def test_cycle_in_winning_policy(self):
        M = GameMaker()

        # Create a map.
        # r0
        #  |
        # r1 -- r2
        #  |    |
        # r3 -- r4
        R0 = M.new_room("r0")
        R1 = M.new_room("r1")
        R2 = M.new_room("r2")
        R3 = M.new_room("r3")
        R4 = M.new_room("r4")
        M.set_player(R1)

        M.connect(R0.south, R1.north),
        M.connect(R1.east, R2.west),
        M.connect(R3.east, R4.west)
        M.connect(R1.south, R3.north)
        M.connect(R2.south, R4.north)

        carrot = M.new(type='f', name='carrot')
        R0.add(carrot)

        apple = M.new(type='f', name='apple')
        R2.add(apple)

        commands = ["go north", "take carrot"]
        M.set_quest_from_commands(commands)
        game = M.build()
        inform7 = Inform7Game(game)
        game_progression = GameProgression(game)

        _apply_command("go south", game_progression, inform7)
        expected_commands = ["go north"] + commands
        winning_commands = inform7.gen_commands_from_actions(
            game_progression.winning_policy)
        assert winning_commands == expected_commands, "{} != {}".format(
            winning_commands, expected_commands)

        _apply_command("go east", game_progression, inform7)
        _apply_command("go north", game_progression, inform7)
        expected_commands = ["go south", "go west", "go north"] + commands
        winning_commands = inform7.gen_commands_from_actions(
            game_progression.winning_policy)
        assert winning_commands == expected_commands, "{} != {}".format(
            winning_commands, expected_commands)

        _apply_command("go west", game_progression, inform7)  # Found shortcut
        expected_commands = commands
        winning_commands = inform7.gen_commands_from_actions(
            game_progression.winning_policy)
        assert winning_commands == expected_commands, "{} != {}".format(
            winning_commands, expected_commands)

        # Quest where player's has to pick up the carrot first.
        commands = [
            "go east", "take apple", "go west", "go north", "drop apple"
        ]

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

        _apply_command("go south", game_progression, inform7)
        expected_commands = ["go north"] + commands
        winning_commands = inform7.gen_commands_from_actions(
            game_progression.winning_policy)
        assert winning_commands == expected_commands, "{} != {}".format(
            winning_commands, expected_commands)

        _apply_command("go east", game_progression, inform7)
        expected_commands = ["go west", "go north"] + commands
        winning_commands = inform7.gen_commands_from_actions(
            game_progression.winning_policy)
        assert winning_commands == expected_commands, "{} != {}".format(
            winning_commands, expected_commands)

        _apply_command("go north", game_progression, inform7)  # Found shortcut
        expected_commands = commands[1:]
        winning_commands = inform7.gen_commands_from_actions(
            game_progression.winning_policy)
        assert winning_commands == expected_commands, "{} != {}".format(
            winning_commands, expected_commands)
Beispiel #12
0
class StateTracking(textworld.core.Wrapper):
    """
    Wrapper that enables state tracking for Inform7 games generated by TextWorld.
    """
    @property
    def tracking(self):
        return (self.infos.intermediate_reward or self.infos.policy_commands
                or self.infos.admissible_commands or self.infos.facts
                or self.infos.last_action)

    def load(self, gamefile: str) -> None:
        self._wrapped_env.load(gamefile)
        self._gamefile = os.path.splitext(gamefile)[0] + ".json"
        try:
            self._game = self._wrapped_env._game
        except AttributeError:
            if not os.path.isfile(self._gamefile):
                raise MissingGameInfosError(self)

            self._game = Game.load(self._gamefile)

        self._game_progression = None
        self._inform7 = Inform7Game(self._game)

    def _gather_infos(self):
        self.state["_game_progression"] = self._game_progression
        self.state["_facts"] = list(self._game_progression.state.facts)

        self.state["won"] = '*** The End ***' in self.state["feedback"]
        self.state["lost"] = '*** You lost! ***' in self.state["feedback"]

        self.state["_winning_policy"] = self._current_winning_policy
        if self.infos.policy_commands:
            self.state["policy_commands"] = []
            if self._current_winning_policy is not None:
                self.state[
                    "policy_commands"] = self._inform7.gen_commands_from_actions(
                        self._current_winning_policy)

        if self.infos.intermediate_reward:
            self.state["intermediate_reward"] = 0
            if self.state["won"]:
                # The last action led to winning the game.
                self.state["intermediate_reward"] = 1

            elif self.state["lost"]:
                # The last action led to losing the game.
                self.state["intermediate_reward"] = -1

            elif self._previous_winning_policy is None:
                self.state["intermediate_reward"] = 0

            else:
                diff = len(self._previous_winning_policy) - len(
                    self._current_winning_policy)
                self.state["intermediate_reward"] = int(diff > 0) - int(
                    diff < 0)  # Sign function.

        if self.infos.facts:
            self.state["facts"] = list(
                map(self._inform7.get_human_readable_fact,
                    self.state["_facts"]))

        self.state["_last_action"] = self._last_action
        if self.infos.last_action and self._last_action is not None:
            self.state[
                "last_action"] = self._inform7.get_human_readable_action(
                    self._last_action)

        self.state["_valid_actions"] = self._game_progression.valid_actions
        if self.infos.admissible_commands:
            all_valid_commands = self._inform7.gen_commands_from_actions(
                self._game_progression.valid_actions)
            # To guarantee the order from one execution to another, we sort the commands.
            # Remove any potential duplicate commands (they would lead to the same result anyway).
            self.state["admissible_commands"] = sorted(set(all_valid_commands))

        if self.infos.moves:
            self.state["moves"] = self._moves

    def _send(self, command: str) -> str:
        """ Send a command to the game without affecting the Environment's state. """
        return self.unwrapped._send(command)

    def reset(self):
        self.state = self._wrapped_env.reset()
        if not self.tracking:
            return self.state  # State tracking not needed.

        self._send(
            'tw-trace-actions')  # Turn on print for Inform7 action events.
        track_quests = (self.infos.intermediate_reward
                        or self.infos.policy_commands)
        self._game_progression = GameProgression(self._game,
                                                 track_quests=track_quests)
        self._last_action = None
        self._previous_winning_policy = None
        self._current_winning_policy = self._game_progression.winning_policy
        self._moves = 0

        self._gather_infos()
        return self.state

    def step(self, command: str):
        self.state, score, done = self._wrapped_env.step(command)
        if not self.tracking:
            return self.state, score, done  # State tracking not needed.

        # Detect what events just happened in the game.
        i7_events, self.state["feedback"] = _detect_i7_events_debug_tags(
            self.state["feedback"])

        if str2bool(os.environ.get("TEXTWORLD_DEBUG", False)):
            print("[DEBUG] Detected Inform7 events:\n{}\n".format(i7_events))

        self._previous_winning_policy = self._current_winning_policy
        for i7_event in i7_events:
            valid_actions = self._game_progression.valid_actions
            self._last_action = self._inform7.detect_action(
                i7_event, valid_actions)
            if self._last_action is not None:
                # An action that affects the state of the game.
                self._game_progression.update(self._last_action)
                self._current_winning_policy = self._game_progression.winning_policy
                self._moves += 1

        self._gather_infos()
        self.state["done"] = self.state["won"] or self.state["lost"]
        return self.state, score, self.state["done"]
Beispiel #13
0
class TextWorldEnv(textworld.Environment):
    """
    Environment for playing games by TextWorld.
    """

    def __init__(self, infos: Optional[EnvInfos] = None) -> None:
        """
        Arguments:
            infos: Information to be included in the game state. By
                   default, only the game's narrative is included.
        """
        super().__init__(infos)
        self._gamefile = None
        self._game = None
        self._inform7 = None
        self._last_action = None
        self._prev_state = None
        self._previous_winning_policy = None
        self._current_winning_policy = None
        self._moves = None
        self._game_progression = None

    def load(self, path: str) -> None:
        self._gamefile = path
        self._game = textworld.Game.load(self._gamefile)
        self._game_progression = None
        self._inform7 = Inform7Game(self._game)

    def _gather_infos(self):
        self.state["game"] = self._game
        self.state["command_templates"] = self._game.command_templates
        self.state["verbs"] = self._game.verbs
        self.state["entities"] = self._game.entity_names
        self.state["objective"] = self._game.objective
        self.state["max_score"] = self._game.max_score

        for k, v in self._game.metadata.items():
            self.state["extra.{}".format(k)] = v

        self.state["_game_progression"] = self._game_progression
        self.state["_facts"] = list(self._game_progression.state.facts)

        self.state["won"] = self._game_progression.completed
        self.state["lost"] = self._game_progression.failed

        self.state["_winning_policy"] = self._current_winning_policy
        if self.infos.policy_commands:
            self.state["policy_commands"] = []
            if self._game_progression.winning_policy is not None:
                self.state["policy_commands"] = self._inform7.gen_commands_from_actions(self._current_winning_policy)

        if self.infos.intermediate_reward:
            self.state["intermediate_reward"] = 0
            if self.state["won"]:
                # The last action led to winning the game.
                self.state["intermediate_reward"] = 1

            elif self.state["lost"]:
                # The last action led to losing the game.
                self.state["intermediate_reward"] = -1

            elif self._previous_winning_policy is None:
                self.state["intermediate_reward"] = 0

            else:
                diff = len(self._previous_winning_policy) - len(self._current_winning_policy)
                self.state["intermediate_reward"] = int(diff > 0) - int(diff < 0)  # Sign function.

        if self.infos.facts:
            self.state["facts"] = list(map(self._inform7.get_human_readable_fact, self.state["_facts"]))

        self.state["last_action"] = None
        self.state["_last_action"] = self._last_action
        if self.infos.last_action and self._last_action is not None:
            self.state["last_action"] = self._inform7.get_human_readable_action(self._last_action)

        self.state["_valid_actions"] = self._game_progression.valid_actions
        self.state["_valid_commands"] = self._inform7.gen_commands_from_actions(self._game_progression.valid_actions)
        # To guarantee the order from one execution to another, we sort the commands.
        # Remove any potential duplicate commands (they would lead to the same result anyway).
        self.state["admissible_commands"] = sorted(set(self.state["_valid_commands"]))

        if self.infos.moves:
            self.state["moves"] = self._moves

    def reset(self):
        self._prev_state = None
        self.state = GameState()
        track_quests = (self.infos.intermediate_reward or self.infos.policy_commands)
        self._game_progression = GameProgression(self._game, track_quests=track_quests)
        self._last_action = None
        self._previous_winning_policy = None
        self._current_winning_policy = self._game_progression.winning_policy
        self._moves = 0

        self.state.raw = DEFAULT_OBSERVATION
        self.state.feedback = DEFAULT_OBSERVATION
        self._gather_infos()
        return self.state

    def step(self, command: str):
        command = command.strip()
        self._prev_state = self.state

        self.state = GameState()
        self.state.last_command = command
        self.state.raw = DEFAULT_OBSERVATION
        self.state.feedback = DEFAULT_OBSERVATION
        self._previous_winning_policy = self._current_winning_policy

        self._last_action = None
        try:
            # Find the action corresponding to the command.
            idx = self._prev_state["_valid_commands"].index(command)
            self._last_action = self._game_progression.valid_actions[idx]
            # An action that affects the state of the game.
            self._game_progression.update(self._last_action)
            self._current_winning_policy = self._game_progression.winning_policy
            self._moves += 1
        except ValueError:
            self.state.feedback = "Invalid command."
            pass  # We assume nothing happened in the game.

        self._gather_infos()
        self.state["score"] = self._game_progression
        self.state["done"] = self.state["won"] or self.state["lost"]
        return self.state, self.state["score"], self.state["done"]

    def copy(self) -> "TextWorldEnv":
        """ Return a copy of this environment.

        It is safe to call `step` and `reset` on the copied environment.

        .. warning:: The `Game` and `Inform7Game` private objects are *soft* copies.
        """
        env = TextWorldEnv()

        # Copy core Environment's attributes.
        env.state = self.state.copy()
        env.infos = self.infos.copy()

        env._gamefile = self._gamefile
        env._game = self._game  # Reference
        env._inform7 = self._inform7  # Reference

        env._prev_state = self._prev_state.copy() if self._prev_state is not None else None
        env._last_action = self._last_action
        env._moves = self._moves
        if self._previous_winning_policy is not None:
            env._previous_winning_policy = tuple(self._previous_winning_policy)

        if self._current_winning_policy is not None:
            env._current_winning_policy = tuple(self._current_winning_policy)

        if self._game_progression is not None:
            env._game_progression = self._game_progression.copy()

        return env
Beispiel #14
0
    def test_cycle_in_winning_policy(cls):
        M = GameMaker()

        # Create a map.
        # r0
        #  |
        # r1 -- r2
        #  |    |
        # r3 -- r4
        R0 = M.new_room("r0")
        R1 = M.new_room("r1")
        R2 = M.new_room("r2")
        R3 = M.new_room("r3")
        R4 = M.new_room("r4")
        M.set_player(R1)

        M.connect(R0.south, R1.north),
        M.connect(R1.east, R2.west),
        M.connect(R3.east, R4.west)
        M.connect(R1.south, R3.north)
        M.connect(R2.south, R4.north)

        carrot = M.new(type='f', name='carrot')
        R0.add(carrot)

        apple = M.new(type='f', name='apple')
        R2.add(apple)

        commands = ["go north", "take carrot"]
        M.set_quest_from_commands(commands)
        game = M.build()
        game_progression = GameProgression(game)

        def _apply_command(command, game_progression):
            valid_commands = gen_commands_from_actions(game_progression.valid_actions, game.infos)

            for action, cmd in zip(game_progression.valid_actions, valid_commands):
                if command == cmd:
                    game_progression.update(action)
                    return

            raise ValueError("Not a valid command: {}. Expected: {}".format(command, valid_commands))

        _apply_command("go south", game_progression)
        expected_commands = ["go north"] + commands
        winning_commands = gen_commands_from_actions(game_progression.winning_policy, game.infos)
        assert winning_commands == expected_commands, "{} != {}".format(winning_commands, expected_commands)

        _apply_command("go east", game_progression)

        _apply_command("go north", game_progression)
        expected_commands = ["go south", "go west", "go north"] + commands
        winning_commands = gen_commands_from_actions(game_progression.winning_policy, game.infos)
        assert winning_commands == expected_commands, "{} != {}".format(winning_commands, expected_commands)

        _apply_command("go west", game_progression)  # Found shortcut
        expected_commands = commands
        winning_commands = gen_commands_from_actions(game_progression.winning_policy, game.infos)
        assert winning_commands == expected_commands, "{} != {}".format(winning_commands, expected_commands)

        # Quest where player's has to pick up the carrot first.
        commands = ["go east", "take apple", "go west", "go north", "drop apple"]
        M.set_quest_from_commands(commands)
        game = M.build()
        game_progression = GameProgression(game)

        _apply_command("go south", game_progression)
        expected_commands = ["go north"] + commands
        winning_commands = gen_commands_from_actions(game_progression.winning_policy, game.infos)
        assert winning_commands == expected_commands, "{} != {}".format(winning_commands, expected_commands)

        _apply_command("go east", game_progression)
        expected_commands = ["go west", "go north"] + commands
        winning_commands = gen_commands_from_actions(game_progression.winning_policy, game.infos)
        assert winning_commands == expected_commands, "{} != {}".format(winning_commands, expected_commands)

        _apply_command("go north", game_progression)  # Found shortcut
        expected_commands = commands[1:]
        winning_commands = gen_commands_from_actions(game_progression.winning_policy, game.infos)
        assert winning_commands == expected_commands, "{} != {}".format(winning_commands, expected_commands)
Beispiel #15
0
    def test_game_with_optional_and_repeatable_quests(self):
        M = textworld.GameMaker()
        museum = M.new_room("Museum")

        weak_statue = M.new(type="o", name="ivory statue")
        normal_statue = M.new(type="o", name="stone statue")
        strong_statue = M.new(type="o", name="granite statue")

        museum.add(weak_statue)
        museum.add(normal_statue)
        museum.add(strong_statue)

        M.set_player(museum)

        M.quests = [
            Quest(win_events=[
                Event(conditions=[M.new_fact('in', weak_statue, M.inventory)]),
            ],
                  reward=-10,
                  optional=True,
                  repeatable=True),
            Quest(win_events=[
                Event(
                    conditions=[M.new_fact('in', normal_statue, M.inventory)]),
            ],
                  reward=3,
                  optional=True),
            Quest(
                win_events=[
                    Event(conditions=[
                        M.new_fact('in', strong_statue, M.inventory)
                    ]),
                ],
                reward=5,
            )
        ]
        M.set_walkthrough(
            ["take ivory", "take stone", "drop ivory", "take granite"])
        game = M.build()

        inform7 = Inform7Game(game)
        game_progress = GameProgression(game)
        assert len(game_progress.quest_progressions) == len(game.quests)

        # Following the actions associated to the last quest actually corresponds
        # to solving the whole game.
        for action in game_progress.winning_policy:
            assert not game_progress.done
            game_progress.update(action)

        assert game_progress.done
        assert not game_progress.quest_progressions[
            0].completed  # Optional, negative quest.
        assert not game_progress.quest_progressions[
            1].completed  # Optional, positive quest.
        assert game_progress.quest_progressions[
            2].completed  # Mandatory quest.

        # Solve the game while completing the optional quests.
        game_progress = GameProgression(game)
        for command in [
                "take ivory statue", "look", "take stone statue",
                "drop ivory statue", "take granite statue"
        ]:
            _apply_command(command, game_progress, inform7)

        progressions = game_progress.quest_progressions
        assert not progressions[0].done  # Repeatable quests can never be done.
        assert progressions[
            0].nb_completions == 3  # They could have been completed a number of times, though.
        assert progressions[
            1].done  # The nonrepeatable-optional quest can be done.
        assert progressions[2].done

        assert game.max_score == 8
        assert game_progress.score == -22
Beispiel #16
0
    def test_game_with_multiple_quests(self):
        M = GameMaker()

        # The subgoals (needs to be executed in order).
        commands = [
            [
                "open wooden door", "go west", "take carrot", "go east",
                "drop carrot"
            ],
            # Now, the player is back in the kitchen and the wooden door is open.
            ["go west", "take lettuce", "go east", "drop lettuce"],
            # Now, the player is back in the kitchen, there are a carrot and a lettuce on the floor.
            [
                "take lettuce", "take carrot", "insert carrot into chest",
                "insert lettuce into chest", "close chest"
            ]
        ]

        # Create a 'bedroom' room.
        R1 = M.new_room("bedroom")
        R2 = M.new_room("kitchen")
        M.set_player(R2)

        path = M.connect(R1.east, R2.west)
        path.door = M.new(type='d', name='wooden door')
        path.door.add_property("closed")

        carrot = M.new(type='f', name='carrot')
        lettuce = M.new(type='f', name='lettuce')
        R1.add(carrot, lettuce)

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

        quest1 = M.new_quest_using_commands(commands[0])
        quest1.desc = "Fetch the carrot and drop it on the kitchen's ground."
        quest2 = M.new_quest_using_commands(commands[0] + commands[1])
        quest2.desc = "Fetch the lettuce and drop it on the kitchen's ground."
        quest3 = M.new_quest_using_commands(commands[0] + commands[1] +
                                            commands[2])
        winning_facts = [
            M.new_fact("in", lettuce, chest),
            M.new_fact("in", carrot, chest),
            M.new_fact("closed", chest)
        ]
        quest3.win_events[0].set_conditions(winning_facts)
        quest3.desc = "Put the lettuce and the carrot into the chest before closing it."

        M.quests = [quest1, quest2, quest3]
        assert len(M.quests) == len(commands)
        game = M.build()

        inform7 = Inform7Game(game)
        game_progress = GameProgression(game)
        assert len(game_progress.quest_progressions) == len(game.quests)

        # Following the actions associated to the last quest actually corresponds
        # to solving the whole game.
        for action in game_progress.winning_policy:
            assert not game_progress.done
            game_progress.update(action)

        assert game_progress.done
        assert all(quest_progression.done
                   for quest_progression in game_progress.quest_progressions)

        # Try solving the game by greedily taking the first action from the current winning policy.
        game_progress = GameProgression(game)
        while not game_progress.done:
            action = game_progress.winning_policy[0]
            game_progress.update(action)
            # print(action.name, [c.name for c in game_progress.winning_policy])

        # Try solving the second quest (i.e. bringing back the lettuce) first.
        game_progress = GameProgression(game)
        for command in [
                "open wooden door", "go west", "take lettuce", "go east",
                "drop lettuce"
        ]:
            _apply_command(command, game_progress, inform7)

        assert not game_progress.quest_progressions[0].done
        assert game_progress.quest_progressions[1].done

        for command in ["go west", "take carrot", "go east", "drop carrot"]:
            _apply_command(command, game_progress, inform7)

        assert game_progress.quest_progressions[0].done
        assert game_progress.quest_progressions[1].done

        for command in [
                "take lettuce", "take carrot", "insert carrot into chest",
                "insert lettuce into chest", "close chest"
        ]:
            _apply_command(command, game_progress, inform7)

        assert game_progress.done

        # Game is done whenever a quest has failed or is unfinishable.
        game_progress = GameProgression(game)

        for command in [
                "open wooden door", "go west", "take carrot", "eat carrot"
        ]:
            assert not game_progress.done
            _apply_command(command, game_progress, inform7)

        assert game_progress.done
Beispiel #17
0
def _apply_command(command: str, game_progression: GameProgression,
                   inform7: Inform7Game) -> None:
    """ Apply a text command to a game_progression object. """
    action = _find_action(command, game_progression.valid_actions, inform7)
    game_progression.update(action)
Beispiel #18
0
    def test_failed(self):
        game = GameProgression(self.game)
        action = self.eating_tomato.actions[0]
        game.update(action)
        assert not game.done
        assert not game.completed
        assert not game.failed
        assert game.winning_policy is not None

        game = GameProgression(self.game)
        action = self.eating_pepper.actions[0]
        game.update(action)
        assert not game.completed
        assert game.failed
        assert game.done
        assert game.winning_policy is None

        game = GameProgression(self.game)
        for action in self.eating_carrot.actions:
            assert not game.done
            game.update(action)

        assert game.done
        assert not game.completed
        assert game.failed
        assert game.winning_policy is None

        game = GameProgression(self.game)
        for action in self.eating_lettuce.actions:
            assert not game.done
            game.update(action)

        assert game.done
        assert not game.completed
        assert game.failed
        assert game.winning_policy is None

        # Completing QuestA but failing quest B.
        game = GameProgression(self.game)
        for action in self.eventA.actions:
            assert not game.done
            game.update(action)

        assert not game.done

        game = GameProgression(self.game)
        for action in self.eating_lettuce.actions:
            assert not game.done
            game.update(action)

        assert game.done
        assert not game.completed
        assert game.failed
        assert game.winning_policy is None