Example #1
0
def test_get_visible_objects_in():
    P = Variable("P")
    room = Variable("room", "r")
    chest = Variable("chest", "c")
    obj = Variable("obj", "o")

    # Closed chest.
    facts = [Proposition("at", [P, room]),
             Proposition("at", [chest, room]),
             Proposition("in", [obj, chest]),
             Proposition("closed", [chest])]

    world = World.from_facts(facts)
    objects = world.get_visible_objects_in(world.player_room)
    assert obj in world.objects
    assert obj not in objects

    # Open chest.
    facts = [Proposition("at", [P, room]),
             Proposition("at", [chest, room]),
             Proposition("in", [obj, chest]),
             Proposition("open", [chest])]

    world = World.from_facts(facts)
    objects = world.get_visible_objects_in(world.player_room)
    assert obj in world.objects
    assert obj in objects
Example #2
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)
Example #3
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)
Example #4
0
def test_used_names_is_updated(verbose=False):
    # Make generation throughout the framework reproducible.
    g_rng.set_seed(1234)

    # Generate a map that's shape in a cross with room0 in the middle.
    P = Variable('P')
    r = Variable('r_0', 'r')
    k1 = Variable('k_1', 'k')
    k2 = Variable('k_2', 'k')
    c1 = Variable('c_1', 'c')
    c2 = Variable('c_2', 'c')
    facts = [
        Proposition('at', [P, r]),
        Proposition('at', [k1, r]),
        Proposition('at', [k2, r]),
        Proposition('at', [c1, r]),
        Proposition('at', [c2, r]),
        Proposition('match', [k1, c1]),
        Proposition('match', [k2, c2])
    ]
    world = World.from_facts(facts)
    world.set_player_room()  # Set start room to the middle one.
    world.populate_room(10,
                        world.player_room)  # Add objects to the starting room.

    # Generate the world representation.
    grammar = textworld.generator.make_grammar({},
                                               rng=np.random.RandomState(42))

    game = textworld.generator.make_game_with(world, [], grammar)
    for entity_infos in game.infos.values():
        if entity_infos.name is None:
            continue

        assert entity_infos.name in grammar.used_names
def test_quest_winning_condition():
    g_rng.set_seed(2018)
    map_ = make_small_map(n_rooms=5, possible_door_states=["open"])
    world = World.from_map(map_)

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

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

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

        return False

    for rule in KnowledgeBase.default().rules.values():
        if _rule_to_skip(rule):
            continue

        options = ChainingOptions()
        options.backward = True
        options.max_depth = 1
        options.create_variables = True
        options.rules_per_depth = [[rule]]
        options.restricted_types = {"r"}
        chain = sample_quest(world.state, options)
        assert len(chain.actions) > 0, rule.name
        event = Event(chain.actions)
        quest = Quest(win_events=[event])

        # Set the initial state required for the quest.
        tmp_world = World.from_facts(chain.initial_state.facts)
        game = make_game_with(tmp_world, [quest], make_grammar({}))

        if tmp_world.player_room is None:
            # Randomly place the player in the world since
            # the action doesn't care about where the player is.
            tmp_world.set_player_room()

        game_name = "test_quest_winning_condition_" + rule.name.replace(
            "/", "_")
        with make_temp_directory(prefix=game_name) as tmpdir:
            game_file = _compile_game(game, path=tmpdir)

            env = textworld.start(game_file)
            env.reset()
            game_state, _, done = env.step("look")
            assert not done
            assert not game_state.won

            game_state, _, done = env.step(event.commands[0])
            assert done
            assert game_state.won
def visualize(world: Union[Game, State, GameState, World],
              interactive: bool = False):
    """
    Show the current state of the world.
    :param world: Object representing a game state to be visualized.
    :param interactive: Whether or not to visualize the state in the browser.
    :return: Image object of the visualization.
    """
    try:
        import webbrowser
        from textworld.render.serve import get_html_template
    except ImportError:
        raise ImportError(
            'Visualization dependencies not installed. Try running `pip install textworld[vis]`'
        )

    if isinstance(world, Game):
        game = world
        state = load_state(game.world, game.infos)
        state["objective"] = game.objective
    elif isinstance(world, GameState):
        state = load_state_from_game_state(game_state=world)
    elif isinstance(world, World):
        state = load_state(world)
    elif isinstance(world, State):
        state = world
        world = World.from_facts(state.facts)
        state = load_state(world)
    else:
        raise ValueError("Don't know how to visualize: {!r}".format(world))

    state["command"] = ""
    state["history"] = ""
    html = get_html_template(game_state=json.dumps(state))
    tmpdir = maybe_mkdir(pjoin(tempfile.gettempdir(), "textworld"))
    fh, filename = tempfile.mkstemp(suffix=".html", dir=tmpdir, text=True)
    url = 'file://' + filename
    with open(filename, 'w') as f:
        f.write(html)

    img_graph = take_screenshot(url, id="world")
    img_inventory = take_screenshot(url, id="inventory")
    image = concat_images(
        img_inventory,
        img_graph,
    )

    if interactive:
        try:
            webbrowser.open(url)
        finally:
            return image

    return image
