Exemplo n.º 1
0
    def test_win_action(self):
        g_rng.set_seed(2018)
        map_ = make_small_map(n_rooms=5, possible_door_states=["open"])
        world = World.from_map(map_)

        for max_depth in range(1, 3):
            for rule in data.get_rules().values():
                chain = sample_quest(world.state, rng=None, max_depth=max_depth,
                                     nb_retry=30, allow_partial_match=True, backward=True,
                                     rules_per_depth={0: [rule]}, exceptions=["r"])
                assert len(chain) == max_depth, rule.name

                # Build the quest by providing the actions.
                actions = [c.action for c in chain]
                quest = Quest(actions)
                tmp_world = World.from_facts(chain[0].state.facts)

                state = tmp_world.state
                for action in actions:
                    assert not state.is_applicable(quest.win_action)
                    state.apply(action)

                assert state.is_applicable(quest.win_action)

                # Build the quest by only providing the winning conditions.
                quest = Quest(actions=None, winning_conditions=actions[-1].postconditions)
                tmp_world = World.from_facts(chain[0].state.facts)

                state = tmp_world.state
                for action in actions:
                    assert not state.is_applicable(quest.win_action)
                    state.apply(action)

                assert state.is_applicable(quest.win_action)
Exemplo n.º 2
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
Exemplo n.º 3
0
    def setUpClass(cls):
        M = GameMaker()

        # 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)
        R1.add(lettuce)

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

        # The goals
        commands = [
            "open wooden door", "go west", "take carrot", "go east",
            "drop carrot"
        ]
        cls.eventA = M.new_event_using_commands(commands)

        commands = [
            "open wooden door", "go west", "take lettuce", "go east",
            "insert lettuce into chest"
        ]
        cls.eventB = M.new_event_using_commands(commands)

        cls.losing_eventA = Event(conditions={M.new_fact("eaten", carrot)})
        cls.losing_eventB = Event(conditions={M.new_fact("eaten", lettuce)})

        cls.questA = Quest(win_events=[cls.eventA],
                           fail_events=[cls.losing_eventA])
        cls.questB = Quest(win_events=[cls.eventB],
                           fail_events=[cls.losing_eventB])
        cls.questC = Quest(win_events=[],
                           fail_events=[cls.losing_eventA, cls.losing_eventB])

        commands = ["open wooden door", "go west", "take carrot", "eat carrot"]
        cls.eating_carrot = M.new_event_using_commands(commands)
        commands = [
            "open wooden door", "go west", "take lettuce", "eat lettuce"
        ]
        cls.eating_lettuce = M.new_event_using_commands(commands)
        commands = [
            "open wooden door", "go west", "take lettuce", "go east",
            "insert lettuce into chest"
        ]

        M.quests = [cls.questA, cls.questB, cls.questC]
        cls.game = M.build()
Exemplo n.º 4
0
def make_game(options: GameOptions) -> Game:
    """
    Make a game (map + objects + quest).

    Arguments:
        options:
            For customizing the game generation (see
            :py:class:`textworld.GameOptions <textworld.generator.game.GameOptions>`
            for the list of available options).

    Returns:
        Generated game.
    """
    rngs = options.rngs

    # Generate only the map for now (i.e. without any objects)
    world = make_world(options.nb_rooms, nb_objects=0, rngs=rngs)

    # Sample a quest.
    chaining_options = options.chaining.copy()
    # Go, examine, look and inventory shouldn't be used for chaining.
    exclude = ["go.*", "examine.*", "look.*", "inventory.*"]
    chaining_options.rules_per_depth = [
        options.kb.rules.get_matching(".*", exclude=exclude)
    ]
    chaining_options.backward = True
    chaining_options.create_variables = True
    chaining_options.rng = rngs['quest']
    chaining_options.restricted_types = {"r", "d"}
    chain = sample_quest(world.state, chaining_options)

    subquests = []
    for i in range(1, len(chain.nodes)):
        if chain.nodes[i].breadth != chain.nodes[i - 1].breadth:
            event = Event(chain.actions[:i])
            subquests.append(Quest(win_events=[event]))

    event = Event(chain.actions)
    subquests.append(Quest(win_events=[event]))

    # Set the initial state required for the quest.
    world.state = chain.initial_state

    # Add distractors objects (i.e. not related to the quest)
    world.populate(options.nb_objects, rng=rngs['objects'])

    grammar = make_grammar(options.grammar, rng=rngs['grammar'])
    game = make_game_with(world, subquests, grammar)
    game.change_grammar(grammar)
    game.metadata["uuid"] = options.uuid

    return game
Exemplo n.º 5
0
    def test_init(self):
        npt.assert_raises(UnderspecifiedQuestError, Quest)

        quest = Quest(win_events=[self.eventA, self.eventB])
        assert len(quest.fail_events) == 0

        quest = Quest(fail_events=[self.eventC, self.eventD])
        assert len(quest.win_events) == 0

        quest = Quest(win_events=[self.eventA],
                      fail_events=[self.eventC, self.eventD])

        assert len(quest.win_events) > 0
        assert len(quest.fail_events) > 0
