コード例 #1
0
ファイル: world.py プロジェクト: syh307611391/Research
def connect(room1: Variable,
            direction: str,
            room2: Variable,
            door: Optional[Variable] = None) -> List[Proposition]:
    """ Generate predicates that connect two rooms.

    Args:
        room1: A room variable.
        direction: Direction that we need to travel to go from
                   room1 to room2.
        room2: A room variable.
        door: The door separating the two rooms. If `None`, there is no
              door between the rooms.
    """
    r_direction = reverse_direction(direction) + "_of"
    direction += "_of"
    facts = [
        Proposition(direction, [room2, room1]),
        Proposition(r_direction, [room1, room2]),
        Proposition("free", [room1, room2]),
        Proposition("free", [room2, room1])
    ]

    if door is not None:
        facts += [
            Proposition("link", [room1, door, room2]),
            Proposition("link", [room2, door, room1])
        ]

    return facts
コード例 #2
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])
コード例 #3
0
def make_game(mode: str, options: GameOptions) -> textworld.Game:
    """ Make a Coin Collector game.

    Arguments:
        mode: Mode for the game where

              * `'simple'`: the distractor rooms are only placed orthogonaly
                to the chain. This means moving off the optimal path leads
                immediately to a dead end.
              * `'random'`: the distractor rooms are randomly place along the
                chain. This means a player can wander for a while before
                reaching a dead end.
        options:
            For customizing the game generation (see
            :py:class:`textworld.GameOptions <textworld.generator.game.GameOptions>`
            for the list of available options).

    Returns:
        Generated game.
    """
    if mode == "simple" and float(options.nb_rooms) / options.quest_length > 4:
        msg = ("Total number of rooms must be less than 4 * `quest_length` "
               "when distractor mode is 'simple'.")
        raise ValueError(msg)

    metadata = {}  # Collect infos for reproducibility.
    metadata["desc"] = "Coin Collector"
    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_grammar = rngs['grammar']

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

    rooms = []
    walkthrough = []
    for i in range(options.quest_length):
        r = M.new_room()
        if i >= 1:
            # Connect it to the previous rooms.
            free_exits = [k for k, v in rooms[-1].exits.items() if v.dest is None]
            src_exit = rng_map.choice(free_exits)
            dest_exit = reverse_direction(src_exit)
            M.connect(rooms[-1].exits[src_exit], r.exits[dest_exit])
            walkthrough.append("go {}".format(src_exit))

        rooms.append(r)

    M.set_player(rooms[0])

    # Add object the player has to pick up.
    obj = M.new(type="o", name="coin")
    rooms[-1].add(obj)

    # Add distractor rooms, if needed.
    chain_of_rooms = list(rooms)
    while len(rooms) < options.nb_rooms:
        if mode == "random":
            src = rng_map.choice(rooms)
        else:
            # Add one distractor room per room along the chain.
            src = chain_of_rooms[len(rooms) % len(chain_of_rooms)]

        free_exits = [k for k, v in src.exits.items() if v.dest is None]
        if len(free_exits) == 0:
            continue

        dest = M.new_room()
        src_exit = rng_map.choice(free_exits)
        dest_exit = reverse_direction(src_exit)
        M.connect(src.exits[src_exit], dest.exits[dest_exit])
        rooms.append(dest)

    # Generate the quest thats by collecting the coin.
    walkthrough.append("take coin")
    # TODO: avoid compiling the game at all (i.e. use the inference engine).
    M.set_quest_from_commands(walkthrough)

    game = M.build()
    game.metadata = metadata
    mode_choice = 0 if mode == "simple" else 1
    uuid = "tw-coin_collector-{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
コード例 #4
0
ファイル: world.py プロジェクト: syh307611391/Research
    def _process_rooms(self) -> None:
        for fact in self.facts:
            if not self.kb.types.is_descendant_of(fact.arguments[0].type, 'r'):
                continue  # Skip non room facts.

            room = self._get_room(fact.arguments[0])
            room.add_related_fact(fact)

            if fact.name.endswith("_of"):
                # Handle room positioning facts.
                exit = reverse_direction(fact.name.split("_of")[0])
                dest = self._get_room(fact.arguments[1])
                dest.add_related_fact(fact)
                assert exit not in room.exits
                room.exits[exit] = dest

        # Handle door link facts.
        for fact in self.facts:
            if fact.name != "link":
                continue

            src = self._get_room(fact.arguments[0])
            door = self._get_object(fact.arguments[1])
            dest = self._get_room(fact.arguments[2])
            door.add_related_fact(fact)
            src.content.append(door)

            exit_found = False
            for exit, room in src.exits.items():
                if dest == room:
                    src.doors[exit] = door
                    exit_found = True
                    break

            if not exit_found:
                # Need to position both rooms w.r.t. each other.
                src_free_exits = [
                    exit for exit in DIRECTIONS if exit not in src.exits
                ]
                for exit in src_free_exits:
                    r_exit = reverse_direction(exit)
                    if r_exit not in dest.exits:
                        src.exits[exit] = dest
                        dest.exits[r_exit] = src
                        src.doors[exit] = door
                        exit_found = True
                        break

            # Relax the Cartesian grid constraint.
            if not exit_found:
                # Need to position both rooms w.r.t. each other.
                src_free_exits = [
                    exit for exit in DIRECTIONS if exit not in src.exits
                ]
                dest_free_exits = [
                    exit for exit in DIRECTIONS if exit not in dest.exits
                ]
                if len(src_free_exits) > 0 and len(dest_free_exits) > 0:
                    exit = src_free_exits[0]
                    r_exit = dest_free_exits[0]
                    src.exits[exit] = dest
                    dest.exits[r_exit] = src
                    src.doors[exit] = door
                    exit_found = True

            if not exit_found:  # If there is still no exit found.
                raise NoFreeExitError("Cannot connect {} and {}.".format(
                    src, dest))
