Exemplo n.º 1
0
    def setUpClass(cls):
        M = GameMaker()

        # The goal
        commands = [
            "open wooden door", "go west", "take carrot", "go east",
            "drop carrot"
        ]

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

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

        cls.quest = M.set_quest_from_commands(commands)
Exemplo n.º 2
0
def make_game() -> textworld.Game:
    maker = GameMaker(game_options)
    rng_grammar = rngs["grammar"]
    maker.grammar = textworld.generator.make_grammar(maker.options.grammar,
                                                     rng=rng_grammar)

    place_rooms(maker)

    if config.verbose:
        print()
        print("====== Placing furniture ======")

    place_furniture(maker)

    if config.verbose:
        print()
        print("====== Placing objects ======")

    placed_objects = place_objects(maker)

    if config.verbose:
        print()
        print("====== Shuffling objects ======")

    move_objects(maker, placed_objects)

    if config.verbose and config.distractors:
        print()
        print("====== Placing distractors ======")

    place_distractors(maker)

    set_container_properties(maker)
    limit_inventory_size(maker)
    maker.quests = generate_quests(maker, placed_objects)

    check_properties(maker)

    uuid = generate_uuid(maker)
    game = maker.build()

    set_metadata(maker, game, placed_objects)

    if config.verbose:
        print()
        print("====== Goal Locations ======")
        for obj, locations in game.metadata["goal_locations"].items():
            print(f'{obj} ->', ", ".join(locations))

    game_options.path = pjoin(config.output_dir, uuid)

    return textworld.generator.compile_game(game, game_options)
Exemplo n.º 3
0
def test_reloading_game_with_custom_kb():
    twl = KnowledgeBase.default().logic._document
    twl += """
        type customobj : o {
            inform7 {
                type {
                    kind :: "custom-obj-like";
                }
            }
        }
    """

    logic = GameLogic.parse(twl)
    options = GameOptions()
    options.kb = KnowledgeBase(logic, "")
    M = GameMaker(options)

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

    custom_obj = M.new(type='customobj', name='customized object')
    M.inventory.add(custom_obj)

    commands = ["drop customized object"]
    quest = M.set_quest_from_commands(commands)
    assert quest.commands == tuple(commands)
    game = M.build()
    assert game == Game.deserialize(game.serialize())
Exemplo n.º 4
0
    def setUpClass(cls):
        M = GameMaker()

        # The goal
        commands = ["take carrot", "insert carrot into chest"]

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

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

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

        cls.event = M.new_event_using_commands(commands)
        cls.actions = cls.event.actions
        cls.conditions = {M.new_fact("in", carrot, chest)}
Exemplo n.º 5
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
Exemplo n.º 6
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.failing_conditions = (Proposition("eaten", [carrot.var]),)
        cls.quest = M.set_quest_from_commands(commands)
        cls.quest.set_failing_conditions(cls.failing_conditions)
        cls.game = M.build()