Exemplo n.º 6
0
def build_test_game():
    M = 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')
    M.inventory.add(carrot)

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

    commands = ["go east", "insert carrot into chest"]
    quest1 = M.new_quest_using_commands(commands)
    quest1.reward = 2
    commands = ["go east", "insert carrot into chest", "close chest"]
    event = M.new_event_using_commands(commands)
    quest2 = Quest(win_events=[event])
    M.quests = [quest1, quest2]
    game = M.build()
    return game
Exemplo n.º 7
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]
Exemplo n.º 8
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)
Exemplo n.º 9
0
    def test_quest_creation(self):
        quest = Quest(self.quest.actions)
        assert quest.actions == self.quest.actions
        assert quest.win_action == self.quest.win_action
        assert quest.win_action.preconditions == self.quest.actions[-1].postconditions
        assert quest.fail_action is None

        quest = Quest(actions=None, winning_conditions=self.quest.actions[-1].postconditions)
        assert quest.actions is None
        assert quest.win_action == self.quest.win_action
        assert quest.fail_action is None

        npt.assert_raises(UnderspecifiedQuestError, Quest, actions=None, winning_conditions=None)

        quest = Quest(self.quest.actions, failing_conditions=self.failing_conditions)
        assert quest.fail_action == self.quest.fail_action
        assert quest.fail_action.preconditions == self.failing_conditions
Exemplo n.º 10
0
 def generate_quest(self, obj):
     quests = []
     locations = self.find_correct_locations(obj)
     assert len(locations) > 0
     conditions = [self.maker.new_fact(preposition_of(location), obj, location) for location in locations]
     events = [Event(conditions={c}) for c in conditions]
     place_quest = Quest(win_events=events, reward=self.config.reward)
     quests.append(place_quest)
     if self.config.intermediate_reward > 0:
         current_location = obj.parent
         if current_location == self.maker.inventory:
             return quests
         take_cond = self.maker.new_fact('in', obj, self.maker.inventory)
         events = [Event(conditions={take_cond})]
         take_quest = Quest(win_events=events, reward=int(self.config.intermediate_reward))
         quests.append(take_quest)
     return quests
Exemplo n.º 11
0
    def test_generating_quests(self):
        g_rng.set_seed(2018)
        map_ = make_small_map(n_rooms=5, possible_door_states=["open"])
        world = World.from_map(map_)

        def _rule_to_skip(rule):
            # Examine, look and inventory shouldn't be used for chaining.
            if rule.name.startswith("look"):
                return True

            if rule.name.startswith("inventory"):
                return True

            if rule.name.startswith("examine"):
                return True

            return False

        for max_depth in range(1, 3):
            for rule in KnowledgeBase.default().rules.values():
                if _rule_to_skip(rule):
                    continue

                options = ChainingOptions()
                options.backward = True
                options.max_depth = max_depth
                options.max_length = max_depth
                options.create_variables = True
                options.rules_per_depth = [[rule]]
                options.restricted_types = {"r"}
                chain = sample_quest(world.state, options)

                # Build the quest by providing the actions.
                actions = chain.actions
                assert len(actions) == max_depth, rule.name
                quest = Quest(win_events=[Event(actions)])
                tmp_world = World.from_facts(chain.initial_state.facts)

                state = tmp_world.state
                for action in actions:
                    assert not quest.is_winning(state)
                    state.apply(action)

                assert quest.is_winning(state)

                # Build the quest by only providing the winning conditions.
                quest = Quest(
                    win_events=[Event(conditions=actions[-1].postconditions)])
                tmp_world = World.from_facts(chain.initial_state.facts)

                state = tmp_world.state
                for action in actions:
                    assert not quest.is_winning(state)
                    state.apply(action)

                assert quest.is_winning(state)
Exemplo n.º 12
0
def generate_quest(maker, obj):
    locations = find_correct_locations(maker, obj)
    assert len(locations) > 0
    conditions = [
        maker.new_fact(preposition_of(location), obj, location)
        for location in locations
    ]
    events = [Event(conditions={c}) for c in conditions]
    return Quest(win_events=events)
Exemplo n.º 13
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]
Exemplo n.º 14
0
def build_and_compile_game(options: GameOptions):
    M = textworld.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')
    M.inventory.add(carrot)

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

    quest1_cmds = ["go east", "insert carrot into chest"]
    carrot_in_chest = M.new_event_using_commands(quest1_cmds)
    eating_carrot = Event(conditions={M.new_fact("eaten", carrot)})
    quest1 = Quest(win_events=[carrot_in_chest],
                   fail_events=[eating_carrot],
                   reward=2)

    quest2_cmds = quest1_cmds + ["close chest"]
    quest2_actions = M.new_event_using_commands(quest2_cmds).actions
    chest_closed_with_carrot = Event(conditions={
        M.new_fact("in", carrot, chest),
        M.new_fact("closed", chest)
    },
                                     actions=quest2_actions)

    quest2 = Quest(win_events=[chest_closed_with_carrot],
                   fail_events=[eating_carrot])

    M.quests = [quest1, quest2]
    M.set_walkthrough(quest2_cmds)
    game = M.build()
    game_file = _compile_test_game(game, options)
    return game, game_file