Example #7
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)
Example #8
0
def test_get_objects_in_inventory():
    P = Variable("P")
    I = Variable("I")
    room = Variable("room", "r")
    obj = Variable("obj", "o")

    # Closed chest.
    facts = [Proposition("at", [P, room]),
             Proposition("in", [obj, I])]

    world = World.from_facts(facts)
    objects = world.get_objects_in_inventory()
    assert obj in world.objects
    assert obj in objects
Example #9
0
def load_state_from_game_state(game_state: GlulxGameState, format: str = 'png', limit_player_view: bool = False) -> dict:
    """
    Generates serialization of game state.

    :param game_state: The current game state to visualize.
    :param format: The graph output format (png, svg, pdf, ...)
    :param limit_player_view: Whether to limit the player's view. Default: False.
    :return: The graph generated from this World
    """
    game_infos = game_state.game_infos
    game_infos["objective"] = game_state.objective
    last_action = game_state.action
    # Create a world from the current state's facts.
    world = World.from_facts(game_state.state.facts)
    return load_state(world, game_infos, last_action, format, limit_player_view)
Example #10
0
def test_populate_with():
    # setup
    P = Variable('P')
    I = Variable('I')
    room = Variable('room', 'r')
    facts = [Proposition('at', [P, room])]

    world = World.from_facts(facts)

    # test
    obj = Variable('obj', 'o')
    world.populate_with(objects=[obj])

    assert obj in world.objects
    assert (Proposition('at', [obj, room]) in world.facts or Proposition('in', [obj, I]) in world.facts)
Example #11
0
def test_cannot_automatically_positioning_rooms():
    P = Variable("P")
    r0 = Variable("Room0", "r")
    r1 = Variable("Room1", "r")
    r2 = Variable("Room2", "r")
    r3 = Variable("Room3", "r")
    r4 = Variable("Room4", "r")
    r5 = Variable("Room5", "r")
    d = Variable("door", "d")

    facts = [Proposition("at", [P, r0])]
    facts.extend(connect(r0, 'north', r1))
    facts.extend(connect(r0, 'east', r2))
    facts.extend(connect(r0, 'south', r3))
    facts.extend(connect(r0, 'west', r4))

    world = World.from_facts(facts)
    npt.assert_raises(NoFreeExitError, world.add_fact, Proposition("link", [r0, d, r5]))
Example #12
0
def test_automatically_positioning_rooms():
    P = Variable("P")
    r1 = Variable("Room1", "r")
    r2 = Variable("Room2", "r")
    d = Variable("door", "d")
    facts = [Proposition("at", [P, r1])]
    world = World.from_facts(facts)
    assert len(world.rooms) == 1
    assert len(world.find_room_by_id(r1.name).exits) == 0

    world.add_fact(Proposition("link", [r1, d, r2]))
    assert len(world.rooms) == 2
    r1_entity = world.find_room_by_id(r1.name)
    r2_entity = world.find_room_by_id(r2.name)
    assert len(r1_entity.exits) == 1
    assert len(r2_entity.exits) == 1

    assert list(r1_entity.exits.keys())[0] == reverse_direction(list(r2_entity.exits.keys())[0])
Example #13
0
def visualize(world: Union[Game, State, GlulxGameState, World],
              interactive: bool = False):
    """
    Show the current state of the world.
    :param world: Object representing a game state to be visualized.
    :param interactive: Whether or not to visualize the state in the browser.
    :return: Image object of the visualization.
    """
    if isinstance(world, Game):
        game = world
        state = load_state(game.world, game.infos)
        state["objective"] = ""
        if len(game.quests) > 0:
            state["objective"] = game.quests[0].desc
    elif isinstance(world, GlulxGameState):
        state = load_state_from_game_state(game_state=world)
    elif isinstance(world, World):
        state = load_state(world)
    elif isinstance(world, State):
        state = world
        world = World.from_facts(state.facts)
        state = load_state(world)
    else:
        raise ValueError("Don't know how to visualize: {!r}".format(world))

    state["command"] = ""
    state["history"] = ""
    html = textworld.render.serve.get_html_template(
        game_state=json.dumps(state))
    tmpdir = maybe_mkdir(pjoin(tempfile.gettempdir(), "textworld"))
    fh, filename = tempfile.mkstemp(suffix=".html", dir=tmpdir, text=True)
    url = 'file://' + filename
    with open(filename, 'w') as f:
        f.write(html)

    image = take_screenshot(url)
    if interactive:
        try:
            webbrowser.open(url)
        finally:
            return image

    return image
Example #14
0
def test_quest_winning_condition():
    g_rng.set_seed(2018)
    map_ = make_small_map(n_rooms=5, possible_door_states=["open"])
    world = World.from_map(map_)

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

        # Set the initial state required for the quest.
        tmp_world = World.from_facts(chain[0].state.facts)
        game = make_game_with(tmp_world, [quest], make_grammar({}))

        if tmp_world.player_room is None:
            # Randomly place the player in the world since
            # the action doesn't care about where the player is.
            tmp_world.set_player_room()

        game_name = "test_quest_winning_condition_" + rule.name.replace(
            "/", "_")
        with make_temp_directory(prefix=game_name) as tmpdir:
            game_file = compile_game(game, game_name, games_folder=tmpdir)

            env = textworld.start(game_file)
            env.reset()
            game_state, _, done = env.step("look")
            assert not done
            assert not game_state.has_won

            game_state, _, done = env.step(quest.commands[0])
            assert done
            assert game_state.has_won