コード例 #5
0
def make_game(
        mode: str,
        n_rooms: int,
        quest_length: int,
        grammar_flags: Mapping = {},
        seeds: Optional[Union[int, Dict[str, int]]] = None) -> textworld.Game:
    """ Make a Coin Collector game.

    Arguments:
        mode: Mode for the game where

              * `'simple'`: the distractor rooms are only placed orthogonaly
                to the chain. This means moving off the optimal path leads
                immediately to a dead end.
              * `'random'`: the distractor rooms are randomly place along the
                chain. This means a player can wander for a while before
                reaching a dead end.
        n_rooms: Number of rooms in the game.
        quest_length: Number of rooms in the chain. This also represents the
                      number of commands for the optimal policy.
        grammar_flags: Options for the grammar controlling the text generation
                       process.
        seeds: Seeds for the different generation processes.

               * If `None`, seeds will be sampled from
                 :py:data:`textworld.g_rng <textworld.utils.g_rng>`.
               * If `int`, it acts as a seed for a random generator that will be
                 used to sample the other seeds.
               * If dict, the following keys can be set:

                 * `'seed_map'`: control the map generation;
                 * `'seed_objects'`: control the type of objects and their
                   location;
                 * `'seed_quest'`: control the quest generation;
                 * `'seed_grammar'`: control the text generation.

                 For any key missing, a random number gets assigned (sampled
                 from :py:data:`textworld.g_rng <textworld.utils.g_rng>`).

    Returns:
        Generated game.
    """
    if mode == "simple" and float(n_rooms) / quest_length > 4:
        msg = ("Total number of rooms must be less than 4 * `quest_length` "
               "when distractor mode is 'simple'.")
        raise ValueError(msg)

    # Deal with any missing random seeds.
    seeds = get_seeds_for_game_generation(seeds)

    metadata = {}  # Collect infos for reproducibility.
    metadata["desc"] = "Coin Collector"
    metadata["mode"] = mode
    metadata["seeds"] = seeds
    metadata["world_size"] = n_rooms
    metadata["quest_length"] = quest_length
    metadata["grammar_flags"] = grammar_flags

    rng_map = np.random.RandomState(seeds['seed_map'])
    rng_grammar = np.random.RandomState(seeds['seed_grammar'])

    # Generate map.
    M = textworld.GameMaker()
    M.grammar = textworld.generator.make_grammar(flags=grammar_flags,
                                                 rng=rng_grammar)

    rooms = []
    walkthrough = []
    for i in range(quest_length):
        r = M.new_room()
        if i >= 1:
            # Connect it to the previous rooms.
            free_exits = [
                k for k, v in rooms[-1].exits.items() if v.dest is None
            ]
            src_exit = rng_map.choice(free_exits)
            dest_exit = reverse_direction(src_exit)
            M.connect(rooms[-1].exits[src_exit], r.exits[dest_exit])
            walkthrough.append("go {}".format(src_exit))

        rooms.append(r)

    M.set_player(rooms[0])

    # Add object the player has to pick up.
    obj = M.new(type="o", name="coin")
    rooms[-1].add(obj)

    # Add distractor rooms, if needed.
    chain_of_rooms = list(rooms)
    while len(rooms) < n_rooms:
        if mode == "random":
            src = rng_map.choice(rooms)
        else:
            # Add one distractor room per room along the chain.
            src = chain_of_rooms[len(rooms) % len(chain_of_rooms)]

        free_exits = [k for k, v in src.exits.items() if v.dest is None]
        if len(free_exits) == 0:
            continue

        dest = M.new_room()
        src_exit = rng_map.choice(free_exits)
        dest_exit = reverse_direction(src_exit)
        M.connect(src.exits[src_exit], dest.exits[dest_exit])
        rooms.append(dest)

    # Generate the quest thats by collecting the coin.
    walkthrough.append("take coin")
    # TODO: avoid compiling the game at all (i.e. use the inference engine).
    M.set_quest_from_commands(walkthrough)

    game = M.build()
    game.metadata = metadata
    mode_choice = 0 if mode == "simple" else 1
    uuid = "tw-coin_collector-{specs}-{flags}-{seeds}"
    uuid = uuid.format(specs=encode_seeds(
        (mode_choice, n_rooms, quest_length)),
                       flags=encode_flags(grammar_flags),
                       seeds=encode_seeds([seeds[k] for k in sorted(seeds)]))
    game.metadata["uuid"] = uuid
    return game