Exemplo n.º 15
0
def make_quest(world: Union[World, State],
               options: Optional[GameOptions] = None):
    state = getattr(world, "state", world)

    if options is None:
        options = GameOptions()

        # By default, exclude quests finishing with: go, examine, look and inventory.
        exclude = ["go.*", "examine.*", "look.*", "inventory.*"]
        options.chaining.rules_per_depth = [
            options.kb.rules.get_matching(".*", exclude=exclude)
        ]
        options.chaining.rng = options.rngs['quest']

    chains = []
    for _ in range(options.nb_parallel_quests):
        chain = sample_quest(state, options.chaining)
        if chain is None:
            msg = "No quest can be generated with the provided options."
            raise NoSuchQuestExistError(msg)

        chains.append(chain)
        state = chain.initial_state  # State might have changed, i.e. options.create_variable is True.

    if options.chaining.backward and hasattr(world, "state"):
        world.state = state

    quests = []
    actions = []
    for chain in reversed(chains):
        for i in range(1, len(chain.nodes)):
            actions.append(chain.actions[i - 1])
            if chain.nodes[i].breadth != chain.nodes[i - 1].breadth:
                event = Event(actions)
                quests.append(Quest(win_events=[event]))

        actions.append(chain.actions[-1])
        event = Event(actions)
        quests.append(Quest(win_events=[event]))

    return quests
Exemplo n.º 16
0
    def test_win_action(self):
        g_rng.set_seed(2018)
        map_ = make_small_map(n_rooms=5, possible_door_states=["open"])
        world = World.from_map(map_)

        for max_depth in range(1, 3):
            for rule in data.get_rules().values():
                options = ChainingOptions()
                options.backward = True
                options.max_depth = max_depth
                options.create_variables = True
                options.rules_per_depth = [[rule]]
                options.restricted_types = {"r"}
                chain = sample_quest(world.state, options)

                # Build the quest by providing the actions.
                actions = chain.actions
                if len(actions) != max_depth:
                    print(chain)
                assert len(actions) == max_depth, rule.name
                quest = Quest(actions)
                tmp_world = World.from_facts(chain.initial_state.facts)

                state = tmp_world.state
                for action in actions:
                    assert not state.is_applicable(quest.win_action)
                    state.apply(action)

                assert state.is_applicable(quest.win_action)

                # Build the quest by only providing the winning conditions.
                quest = Quest(actions=None,
                              winning_conditions=actions[-1].postconditions)
                tmp_world = World.from_facts(chain.initial_state.facts)

                state = tmp_world.state
                for action in actions:
                    assert not state.is_applicable(quest.win_action)
                    state.apply(action)

                assert state.is_applicable(quest.win_action)
