Exemplo n.º 1
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.º 2
0
def test_parallel_quests():
    logic = GameLogic.parse("""
        type foo {
            rules {
                do_a :: not_a(foo) & $not_c(foo) -> a(foo);
                do_b :: not_b(foo) & $not_c(foo) -> b(foo);
                do_c :: $a(foo) & $b(foo) & not_c(foo) -> c(foo);
            }

            constraints {
                a_or_not_a :: a(foo) & not_a(foo) -> fail();
                b_or_not_b :: b(foo) & not_b(foo) -> fail();
                c_or_not_c :: c(foo) & not_c(foo) -> fail();
            }
        }
    """)
    kb = KnowledgeBase(logic, "")

    state = State(kb.logic, [
        Proposition.parse("a(foo)"),
        Proposition.parse("b(foo)"),
        Proposition.parse("c(foo)"),
    ])

    options = ChainingOptions()
    options.backward = True
    options.kb = kb

    options.max_depth = 3
    options.max_breadth = 1
    options.max_length = 3
    chains = list(get_chains(state, options))
    assert len(chains) == 2

    options.max_breadth = 2
    chains = list(get_chains(state, options))
    assert len(chains) == 3

    options.min_breadth = 2
    chains = list(get_chains(state, options))
    assert len(chains) == 1
    assert len(chains[0].actions) == 3
    assert chains[0].nodes[0].depth == 2
    assert chains[0].nodes[0].breadth == 2
    assert chains[0].nodes[0].parent == chains[0].nodes[2]
    assert chains[0].nodes[1].depth == 2
    assert chains[0].nodes[1].breadth == 1
    assert chains[0].nodes[1].parent == chains[0].nodes[2]
    assert chains[0].nodes[2].depth == 1
    assert chains[0].nodes[2].breadth == 1
    assert chains[0].nodes[2].parent is None

    options.min_breadth = 1
    options.create_variables = True
    state = State(kb.logic)
    chains = list(get_chains(state, options))
    assert len(chains) == 5
Exemplo n.º 3
0
    def load(cls, target_dir: Optional[str] = None):
        if target_dir is None:
            if os.path.isdir("./textworld_data"):
                target_dir = "./textworld_data"
            else:
                target_dir = BUILTIN_DATA_PATH

        # Load knowledge base related files.
        paths = glob.glob(pjoin(target_dir, "logic", "*"))
        logic = GameLogic.load(paths)

        # Load text generation related files.
        text_grammars_path = pjoin(target_dir, "text_grammars")
        return cls(logic, text_grammars_path)
Exemplo n.º 4
0
def test_reverse_rule_and_action():
    logic = GameLogic.parse("""
        type container {
            predicates {
                open(container);
                closed(container);
            }

            rules {
                open  :: closed(container) -> open(container);
                close :: open(container) -> closed(container);
            }

            reverse_rules {
                open :: close;
            }

            inform7 {
                commands {
                    open :: "open {container}" :: "opening the {container}";
                    close :: "close {container}" :: "closing the {container}";
                }
            }

        }
    """)

    open_rule = logic.rules["open"]
    close_rule = logic.rules["close"]
    assert open_rule.reverse_rule == close_rule
    assert close_rule.reverse_rule == open_rule

    open_action = open_rule.instantiate(
        {Placeholder("container", "container"): Variable("c_0", "container")})

    mapping = {"c_0": "chest"}
    assert open_action.format_command(mapping) == "open chest"
    r_open_action = open_action.inverse()
    assert r_open_action.name == "close"
    assert r_open_action.format_command(mapping) == "close chest"

    # Action's command template should persist through serialization.
    open_action2 = Action.deserialize(open_action.serialize())
    open_action2.format_command(mapping) == "open chest"

    assert open_action2.inverse() == r_open_action