Exemplo n.º 7
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)
Exemplo n.º 8
0
def build_and_compile_super_hero_game():
    M = GameMaker()
    roomA = M.new_room("Room A")
    alley = M.new_room("Alley")
    bank1 = M.new_room("Bank1")
    bank2 = M.new_room("Bank2")
    bank3 = M.new_room("Bank3")
    corridor = M.connect(roomA.east, alley.west)
    corridor1 = M.connect(alley.east, bank1.west)
    corridor1 = M.connect(alley.north, bank2.south)
    corridor1 = M.connect(alley.south, bank3.north)
    M.set_player(roomA)
    
    roomA.infos.desc = "You are in a road. Some mobs are planning to rob a bank. You need to stop them. Go east to the alley. You can find a person in the alley who has information about the roberry. Collect information from him and prevent the roberry."
    alley.infos.desc = "This is an alley. There is a person beside the table. He knows about the bank roberry."
    bank2.infos.desc = "This is the north bank. Some robbers are going to rob the bank. You can call the police and try to capture them or convince them to surrender. Or you can also shoot them to stop the robbery."
    
    money = M.new(type="o", name = 'money') 
    money.infos.desc = "it is money"
    M.inventory.add(money) 
    person = M.new(type="pr", name = "informant")
    person.infos.desc = "This person knows about the bank roberry. Do a favor for him. He will help you."
    M.add_fact("not_asked", person)
    M.add_fact("not_given", person)
    alley.add(person)
    
    robber = M.new(type="rbr", name = "joker")
    bank2.add(robber)
    M.add_fact("not_stopped", robber)
    
    M.add_fact("not_conflict", robber)
    M.add_fact("not_allowed", robber)
    
    police = M.new(type="pl", name = "police")
    bank2.add(police)
    M.add_fact("not_called", police)
    
    
    # asking quest
    qst_event_asking = Event(conditions={M.new_fact("asked", person)})
    quest_asking = Quest(win_events=[qst_event_asking],
                      reward=2)
    # the wining quest
    qst_event_stopped_rob = Event(conditions={M.new_fact("asked", person),
                                             M.new_fact("stopped", robber)})
    win_quest = Quest(win_events=[qst_event_stopped_rob],
                      reward=2)

    # 1st failure condition
    failed_cmds1 = ["go east", "go south"]
    failed_event1 = M.new_event_using_commands(failed_cmds1)
    failed_quest_1 = Quest(win_events=[],
                           fail_events=[failed_event1])
    
    # 2nd failure condition
    failed_cmds2 = ["go east", "go east"]
    failed_event2 = M.new_event_using_commands(failed_cmds2)
    failed_quest_2 = Quest(win_events=[],
                           fail_events=[failed_event2])
    
    # 3rd failure condition
    failed_event3 = Event(conditions={
        M.new_fact("not_asked", person),
        M.new_fact("at", M._entities['P'], bank2)})
    
    failed_quest_3 = Quest(win_events=[],
                           fail_events=[failed_event3])
    
    
    failed_event4 = Event(conditions={
        M.new_fact("allowed", robber)})
    
    failed_quest_4 = Quest(win_events=[],
                   fail_events=[failed_event4])
    
    
    M.quests = [win_quest, quest_asking, failed_quest_1, failed_quest_2, failed_quest_3, failed_quest_4]
    game = M.build()

    game.main_quest = win_quest
    game_file = _compile_test_game(game)
    return game, game_file
Exemplo n.º 9
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.º 10
0
def make_example_game(args):
    g_rng.set_seed(20201008)

    M = GameMaker()

    # Define rooms
    roomS = M.new_room(name="start", desc="\n")
    roomI = M.new_room(name="if", desc="\n")
    roomV = M.new_room(name="variable", desc="\n")
    roomF = M.new_room(name="for", desc="\n")

    # Define connections
    connectSI = M.connect(roomS.east, roomI.west)
    connectSV = M.connect(roomS.south, roomV.north)
    connectFS = M.connect(roomF.east, roomS.west)

    # Set player
    M.set_player(roomS)

    #Create objects
    i_rand=random.choice(string.ascii_letters)
    f_rand=random.choice(string.ascii_letters)
    v_rand=random.choice(string.ascii_letters)

    objectI = M.new(type='o', name=i_rand, desc="if")
    objectF = M.new(type='o', name=f_rand, desc="for")
    objectV = M.new(type='o', name=v_rand, desc="variable")

    #Add objects to rooms
    roomI.add(objectI)
    roomF.add(objectF)
    roomV.add(objectV)

    #Print object names for testing (will not be in game)
    print(objectI.name)
    print(objectF.name)
    print(objectV.name)

    #Create quests with assigned rewards
    q1 = M.record_quest() #Create quest for including completed if statement
    q1.reward = 1 #Reward for completing if statement (sparse=1, dense=5, balanced=1)
    q2 = M.record_quest() #Create quest for including complete for loop
    q2.reward = 1 #Reward for completing for loop (same distribution as if)
    q3 = M.record_quest() #Create quest for including print statement
    q3.reward = 1 #Reward for completing print statement (sparse=0, dense=1, balanced=1)
    q4 = M.record_quest() #Create quest for including new variable assignment
    q4.reward = 1 #Reward for completing variable assignment (same distribution as print)

    #Create game and associated files
    game_file = M.compile("./carr_dang_shortRL/compiled_game/games.ulx")

    return game_file
Exemplo n.º 11
0
 def reset(self):
     self.maker = GameMaker(self.config.game_options)
Exemplo n.º 12
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)

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

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

        commands = ["drop pepper"]
        cls.eventC = 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=[cls.eventC], fail_events=[])
        cls.questD = 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 = ["eat tomato"]
        cls.eating_tomato = M.new_event_using_commands(commands)
        commands = ["eat pepper"]
        cls.eating_pepper = M.new_event_using_commands(commands)

        M.quests = [cls.questA, cls.questB, cls.questC]
        cls.game = M.build()