Exemplo n.º 17
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.
        """
        event = self.new_event_using_commands(commands)
        return Quest(win_events=[event], commands=event.commands)
Exemplo n.º 18
0
def generate_text_from_grammar(game, grammar: Grammar):
    # Assign a specific room type and name to our rooms
    for room in game.world.rooms:
        # First, generate a unique roomtype and name from the grammar
        if game.infos[room.id].room_type is None and grammar.has_tag(
                "#room_type#"):
            game.infos[room.id].room_type = grammar.expand("#room_type#")

        assign_name_to_object(room, grammar, game.infos)

        # Next, assure objects contained in a room must have the same room type
        for obj in game.world.get_all_objects_in(room):
            if game.infos[obj.id].room_type is None:
                game.infos[obj.id].room_type = game.infos[room.id].room_type

    # Objects in inventory can be of any room type.
    for obj in game.world.get_objects_in_inventory():
        if game.infos[obj.id].room_type is None and grammar.has_tag(
                "#room_type#"):
            game.infos[obj.id].room_type = grammar.expand("#room_type#")

    # Assign name and description to objects.
    for obj in game.world.objects:
        if obj.type in ["I", "P"]:
            continue

        assign_name_to_object(obj, grammar, game.infos)
        assign_description_to_object(obj, grammar, game.infos)

    # Generate the room descriptions.
    for room in game.world.rooms:
        if game.infos[
                room.
                id].desc is None:  # Skip rooms which already have a description.
            game.infos[room.id].desc = assign_description_to_room(
                room, game, grammar)

    # Generate the instructions.
    for quest in game.quests:
        if quest.desc is None:  # Skip quests which already have a description.
            quest.desc = assign_description_to_quest(quest, game, grammar)

    if grammar.options.only_last_action and len(game.quests) > 1:
        main_quest = Quest(
            actions=[quest.actions[-1] for quest in game.quests])
        only_last_action_bkp = grammar.options.only_last_action
        grammar.options.only_last_action = False
        game.objective = assign_description_to_quest(main_quest, game, grammar)
        grammar.options.only_last_action = only_last_action_bkp

    return game
Exemplo n.º 19
0
def make_quest(world, quest_length, rng=None, rules_per_depth=(), backward=False):
    state = world
    if hasattr(world, "state"):
        state = world.state

    rng = g_rng.next() if rng is None else rng

    # Sample a quest according to quest_length.
    options = ChainingOptions()
    options.backward = backward
    options.max_depth = quest_length
    options.rng = rng
    options.rules_per_depth = rules_per_depth
    chain = sample_quest(state, options)
    return Quest(chain.actions)
Exemplo n.º 20
0
def make_game(world_size: int,
              nb_objects: int,
              quest_length: int,
              grammar_flags: Mapping = {},
              rngs: Optional[Dict[str, RandomState]] = None) -> Game:
    """
    Make a game (map + objects + quest).

    Arguments:
        world_size: Number of rooms in the world.
        nb_objects: Number of objects in the world.
        quest_length: Minimum nb. of actions the quest requires to be completed.
        grammar_flags: Options for the grammar.

    Returns:
        Generated game.
    """
    if rngs is None:
        rngs = {}
        rng = g_rng.next()
        rngs['rng_map'] = RandomState(rng.randint(65635))
        rngs['rng_objects'] = RandomState(rng.randint(65635))
        rngs['rng_quest'] = RandomState(rng.randint(65635))
        rngs['rng_grammar'] = RandomState(rng.randint(65635))

    # Generate only the map for now (i.e. without any objects)
    world = make_world(world_size, nb_objects=0, rngs=rngs)

    # Sample a quest according to quest_length.
    options = ChainingOptions()
    options.backward = True
    options.max_depth = quest_length
    options.create_variables = True
    options.rng = rngs['rng_quest']
    options.restricted_types = {"r", "d"}
    chain = sample_quest(world.state, options)
    quest = Quest(chain.actions)

    # Set the initial state required for the quest.
    world.state = chain.initial_state

    # Add distractors objects (i.e. not related to the quest)
    world.populate(nb_objects, rng=rngs['rng_objects'])

    grammar = make_grammar(grammar_flags, rng=rngs['rng_grammar'])
    game = make_game_with(world, [quest], grammar)
    return game
Exemplo n.º 21
0
def make_game(world_size: int,
              nb_objects: int,
              quest_length: int,
              grammar_flags: Mapping = {},
              rngs: Optional[Dict[str, RandomState]] = None) -> Game:
    """
    Make a game (map + objects + quest).

    Arguments:
        world_size: Number of rooms in the world.
        nb_objects: Number of objects in the world.
        quest_length: Minimum nb. of actions the quest requires to be completed.
        grammar_flags: Options for the grammar.

    Returns:
        Generated game.
    """
    if rngs is None:
        rngs = {}
        rng = g_rng.next()
        rngs['rng_map'] = RandomState(rng.randint(65635))
        rngs['rng_objects'] = RandomState(rng.randint(65635))
        rngs['rng_quest'] = RandomState(rng.randint(65635))
        rngs['rng_grammar'] = RandomState(rng.randint(65635))

    # Generate only the map for now (i.e. without any objects)
    world = make_world(world_size, nb_objects=0, rngs=rngs)

    # Sample a quest according to quest_length.
    chain = sample_quest(world.state,
                         rngs['rng_quest'],
                         max_depth=quest_length,
                         nb_retry=20,
                         allow_partial_match=True,
                         backward=True,
                         exceptions=["r"])
    quest = Quest([c.action for c in chain])

    # Set the initial state required for the quest.
    world.state = chain[0].state

    # Add distractors objects (i.e. not related to the quest)
    world.populate(nb_objects, rng=rngs['rng_objects'])

    grammar = make_grammar(grammar_flags, rng=rngs['rng_grammar'])
    game = make_game_with(world, [quest], grammar)
    return game
Exemplo n.º 22
0
def build_and_compile_playground_game():
    M = GameMaker()
    
    room_dr = M.new_room("Locker Room")
    room_mr = M.new_room("Meeting Room")
    room_fl = M.new_room("Field")
    team_mates = M.new(type='tm', name = "teammates")
    captain = M.new(type='tm3', name = "captain")
    room_dr.add(team_mates)
    room_mr.add(captain)
    corridor = M.connect(room_dr.east, room_mr.west)
    corridor1 = M.connect(room_mr.east, room_fl.west)
    #corridor2 = M.connect(room_fl.east, new_room.west)
    M.set_player(room_dr)

    team_mates_2 = M.new(type='tm2', name = "someone")
    room_dr.add(team_mates_2)

    game_gear = M.new(type='ap', name = "game gears")
    room_dr.add(game_gear)
    M.add_fact("not_equiped", game_gear)
    M.add_fact("not_participated", captain)
    M.add_fact("not_helped", team_mates)
    M.add_fact("not_disturbed", team_mates)
    M.add_fact("not_bully", team_mates)
    
    
    room_dr.infos.desc = "You are in the Locker room with your team mates. You will find your game gears here. Collect the game gears and wear them before the meeting. If you need help, ask help from others and be helpful to others as well. \n After your are done here, go to the meeting room."
    room_mr.infos.desc = "You are in the meeting room. A meeting is going to start to finalize the game plan. Join the meeting and try to share your thought."
    
    captain.infos.desc = "The meeting is leading by the captain. Please, Cooperate with him."
    
    failed_event_1 = Event(conditions={
        M.new_fact("not_equiped", game_gear),
        M.new_fact("at", M._entities['P'], room_mr)})
    
    failed_quest_1 = Quest(win_events=[],
                           fail_events=[failed_event_1])
    
    
    #M.quests = [failed_quest_1]
    game = M.build()
    game_file = _compile_test_game(game)
    return game, game_file
Exemplo n.º 23
0
    def set_quest_from_final_state(self, final_state: Collection[Proposition]) -> Quest:
        """ Defines the game's quest using a collection of facts.

        The quest will be considered as finished as soon as all the provided
        facts are true.

        Args:
            final_state: List of all facts that will have to be true for
                         the quest to be considered as completed.

        Returns:
            The resulting quest.
        """
        quest = Quest(actions=None, winning_conditions=final_state)
        self._quests = [quest]

        # Calling build will generate the description for the quest
        self.build()
        return self._quests[0]
Exemplo n.º 24
0
def make_quest(world,
               quest_length,
               rng=None,
               rules_per_depth={},
               backward=False):
    state = world
    if hasattr(world, "state"):
        state = world.state

    rng = g_rng.next() if rng is None else rng

    # Sample a quest according to quest_length.
    chain = sample_quest(state,
                         rng,
                         max_depth=quest_length,
                         nb_retry=20,
                         rules_per_depth=rules_per_depth,
                         backward=backward)
    quest = [c.action for c in chain]
    return Quest(quest)
Exemplo n.º 25
0
    def setUpClass(cls):
        M = GameMaker()

        room = M.new_room("room")
        M.set_player(room)

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

        chest = M.new(type='c', name='chest')
        chest.add_property("open")
        room.add(chest)

        # The goals
        commands = ["take carrot", "insert carrot into chest"]
        cls.eventA = M.new_event_using_commands(commands)

        commands = ["take lettuce", "insert lettuce into chest", "close chest"]
        event = M.new_event_using_commands(commands)
        cls.eventB = Event(actions=event.actions,
                           conditions={
                               M.new_fact("in", lettuce, chest),
                               M.new_fact("closed", chest)
                           })

        cls.fail_eventA = Event(conditions={M.new_fact("eaten", carrot)})
        cls.fail_eventB = Event(conditions={M.new_fact("eaten", lettuce)})

        cls.quest = Quest(win_events=[cls.eventA, cls.eventB],
                          fail_events=[cls.fail_eventA, cls.fail_eventB])

        commands = ["take carrot", "eat carrot"]
        cls.eating_carrot = M.new_event_using_commands(commands)
        commands = ["take lettuce", "eat lettuce"]
        cls.eating_lettuce = M.new_event_using_commands(commands)
        commands = ["take lettuce", "insert lettuce into chest"]

        M.quests = [cls.quest]
        cls.game = M.build()
Exemplo n.º 26
0
    def setUpClass(cls):
        M = GameMaker()

        # The goal
        commands = ["go east", "insert carrot 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")

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

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

        cls.eventA = M.new_event_using_commands(commands)
        cls.eventB = Event(conditions={
            M.new_fact("at", carrot, R1),
            M.new_fact("closed", path.door)
        })
        cls.eventC = Event(conditions={M.new_fact("eaten", carrot)})
        cls.eventD = Event(conditions={
            M.new_fact("closed", chest),
            M.new_fact("closed", path.door)
        })
        cls.quest = Quest(win_events=[cls.eventA, cls.eventB],
                          fail_events=[cls.eventC, cls.eventD],
                          reward=2)

        M.quests = [cls.quest]
        cls.game = M.build()
        cls.inform7 = Inform7Game(cls.game)
Exemplo n.º 27
0
    def set_quest_from_commands(self, commands: List[str]) -> Quest:
        """ Defines the game's quest using predefined text commands.

        This launches a `textworld.play` session.

        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,
                               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]

        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)
        self.quests = [Quest(win_events=[event])]

        # Calling build will generate the description for the quest.
        self.build()
        return self.quests[-1]