def test_quest_winning_condition():
    g_rng.set_seed(2018)
    map_ = make_small_map(n_rooms=5, possible_door_states=["open"])
    world = World.from_map(map_)

    for rule in data.get_rules().values():
        options = ChainingOptions()
        options.backward = True
        options.max_depth = 1
        options.create_variables = True
        options.rules_per_depth = [[rule]]
        options.restricted_types = {"r"}
        chain = sample_quest(world.state, options)
        assert len(chain.actions) > 0, rule.name
        quest = Quest(chain.actions)

        # Set the initial state required for the quest.
        tmp_world = World.from_facts(chain.initial_state.facts)
        game = make_game_with(tmp_world, [quest], make_grammar({}))

        if tmp_world.player_room is None:
            # Randomly place the player in the world since
            # the action doesn't care about where the player is.
            tmp_world.set_player_room()

        game_name = "test_quest_winning_condition_" + rule.name.replace(
            "/", "_")
        with make_temp_directory(prefix=game_name) as tmpdir:
            game_file = compile_game(game, game_name, games_folder=tmpdir)

            env = textworld.start(game_file)
            env.reset()
            game_state, _, done = env.step("look")
            assert not done
            assert not game_state.has_won

            game_state, _, done = env.step(quest.commands[0])
            assert done
            assert game_state.has_won
Example #16
0
def filter_observables(world_facts: List[Proposition],
                       verbose=False,
                       game=None):
    fixups = defaultdict(set)
    if not world_facts:
        return None
    world_facts = reconstitute_facts(world_facts)

    # print("WORLD FACTS:")
    for fact in world_facts:
        # print('\t', fact)
        for v in fact.arguments:
            #     print('\t\t{}:{}'.format(v.name, v.type))
            if not v.name:
                v_count = len(fixups[v.type])
                assert v not in fixups[v.type]
                if v.type == 'P' or v.type == 'I' or v.type == 'RECIPE' or v.type == 'MEAL':
                    v.name = v.type
                    if v_count == 0:
                        fixups[v.type].add(v)
                else:
                    v.name = '~{}_{}'.format(v.type, v_count)
                    fixups[v.type].add(v)

    world = World.from_facts(world_facts)
    world_state = world.state

    if 'P' in world_state._vars_by_type:
        players = world_state.variables_of_type('P')
        assert len(players) == 1
    #     for p in players:
    #         player = p
    # else:
    #     player = None

    where_sig = Signature('at', ('P', 'r'))
    where_am_i = world_state.facts_with_signature(where_sig)
    assert len(where_am_i) == 1
    where_fact = list(where_am_i)[0]
    the_player = where_fact.arguments[0]
    player_location = where_fact.arguments[1]
    # if verbose:
    #     print("WORLD FACTS:")
    #     for fact in world_facts:
    #         print('\t', fact)
    #         # print_fact(game, fact)

    # if verbose:
    #     print("VARIABLES:")
    #     for v in world_state.variables:
    #         print('\t\t{}:{}'.format(v.name, v.type))

    print(where_fact, world.player_room)
    facts_in_scope = world.get_facts_in_scope()
    observable_facts = []
    for fact in facts_in_scope:
        # print("***\t\t", fact)
        if is_observable_relation(fact.name):
            if fact != where_fact:
                observable_facts.append(fact)
            else:  # consider the player's current location to be directly observable
                observable_facts.append(fact)
        else:
            pass

    for e in world.player_room.exits:
        if world.state.is_fact(
                Proposition(
                    'free',
                    (world.player_room.exits[e], where_fact.arguments[1]))):
            observable_facts.append(
                Proposition(
                    "{}_of".format(e),
                    (
                        Variable("exit_{}".format(e), 'e'),
                        world.player_room  # the_player
                    )))
    # REFACTORING: the following is now handled within add_extra_door_facts()
    #     else:  # probably a closed door
    #         door_facts = world.state.facts_with_signature(Signature('link', ('r', 'd', 'r')))
    #         for df in door_facts:
    #             if df.arguments[0] == player_location:
    #                 the_door = df.arguments[1]
    #                 observable_facts.append(Proposition("{}_of".format(e), (
    #                                                                 the_player,
    #                                                                 the_door
    #                                                                 )))
    #                 if world.state.is_fact(Proposition('closed', [the_door])):
    #                     observable_facts.append(Proposition('closed', [the_door]))

    add_extra_door_facts(world,
                         world_facts,
                         local_facts=observable_facts,
                         where_fact=where_fact)

    if verbose:
        print("++WORLD FACTS++:")
        for fact in world_facts:
            prettyprint_fact(fact, game=game)
    return observable_facts, player_location