Exemplo n.º 13
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)

        M.quests = [cls.quest]
        cls.game = M.build()
Exemplo n.º 14
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.º 15
0
import textworld as tw
from textworld import GameMaker

from textworld import g_rng  # global random generator
g_rng.set_seed(1)

M = GameMaker()
roomA = M.new_room("room A")
roomB = M.new_room("room B")
corridor = M.connect(roomA.exits['east'], roomB.exits['west'])
M.render(interactive=True)
Exemplo n.º 16
0
class TWCGameMaker:
    def __init__(self, config):
        self.config = config
        self.data = TWCData(config)
        self.maker = GameMaker(config.game_options)
        self.num_games = 0

    def reset(self):
        self.maker = GameMaker(self.config.game_options)

    def make_game(self):
        rng_grammar = self.config.rngs["grammar"]
        self.maker.grammar = textworld.generator.make_grammar(self.maker.options.grammar, rng=rng_grammar)

        self.place_rooms()

        placed_objects = []

        while len(placed_objects) < self.config.objects:
            if self.config.verbose:
                print()
                print("====== Placing furniture ======")

            furniture = self.place_furniture()
            if not furniture:
                print()
                print(f"Could not generate the game with the provided configuration")
                sys.exit(-1)

            if self.config.verbose:
                print()
                print("====== Placing objects ======")

            placed_objects += self.place_objects()
            assert len(placed_objects) == len(set(placed_objects))

        if self.config.verbose:
            print()
            print("====== Shuffling objects ======")

        self.move_objects(placed_objects)

        if self.config.verbose and self.config.distractors:
            print()
            print("====== Placing distractors ======")

        self.place_distractors()

        self.set_container_properties()
        self.limit_inventory_size()
        self.maker.quests = self.generate_quests(placed_objects)

        self.check_properties()

        uuid = self.generate_uuid()
        game = self.maker.build()
        self.num_games += 1

        self.set_metadata(game, placed_objects)

        if self.config.verbose:
            print()
            print("====== Goal Locations ======")
            for obj, locations in game.metadata["goal_locations"].items():
                print(f'{obj} ->', ", ".join(locations))

        self.config.game_options.path = pjoin(self.config.output_dir, uuid)

        result = textworld.generator.compile_game(game, self.config.game_options)
        self.reset()
        return result

    def place_rooms(self):
        rng = self.config.rngs["map"]
        assert self.config.rooms <= len(self.data.rooms)
        initial_room = self.config.initial_room or rng.choice(self.data.rooms)
        rooms_to_place = self.pick_rooms(initial_room)
        if self.config.verbose:
            print("Rooms:", rooms_to_place)
        self.create_map(rooms_to_place)
        room = self.maker.find_by_name(initial_room)
        self.maker.set_player(room)

    def pick_name(self, names):
        rng = self.config.rngs["objects"]
        names = list(names)
        rng.shuffle(names)
        for name in names:
            if self.maker.find_by_name(name) is None:
                return name
        assert False

    def pick_rooms(self, initial_room):
        assert self.config.rooms <= len(self.data.rooms)
        rng = self.config.rngs["map"]
        visited = {initial_room}
        neighbors = set(self.data.map[initial_room])
        neighbors -= visited

        while len(visited) < self.config.rooms:
            room = rng.choice(list(neighbors))
            visited.add(room)
            neighbors |= set(self.data.map[room])
            neighbors -= visited

        return list(visited)

    def pick_correct_location(self, locations):
        rng = self.config.rngs["objects"]
        locations = list(locations)
        rng.shuffle(locations)
        for location in locations:
            holder = None
            if "." in location:
                room_name = location.split(".")[0]
                holder_name = location.split(".")[1]
                room = self.maker.find_by_name(room_name)
                if room is not None:
                    holder = next((e for e in room.content if e.infos.name == holder_name), None)
            else:
                holder = self.maker.find_by_name(location)
            if holder:
                return holder
        return None

    def pick_wrong_object_location(self, object_name, prefer_correct_room=None):
        rng = self.config.rngs["objects"]
        correct_locations = self.data.objects[object_name]["locations"]
        rng.shuffle(correct_locations)

        holder_names = {location.split(".")[-1] for location in correct_locations}
        forbidden = illegal_locations(self.data.objects[object_name])
        holder_names |= forbidden

        if prefer_correct_room is None:
            prefer_correct_room = self.config.isolated_rooms

        assert prefer_correct_room in [True, False]
        correct_room = self.find_correct_room(object_name)

        # Try to pick location in correct room
        if correct_room and prefer_correct_room:
            room_furniture = [e for e in correct_room.content if e.infos.type in ["c", "s"]]
            wrong_holders = [e for e in room_furniture if e.infos.name not in holder_names]
            if FLOOR not in holder_names:
                wrong_holders.append(correct_room)
            rng.shuffle(wrong_holders)
            if len(wrong_holders) > 0:
                return wrong_holders[0]

        # Pick a random supporter or container
        all_supporters = list(self.maker.findall("s"))
        all_containers = list(self.maker.findall("c"))
        all_rooms = self.maker.rooms

        all_holders = all_supporters + all_containers
        if FLOOR not in holder_names:
            all_holders += all_rooms

        rng.shuffle(all_holders)
        wrong_holders = [e for e in all_holders if e.infos.name not in holder_names]

        if len(wrong_holders) > 0:
            return wrong_holders[0]

        # No wrong location found. Create new furniture
        pool = [f for f in self.data.locations.keys() if f not in holder_names]
        return self.place_random_entity(pool)

    def find_correct_room(self, object_name):
        correct_locations = self.data.objects[object_name]["locations"]
        holder_names = {location.split(".")[-1] for location in correct_locations}

        for location in correct_locations:
            if "." in location:
                room_name = location.split(".")[0]
                return self.maker.find_by_name(room_name)
        for holder_name in holder_names:
            holder = self.maker.find_by_name(holder_name)
            if holder:
                return holder.parent

    def place_at(self, name, holder):
        entity = self.maker.new(type=self.data.entities[name]["type"], name=name)
        entity.infos.noun = name
        if "adjs" in self.data.entities[name] and self.data.entities[name]["adjs"]:
            entity.infos.adj = self.data.entities[name]["adjs"][0]
        if "desc" in self.data.entities[name]:
            entity.infos.desc = self.data.entities[name]["desc"][0]
        if "indefinite" in self.data.entities[name]:
            entity.infos.indefinite = self.data.entities[name]["indefinite"]
        for property_ in self.data.entities[name]["properties"]:
            entity.add_property(property_)
        holder.add(entity)
        self.log_entity_placement(entity, holder)
        return entity

    def log_entity_placement(self, entity, holder):
        name = entity.infos.name
        if self.config.verbose:
            if self.data.entities[name]["category"] == "furniture":
                print(f"{entity.infos.name} added to the {holder.infos.name}")
            elif holder.type == "r":
                print(f"{entity.infos.name} added to the floor in the {holder.infos.name}")
            else:
                print(f"{entity.infos.name} added to the {holder.infos.name} in the {holder.parent.infos.name}")

    def attempt_place_entity(self, name):
        if self.maker.find_by_name(name):
            return
        holder = self.pick_correct_location(self.data.entities[name]["locations"])
        if holder is None:
            return None
        return self.place_at(name, holder)

    def place_entities(self, names):
        return [self.attempt_place_entity(name) for name in names]

    def place_random_entities(self, nb_entities, pool=None):
        rng = self.config.rngs["objects"]
        if pool is None:
            pool = list(self.data.entities.keys())
        if len(pool) == 0:
            return []
        seen = set(e.name for e in self.maker._entities.values())
        candidates = [name for name in pool if name not in seen]
        rng.shuffle(candidates)
        entities = []
        for candidate in candidates:
            if len(entities) >= nb_entities:
                break
            entity = self.attempt_place_entity(candidate)
            if entity:
                entities.append(entity)

        return entities

    def place_random_entity(self, pool):
        entities = self.place_random_entities(1, pool)
        return entities[0] if entities else None

    def place_random_furniture(self, nb_furniture):
        return self.place_random_entities(nb_furniture, self.data.locations.keys())

    def make_graph_map(self, rooms, size=(5, 5)):
        rng = self.config.rngs["map"]
        walker = RandomWalk(neighbors=self.data.map, size=size, rng=rng)
        return walker.place_rooms(rooms)

    def create_map(self, rooms_to_place):
        graph = self.make_graph_map(rooms_to_place)
        rooms = self.maker.import_graph(graph)

        for infos in self.data.doors:
            room1 = self.maker.find_by_name(infos["path"][0])
            room2 = self.maker.find_by_name(infos["path"][1])
            if room1 is None or room2 is None:
                continue  # This door doesn't exist in this world.
            path = self.maker.find_path(room1, room2)
            if path:
                assert path.door is None
                name = self.pick_name(infos["names"])
                door = self.maker.new_door(path, name)
                door.add_property("closed")
        return rooms

    def find_correct_locations(self, obj):
        name = obj.infos.name
        locations = self.data.objects[name]["locations"]
        result = []
        for location in locations:
            if "." in location:
                room_name = location.split(".")[0]
                holder_name = location.split(".")[1]
                room = self.maker.find_by_name(room_name)
                if room is not None:
                    result += [e for e in room.content if e.infos.name == holder_name]
            else:
                holder = self.maker.find_by_name(location)
                if holder:
                    result.append(holder)
        return result

    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

    def generate_goal_locations(self, objs):
        result = {obj.infos.name: [] for obj in objs}
        for obj in objs:
            locations = self.find_correct_locations(obj)
            for loc in locations:
                result[obj.infos.name].append(loc.infos.name)
        return result

    def generate_quests(self, objs):
        return [q for obj in objs for q in self.generate_quest(obj)]

    def set_metadata(self, game, placed_objects):
        game.objective = INTRO + " " + GOAL
        config = dict(vars(self.config))
        del config['game_options']
        del config['rngs']
        metadata = {
            "seeds": self.maker.options.seeds,
            "config": config,
            "entities": [e.name for e in self.maker._entities.values() if e.name],
            "max_score": sum(quest.reward for quest in game.quests),
            "goal": GOAL,
            "goal_locations": self.generate_goal_locations(placed_objects),
            "uuid": self.generate_uuid()
        }
        game.metadata = metadata

    def generate_uuid(self):
        uuid = "tw-iqa-cleanup-{specs}-{seeds}"
        seeds = self.maker.options.seeds
        uuid = uuid.format(specs=prettify_config(self.config),
                           seeds=encode_seeds([seeds[k] + self.num_games for k in sorted(seeds)]))
        return uuid

    def check_properties(self):
        for entity in self.maker._entities.values():
            if entity.type in ["c", "d"] and not \
                    (entity.has_property("closed") or
                     entity.has_property("open") or
                     entity.has_property("locked")):
                raise ValueError("Forgot to add closed/locked/open property for '{}'.".format(entity.name))

    def limit_inventory_size(self):
        inventory_limit = self.config.objects * 2
        nb_objects_in_inventory = self.config.objects - self.config.take
        if self.config.drop:
            inventory_limit = max(1, nb_objects_in_inventory)
        for i in range(inventory_limit):
            slot = self.maker.new(type="slot", name="")
            if i < len(self.maker.inventory.content):
                slot.add_property("used")
            else:
                slot.add_property("free")
            self.maker.nowhere.append(slot)

    def set_container_properties(self):
        if not self.config.open:
            for entity in self.maker._entities.values():
                if entity.has_property("closed"):
                    entity.remove_property("closed")
                    entity.add_property("open")

    def place_distractors(self):
        rng_objects = self.config.rngs["objects"]
        nb_objects = self.config.objects
        if self.config.distractors:
            nb_distractors = max(0, int(rng_objects.randn(1) * 3 + nb_objects))
            self.place_random_entities(nb_distractors, pool=list(self.data.objects.keys()))

    def move_objects(self, placed_objects):
        rng_quest = self.config.rngs["quest"]
        nb_objects_in_inventory = self.config.objects - self.config.take
        shuffled_objects = list(placed_objects)
        rng_quest.shuffle(shuffled_objects)

        for obj in shuffled_objects[:nb_objects_in_inventory]:
            self.maker.move(obj, self.maker.inventory)

        for obj in shuffled_objects[nb_objects_in_inventory:]:
            wrong_location = self.pick_wrong_object_location(obj.infos.name)
            self.maker.move(obj, wrong_location)
            self.log_entity_placement(obj, wrong_location)

        return nb_objects_in_inventory

    def objects_by_furniture(self, furniture):
        result = []
        for o in self.data.objects:
            locations = [loc.split(".")[-1] for loc in self.data.objects[o]["locations"]]
            if furniture in locations:
                result.append(o)
        return result

    def evenly_place_objects(self):
        all_supporters = list(self.maker.findall("s"))
        all_containers = list(self.maker.findall("c"))
        furniture = all_supporters + all_containers

        objects_per_furniture = self.config.objects // len(furniture)

        placed = []
        for holder in furniture:
            pool = self.objects_by_furniture(holder.infos.name)
            placed += self.place_random_entities(objects_per_furniture, pool)

        remainder = self.config.objects - len(placed)
        placed += self.place_random_entities(remainder, list(self.data.objects.keys()))
        return placed

    def place_objects(self, distribute_evenly=True):
        rng = self.config.rngs["objects"]
        if distribute_evenly is None:
            distribute_evenly = rng.choice([True, False])
        if distribute_evenly:
            return self.evenly_place_objects()
        placed_objects = self.place_random_entities(self.config.objects, list(self.data.objects.keys()))
        return placed_objects

    def evenly_place_furniture(self, nb_furniture):
        furniture_per_room = nb_furniture // self.config.rooms
        placed = []
        for room in self.maker.rooms:
            room_name = room.infos.name
            pool = [k for k, v in self.data.locations.items() if room_name in v["locations"]]
            placed += self.place_random_entities(furniture_per_room, pool)

        remainder = nb_furniture - len(placed)
        placed += self.place_random_furniture(remainder)
        return placed

    def place_furniture(self, distribute_evenly=True):
        rng = self.config.rngs["objects"]
        if distribute_evenly is None:
            distribute_evenly = rng.choice([True, False])
        self.place_entities(DEFAULT_FURNITURE)
        upper_bound = max(2 * len(self.maker.rooms), 0.33 * self.config.objects)
        nb_furniture = rng.randint(len(self.maker.rooms), min(upper_bound, len(self.data.locations) + 1))
        if distribute_evenly:
            return self.evenly_place_furniture(nb_furniture)
        else:
            return self.place_random_furniture(nb_furniture)