Exemplo n.º 28
0
    def record_quest(self) -> Quest:
        """ Defines the game's quest by recording the commands.

        This launches a `textworld.play` session.

        Returns:
            The resulting quest.
        """
        with make_temp_directory() as tmpdir:
            game_file = self.compile(pjoin(tmpdir, "record_quest.ulx"))
            recorder = Recorder()
            agent = textworld.agents.HumanAgent(autocompletion=True)
            textworld.play(game_file, agent=agent, wrappers=[recorder])

        # Skip "None" actions.
        actions = [action for action in recorder.actions if action is not None]

        # Assume the last action contains all the relevant facts about the winning condition.
        event = Event(actions=actions)
        self.quests.append(Quest(win_events=[event]))
        # Calling build will generate the description for the quest.
        self.build()
        return self.quests[-1]
Exemplo n.º 29
0
def make_game(settings: Mapping[str, str],
              options: Optional[GameOptions] = None) -> textworld.Game:
    """ Make a simple game.

    Arguments:
        settings: Difficulty settings (see notes).
        options:
            For customizing the game generation (see
            :py:class:`textworld.GameOptions <textworld.generator.game.GameOptions>`
            for the list of available options).

    Returns:
        Generated game.

    Notes:
        The settings that can be provided are:

        * rewards : The reward frequency: dense, balanced, or sparse.
        * goal : The description of the game's objective shown at the
          beginning of the game: detailed, bried, or none.
        * test : Whether this game should be drawn from the test
          distributions of games.
    """
    metadata = {}  # Collect infos for reproducibility.
    metadata["desc"] = "Simple game"
    metadata["seeds"] = options.seeds
    metadata["world_size"] = 6
    metadata["quest_length"] = None  # TBD

    rngs = options.rngs
    rng_map = rngs['map']
    rng_objects = rngs['objects']
    rng_grammar = rngs['grammar']
    rng_quest = rngs['quest']

    # Make the generation process reproducible.
    textworld.g_rng.set_seed(2018)

    M = textworld.GameMaker()
    M.grammar = textworld.generator.make_grammar(options.grammar,
                                                 rng=rng_grammar)

    # Start by building the layout of the world.
    bedroom = M.new_room("bedroom")
    kitchen = M.new_room("kitchen")
    livingroom = M.new_room("living room")
    bathroom = M.new_room("bathroom")
    backyard = M.new_room("backyard")
    garden = M.new_room("garden")

    # Connect rooms together.
    bedroom_kitchen = M.connect(bedroom.east, kitchen.west)
    kitchen_bathroom = M.connect(kitchen.north, bathroom.south)
    kitchen_livingroom = M.connect(kitchen.south, livingroom.north)
    kitchen_backyard = M.connect(kitchen.east, backyard.west)
    backyard_garden = M.connect(backyard.south, garden.north)

    # Add doors.
    bedroom_kitchen.door = M.new(type='d', name='wooden door')
    kitchen_backyard.door = M.new(type='d', name='screen door')

    kitchen_backyard.door.add_property("closed")

    # Design the bedroom.
    drawer = M.new(type='c', name='chest drawer')
    trunk = M.new(type='c', name='antique trunk')
    bed = M.new(type='s', name='king-size bed')
    bedroom.add(drawer, trunk, bed)

    # Close the trunk and drawer.
    trunk.add_property("closed")
    drawer.add_property("closed")

    # - The bedroom's door is locked
    bedroom_kitchen.door.add_property("locked")

    # Design the kitchen.
    counter = M.new(type='s', name='counter')
    stove = M.new(type='s', name='stove')
    kitchen_island = M.new(type='s', name='kitchen island')
    refrigerator = M.new(type='c', name='refrigerator')
    kitchen.add(counter, stove, kitchen_island, refrigerator)

    # - Add some food in the refrigerator.
    apple = M.new(type='f', name='apple')
    milk = M.new(type='f', name='milk')
    refrigerator.add(apple, milk)

    # Design the bathroom.
    toilet = M.new(type='c', name='toilet')
    sink = M.new(type='s', name='sink')
    bath = M.new(type='c', name='bath')
    bathroom.add(toilet, sink, bath)

    toothbrush = M.new(type='o', name='toothbrush')
    sink.add(toothbrush)
    soap_bar = M.new(type='o', name='soap bar')
    bath.add(soap_bar)

    # Design the living room.
    couch = M.new(type='s', name='couch')
    low_table = M.new(type='s', name='low table')
    tv = M.new(type='s', name='tv')
    livingroom.add(couch, low_table, tv)

    remote = M.new(type='o', name='remote')
    low_table.add(remote)
    bag_of_chips = M.new(type='f', name='half of a bag of chips')
    couch.add(bag_of_chips)

    # Design backyard.
    bbq = M.new(type='s', name='bbq')
    patio_table = M.new(type='s', name='patio table')
    chairs = M.new(type='s', name='set of chairs')
    backyard.add(bbq, patio_table, chairs)

    # Design garden.
    shovel = M.new(type='o', name='shovel')
    tomato = M.new(type='f', name='tomato plant')
    pepper = M.new(type='f', name='bell pepper')
    lettuce = M.new(type='f', name='lettuce')
    garden.add(shovel, tomato, pepper, lettuce)

    # Close all containers
    for container in M.findall(type='c'):
        container.add_property("closed")

    # Set uncooked property for to all food items.
    foods = M.findall(type='f')
    for food in foods:
        food.add_property("edible")

    food_names = [food.name for food in foods]

    # Shuffle the position of the food items.
    rng_quest.shuffle(food_names)

    for food, name in zip(foods, food_names):
        food.orig_name = food.name
        food.name = name

    # The player starts in the bedroom.
    M.set_player(bedroom)

    # Quest
    walkthrough = []

    # Part I - Escaping the room.
    # Generate the key that unlocks the bedroom door.
    bedroom_key = M.new(type='k', name='old key')
    M.add_fact("match", bedroom_key, bedroom_kitchen.door)

    # Decide where to hide the key.
    if rng_quest.rand() > 0.5:
        drawer.add(bedroom_key)
        walkthrough.append("open chest drawer")
        walkthrough.append("take old key from chest drawer")
        bedroom_key_holder = drawer
    else:
        trunk.add(bedroom_key)
        walkthrough.append("open antique trunk")
        walkthrough.append("take old key from antique trunk")
        bedroom_key_holder = trunk

    # Unlock the door, open it and leave the room.
    walkthrough.append("unlock wooden door with old key")
    walkthrough.append("open wooden door")
    walkthrough.append("go east")

    # Part II - Find food item.
    # 1. Randomly pick a food item to cook.
    food = rng_quest.choice(foods)

    if settings["test"]:
        TEST_FOODS = ["garlic", "kiwi", "carrot"]
        food.name = rng_quest.choice(TEST_FOODS)

    # Retrieve the food item and get back in the kitchen.
    # HACK: handcrafting the walkthrough.
    if food.orig_name in ["apple", "milk"]:
        rooms_to_visit = []
        doors_to_open = []
        walkthrough.append("open refrigerator")
        walkthrough.append("take {} from refrigerator".format(food.name))
    elif food.orig_name == "half of a bag of chips":
        rooms_to_visit = [livingroom]
        doors_to_open = []
        walkthrough.append("go south")
        walkthrough.append("take {} from couch".format(food.name))
        walkthrough.append("go north")
    elif food.orig_name in ["bell pepper", "lettuce", "tomato plant"]:
        rooms_to_visit = [backyard, garden]
        doors_to_open = [kitchen_backyard.door]
        walkthrough.append("open screen door")
        walkthrough.append("go east")
        walkthrough.append("go south")
        walkthrough.append("take {}".format(food.name))
        walkthrough.append("go north")
        walkthrough.append("go west")

    # Part II - Cooking the food item.
    walkthrough.append("put {} on stove".format(food.name))
    # walkthrough.append("cook {}".format(food.name))
    # walkthrough.append("eat {}".format(food.name))

    # 2. Determine the winning condition(s) of the subgoals.
    quests = []
    bedroom_key_holder

    if settings["rewards"] == "dense":
        # Finding the bedroom key and opening the bedroom door.
        # 1. Opening the container.
        quests.append(
            Quest(win_events=[
                Event(conditions={M.new_fact("open", bedroom_key_holder)})
            ]))

        # 2. Getting the key.
        quests.append(
            Quest(win_events=[
                Event(conditions={M.new_fact("in", bedroom_key, M.inventory)})
            ]))

        # 3. Unlocking the bedroom door.
        quests.append(
            Quest(win_events=[
                Event(conditions={M.new_fact("closed", bedroom_kitchen.door)})
            ]))

        # 4. Opening the bedroom door.
        quests.append(
            Quest(win_events=[
                Event(conditions={M.new_fact("open", bedroom_kitchen.door)})
            ]))

    if settings["rewards"] in ["dense", "balanced"]:
        # Escaping out of the bedroom.
        quests.append(
            Quest(win_events=[
                Event(conditions={M.new_fact("at", M.player, kitchen)})
            ]))

    if settings["rewards"] in ["dense", "balanced"]:
        # Opening doors.
        for door in doors_to_open:
            quests.append(
                Quest(
                    win_events=[Event(conditions={M.new_fact("open", door)})]))

    if settings["rewards"] == "dense":
        # Moving through places.
        for room in rooms_to_visit:
            quests.append(
                Quest(win_events=[
                    Event(conditions={M.new_fact("at", M.player, room)})
                ]))

    if settings["rewards"] in ["dense", "balanced"]:
        # Retrieving the food item.
        quests.append(
            Quest(win_events=[
                Event(conditions={M.new_fact("in", food, M.inventory)})
            ]))

    if settings["rewards"] in ["dense", "balanced"]:
        # Retrieving the food item.
        quests.append(
            Quest(win_events=[
                Event(conditions={M.new_fact("in", food, M.inventory)})
            ]))

    if settings["rewards"] in ["dense", "balanced", "sparse"]:
        # Putting the food on the stove.
        quests.append(
            Quest(
                win_events=[Event(
                    conditions={M.new_fact("on", food, stove)})]))

    # 3. Determine the losing condition(s) of the game.
    quests.append(
        Quest(fail_events=[Event(conditions={M.new_fact("eaten", food)})]))

    # Set the subquest(s).
    M.quests = quests

    # - Add a hint of what needs to be done in this game.
    objective = "The dinner is almost ready! It's only missing a grilled {}."
    objective = objective.format(food.name)
    note = M.new(type='o', name='note', desc=objective)
    kitchen_island.add(note)

    game = M.build()
    game.main_quest = M.new_quest_using_commands(walkthrough)
    game.change_grammar(game.grammar)

    if settings["goal"] == "detailed":
        # Use the detailed version of the objective.
        pass
    elif settings["goal"] == "brief":
        # Use a very high-level description of the objective.
        game.objective = objective
    elif settings["goal"] == "none":
        # No description of the objective.
        game.objective = ""

    game.metadata = metadata
    uuid = "tw-simple-r{rewards}+g{goal}+{dataset}-{flags}-{seeds}"
    uuid = uuid.format(rewards=str.title(settings["rewards"]),
                       goal=str.title(settings["goal"]),
                       dataset="test" if settings["test"] else "train",
                       flags=options.grammar.uuid,
                       seeds=encode_seeds(
                           [options.seeds[k] for k in sorted(options.seeds)]))
    game.metadata["uuid"] = uuid
    return game