Exemplo n.º 5
0
    def load(cls,
             target_dir: Optional[str] = None,
             logic_path: Optional[str] = None,
             grammar_path: Optional[str] = None) -> "KnowledgeBase":
        """ Build a KnowledgeBase from several files (logic and text grammar).

        Args:
            target_dir: Folder containing two subfolders: `logic` and `text_grammars`.
                        If provided, both `logic_path` and `grammar_path` are ignored.
            logic_path: Folder containing `*.twl` files that describe the logic of a game.
            grammar_path: Folder containing `*.twg` files that describe the grammar used for text generation.

        Returns:
            KnowledgeBase object.
        """
        if target_dir:
            logic_path = pjoin(target_dir, "logic")
            grammar_path = pjoin(target_dir, "text_grammars")

        if logic_path is None:
            logic_path = pjoin(".", "textworld_data",
                               "logic")  # Check within working dir.
            if not os.path.isdir(logic_path):
                logic_path = LOGIC_DATA_PATH  # Default to built-in data.

        # Load knowledge base related files.
        paths = glob.glob(pjoin(logic_path, "*.twl"))
        logic = GameLogic.load(paths)

        if grammar_path is None:
            grammar_path = pjoin(".", "textworld_data",
                                 "text_grammars")  # Check within working dir.
            if not os.path.isdir(grammar_path):
                grammar_path = TEXT_GRAMMARS_PATH  # Default to built-in data.

        # Load text generation related files.
        kb = cls(logic, grammar_path)
        kb.logic_path = logic_path
        return kb
Exemplo n.º 6
0
def load_logic(target_dir: str):
    global _LOGIC
    if _LOGIC:
        return

    paths = [pjoin(target_dir, path) for path in os.listdir(target_dir)]
    logic = GameLogic.load(paths)

    global _TYPES
    _TYPES = _to_type_tree(logic.types)

    global _RULES
    _RULES = _to_regex_dict(logic.rules.values())

    global _REVERSE_RULES
    _REVERSE_RULES = _to_reverse_mapper(_RULES, logic.reverse_rules)

    global _CONSTRAINTS
    _CONSTRAINTS = _to_regex_dict(logic.constraints.values())

    global INFORM7_COMMANDS
    INFORM7_COMMANDS = {i7cmd.rule: i7cmd.command for i7cmd in logic.inform7.commands.values()}

    global INFORM7_EVENTS
    INFORM7_EVENTS = {i7cmd.rule: i7cmd.event for i7cmd in logic.inform7.commands.values()}

    global INFORM7_PREDICATES
    INFORM7_PREDICATES = {i7pred.predicate.signature: (i7pred.predicate, i7pred.source) for i7pred in logic.inform7.predicates.values()}

    global INFORM7_VARIABLES
    INFORM7_VARIABLES = {i7type.name: i7type.kind for i7type in logic.inform7.types.values()}

    global INFORM7_VARIABLES_DESCRIPTION
    INFORM7_VARIABLES_DESCRIPTION = {i7type.name: i7type.definition for i7type in logic.inform7.types.values()}

    global INFORM7_ADDONS_CODE
    INFORM7_ADDONS_CODE = logic.inform7.code

    _LOGIC = logic
Exemplo n.º 7
0
 def deserialize(cls, data: Mapping) -> "KnowledgeBase":
     logic = GameLogic.deserialize(data["logic"])
     text_grammars_path = data["text_grammars_path"]
     return cls(logic, text_grammars_path)
Exemplo n.º 8
0
def test_parallel_quests_navigation():
    logic = GameLogic.parse("""
        type P {
        }

        type I {
        }

        type r {
            rules {
                move :: at(P, r) & $free(r, r') -> at(P, r');
            }

            constraints {
                atat :: at(P, r) & at(P, r') -> fail();
            }
        }

        type o {
            rules {
                take :: $at(P, r) & at(o, r) -> in(o, I);
            }

            constraints {
                inat :: in(o, I) & at(o, r) -> fail();
            }
        }

        type flour : o {
        }

        type eggs : o {
        }

        type cake {
            rules {
                bake :: in(flour, I) & in(eggs, I) -> in(cake, I) & in(flour, cake) & in(eggs, cake);
            }

            constraints {
                inincake :: in(o, I) & in(o, cake) -> fail();
                atincake :: at(o, r) & in(o, cake) -> fail();
            }
        }
    """)
    kb = KnowledgeBase(logic, "")

    state = State(kb.logic, [
        Proposition.parse("at(P, r3: r)"),
        Proposition.parse("free(r2: r, r3: r)"),
        Proposition.parse("free(r1: r, r2: r)"),
    ])

    bake = [kb.logic.rules["bake"]]
    non_bake = [r for r in kb.logic.rules.values() if r.name != "bake"]

    options = ChainingOptions()
    options.backward = True
    options.create_variables = True
    options.min_depth = 3
    options.max_depth = 3
    options.min_breadth = 2
    options.max_breadth = 2
    options.max_length = 6
    options.kb = kb
    options.rules_per_depth = [bake, non_bake, non_bake]
    options.restricted_types = {"P", "r"}
    chains = list(get_chains(state, options))
    assert len(chains) == 2