Exemplo n.º 17
0
 def __init__(self, config):
     self.config = config
     self.data = TWCData(config)
     self.maker = GameMaker(config.game_options)
     self.num_games = 0
Exemplo n.º 18
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)
Exemplo n.º 19
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
Exemplo n.º 20
0
def make_example_game(args):
    """
    This game takes place in a typical house and consists in
    three puzzles:
    1) Escape the room;
    2) Find the missing ingredient;
    3) Finish preparing the dinner.

    Here's the map of the house.
                Bathroom
                    +
                    |
                    +
    Bedroom +--+ Kitchen +----+ Backyard
                    +              +
                    |              |
                    +              +
               Living Room       Garden
    """
    # Make the generation process reproducible.
    g_rng.set_seed(2018)

    M = GameMaker()
    # 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)

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

    # - and the key is in the drawer.
    bedroom_key = M.new(type='k', name='old key')
    drawer.add(bedroom_key)
    drawer.add_property("closed")
    M.add_fact("match", bedroom_key, bedroom_kitchen.door)

    # - Describe the room.
    bedroom.desc = ""

    # 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 note on the kitchen island.
    objective = "The dinner is almost ready! It's only missing a grilled carrot."
    note = M.new(type='o', name='note', desc=objective)
    kitchen_island.add(note)

    # - 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')
    carrot = M.new(type='f', name='carrot')
    lettuce = M.new(type='f', name='lettuce')
    garden.add(shovel, tomato, carrot, lettuce)

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

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

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

    # To define a quest we are going to record it by playing the game.
    # print("******* Recording a quest. Hit 'Ctrl + C' when done. *******")
    # M.record_quest()
    commands = [
        "open chest drawer", "take old key from chest drawer",
        "unlock wooden door with old key", "open wooden door", "go east"
    ]

    if args.type in ["short", "medium", "long", "last", "human"]:
        commands.append("open screen door")

    if args.type in ["medium", "long", "last", "human"]:
        commands.extend(["go east", "go south", "take carrot"])

    if args.type in ["long", "last", "human"]:
        commands.extend([
            "go north",
            "go west",
            "put carrot on stove",
            # "cook carrot"  # Not supported yet.
        ])

    quest = M.set_quest_from_commands(commands)

    # TODO: Provide better API to specify failing conditions.
    quest.set_failing_conditions([Proposition("eaten", [carrot.var])])

    if args.type == "human":
        # Use a very high-level description of the objective.
        quest.desc = ""

    elif args.type == "last":
        # Use a very high-level description of the objective.
        quest.desc = objective

    print(quest.desc)

    game_file = M.compile(args.filename)
    print("*** Game created: {}".format(game_file))
    return game_file