Exemplo n.º 30
0
def make_game(mode: str, options: GameOptions) -> textworld.Game:
    """ Make a Treasure Hunter game.

    Arguments:
        mode: Mode for the game where

              * `'easy'`: rooms are all empty except where the two objects are
                placed. Also, connections between rooms have no door.
              * `'medium'`: adding closed doors and containers that might need
                to be open in order to find the object.
              * `'hard'`: adding locked doors and containers (necessary keys
                will in the inventory) that might need to be unlocked (and open)
                in order to find the object.
        options:
            For customizing the game generation (see
            :py:class:`textworld.GameOptions <textworld.generator.game.GameOptions>`
            for the list of available options).

    Returns:
        Generated game.
    """
    kb = KnowledgeBase.default()

    metadata = {}  # Collect infos for reproducibility.
    metadata["desc"] = "Treasure Hunter"
    metadata["mode"] = mode
    metadata["seeds"] = options.seeds
    metadata["world_size"] = options.nb_rooms
    metadata["quest_length"] = options.quest_length

    rngs = options.rngs
    rng_map = rngs['map']
    rng_objects = rngs['objects']
    rng_quest = rngs['quest']
    rng_grammar = rngs['grammar']

    modes = ["easy", "medium", "hard"]
    if mode == "easy":
        door_states = None
        n_distractors = 0
    elif mode == "medium":
        door_states = ["open", "closed"]
        n_distractors = 10
    elif mode == "hard":
        door_states = ["open", "closed", "locked"]
        n_distractors = 20

    # Generate map.
    map_ = textworld.generator.make_map(n_rooms=options.nb_rooms,
                                        rng=rng_map,
                                        possible_door_states=door_states)
    assert len(map_.nodes()) == options.nb_rooms

    world = World.from_map(map_)

    # Randomly place the player.
    starting_room = None
    if len(world.rooms) > 1:
        starting_room = rng_map.choice(world.rooms)

    world.set_player_room(starting_room)
    # Add object the player has to pick up.
    types_counts = kb.types.count(world.state)
    obj_type = kb.types.sample(parent_type='o',
                               rng=rng_objects,
                               include_parent=True)
    var_id = get_new(obj_type, types_counts)
    right_obj = Variable(var_id, obj_type)
    world.add_fact(Proposition("in", [right_obj, world.inventory]))

    # Add containers and supporters to the world.
    types_counts = kb.types.count(world.state)
    objects = []
    distractor_types = uniquify(['c', 's'] + kb.types.descendants('c') +
                                kb.types.descendants('s'))
    for i in range(n_distractors):
        obj_type = rng_objects.choice(distractor_types)
        var_id = get_new(obj_type,
                         types_counts)  # This update the types_counts.
        objects.append(Variable(var_id, obj_type))

    world.populate_with(objects, rng=rng_objects)

    # Add object the player should not pick up.
    types_counts = kb.types.count(world.state)
    obj_type = kb.types.sample(parent_type='o',
                               rng=rng_objects,
                               include_parent=True)
    var_id = get_new(obj_type, types_counts)
    wrong_obj = Variable(var_id, obj_type)
    # Place it anywhere in the world.
    world.populate_with([wrong_obj], rng=rng_objects)

    # Generate a quest that finishes by taking something (i.e. the right
    #  object since it's the only one in the inventory).
    options.chaining.rules_per_depth = [kb.rules.get_matching("take.*")]
    options.chaining.backward = True
    options.chaining.rng = rng_quest
    #options.chaining.restricted_types = exceptions
    #exceptions = ["r", "c", "s", "d"] if mode == "easy" else ["r"]
    chain = textworld.generator.sample_quest(world.state, options.chaining)

    # Add objects needed for the quest.
    world.state = chain.initial_state
    event = Event(chain.actions)
    quest = Quest(
        win_events=[event],
        fail_events=[
            Event(conditions={Proposition("in", [wrong_obj, world.inventory])})
        ])

    grammar = textworld.generator.make_grammar(options.grammar,
                                               rng=rng_grammar)
    game = textworld.generator.make_game_with(world, [quest], grammar)
    game.metadata = metadata
    mode_choice = modes.index(mode)
    uuid = "tw-treasure_hunter-{specs}-{grammar}-{seeds}"
    uuid = uuid.format(specs=encode_seeds(
        (mode_choice, options.nb_rooms, options.quest_length)),
                       grammar=options.grammar.uuid,
                       seeds=encode_seeds(
                           [options.seeds[k] for k in sorted(options.seeds)]))
    game.metadata["uuid"] = uuid
    return game