Exemple #1
0
def test_going_through_door():
    P = Variable("P", "P")
    room = Variable("room", "r")
    kitchen = Variable("kitchen", "r")
    state = State()
    state.add_facts([
        Proposition("at", [P, room]),
        Proposition("north_of", [kitchen, room]),
        Proposition("free", [kitchen, room]),
        Proposition("free", [room, kitchen]),
        Proposition("south_of", [room, kitchen])
    ])

    options = ChainingOptions()
    options.backward = True
    options.max_depth = 3
    options.subquests = True
    options.create_variables = True
    options.rules_per_depth = [
        [KnowledgeBase.default().rules["take/c"], KnowledgeBase.default().rules["take/s"]],
        KnowledgeBase.default().rules.get_matching("go.*"),
        [KnowledgeBase.default().rules["open/d"]],
    ]

    chains = list(get_chains(state, options))
    assert len(chains) == 18
Exemple #2
0
def test_state():
    state = State()

    P = Variable.parse("P")
    kitchen = Variable.parse("kitchen: r")
    study = Variable.parse("study: r")
    stove = Variable.parse("stove: o")
    at_kitchen = Proposition.parse("at(P, kitchen: r)")
    in_kitchen = Proposition.parse("in(stove: o, kitchen: r)")
    at_study = Proposition.parse("at(P, study: r)")

    assert not state.is_fact(at_kitchen)
    assert not state.is_fact(in_kitchen)
    assert not state.is_fact(at_study)
    assert len(state.variables) == 0
    assert len(state.variables_of_type("P")) == 0
    assert len(state.variables_of_type("r")) == 0
    assert len(state.variables_of_type("o")) == 0

    state.add_fact(at_kitchen)
    state.add_fact(in_kitchen)
    assert state.is_fact(at_kitchen)
    assert state.is_fact(in_kitchen)
    assert not state.is_fact(at_study)
    assert set(state.variables) == {P, kitchen, stove}
    assert state.variables_of_type("P") == {P}
    assert state.variables_of_type("r") == {kitchen}
    assert state.variables_of_type("o") == {stove}

    state.remove_fact(at_kitchen)
    assert not state.is_fact(at_kitchen)
    assert state.is_fact(in_kitchen)
    assert not state.is_fact(at_study)
    assert set(state.variables) == {kitchen, stove}
    assert len(state.variables_of_type("P")) == 0
    assert state.variables_of_type("r") == {kitchen}
    assert state.variables_of_type("o") == {stove}

    state.remove_fact(in_kitchen)
    assert not state.is_fact(at_kitchen)
    assert not state.is_fact(in_kitchen)
    assert not state.is_fact(at_study)
    assert len(state.variables) == 0
    assert len(state.variables_of_type("P")) == 0
    assert len(state.variables_of_type("r")) == 0
    assert len(state.variables_of_type("o")) == 0

    state.add_fact(at_study)
    assert not state.is_fact(at_kitchen)
    assert not state.is_fact(in_kitchen)
    assert state.is_fact(at_study)
    assert set(state.variables) == {P, study}
    assert state.variables_of_type("P") == {P}
    assert state.variables_of_type("r") == {study}
    assert len(state.variables_of_type("o")) == 0
Exemple #3
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([
        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
    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 == None

    options.min_breadth = 1
    options.create_variables = True
    chains = list(get_chains(State(), options))
    assert len(chains) == 5
Exemple #4
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
Exemple #5
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
Exemple #6
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)
Exemple #7
0
def check_state(state):
    fail = Proposition("fail", [])
    debug = Proposition("debug", [])

    constraints = state.all_applicable_actions(
        KnowledgeBase.default().constraints.values())
    for constraint in constraints:
        if state.is_applicable(constraint):
            # Optimistically delay copying the state
            copy = state.copy()
            copy.apply(constraint)

            if copy.is_fact(fail):
                return False

    return True
Exemple #8
0
    def add_fact(self, name: str, *entities: List["WorldEntity"]) -> None:
        """ Adds a fact to this entity.

        Args:
            name: The name of the new fact.
            *entities: A list of entities as arguments to the new fact.
        """
        args = [entity.var for entity in entities]
        self._facts.append(Proposition(name, args))
Exemple #9
0
    def new_fact(self, name: str, *entities: List["WorldEntity"]) -> None:
        """ Create new fact.

        Args:
            name: The name of the new fact.
            *entities: A list of entities as arguments to the new fact.
        """
        args = [entity.var for entity in entities]
        return Proposition(name, args)
Exemple #10
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]))
Exemple #11
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])
Exemple #12
0
    def check_state(self, state: State) -> bool:
        """Check that a state satisfies the constraints."""

        fail = Proposition("fail", [])

        constraints = state.all_applicable_actions(self.constraints)
        for constraint in constraints:
            copy = state.apply_on_copy(constraint)
            if copy and copy.is_fact(fail):
                return False

        return True
Exemple #13
0
def test_is_sequence_applicable():
    state = State([
        Proposition.parse("at(P, r_1: r)"),
        Proposition.parse("empty(r_2: r)"),
        Proposition.parse("empty(r_3: r)"),
    ])

    assert state.is_sequence_applicable([
        Action.parse("go :: at(P, r_1: r) & empty(r_2: r) -> at(P, r_2: r) & empty(r_1: r)"),
        Action.parse("go :: at(P, r_2: r) & empty(r_3: r) -> at(P, r_3: r) & empty(r_2: r)"),
    ])

    assert not state.is_sequence_applicable([
        Action.parse("go :: at(P, r_1: r) & empty(r_2: r) -> at(P, r_2: r) & empty(r_1: r)"),
        Action.parse("go :: at(P, r_1: r) & empty(r_3: r) -> at(P, r_3: r) & empty(r_1: r)"),
    ])

    assert not state.is_sequence_applicable([
        Action.parse("go :: at(P, r_2: r) & empty(r_3: r) -> at(P, r_3: r) & empty(r_2: r)"),
        Action.parse("go :: at(P, r_3: r) & empty(r_1: r) -> at(P, r_1: r) & empty(r_3: r)"),
    ])
Exemple #14
0
    def test_count(self):
        rng = np.random.RandomState(1234)
        types_counts = {t: rng.randint(2, 10) for t in self.types.variables}

        state = State()
        for t in self.types.variables:
            v = Variable(get_new(t, types_counts), t)
            state.add_fact(Proposition("dummy", [v]))

        counts = self.types.count(state)
        for t in self.types.variables:
            assert counts[t] == types_counts[t], (counts[t], types_counts[t])
Exemple #15
0
    def facts(self) -> List[Proposition]:
        """ Facts related to this path.

        Returns:
            The facts that make up this path.
        """
        facts = []
        facts.append(
            Proposition("{}_of".format(self.src_exit),
                        [self.dest.var, self.src.var]))
        facts.append(
            Proposition("{}_of".format(self.dest_exit),
                        [self.src.var, self.dest.var]))

        if self.door is None or self.door.has_property("open"):
            facts.append(Proposition("free", [self.src.var, self.dest.var]))
            facts.append(Proposition("free", [self.dest.var, self.src.var]))

        if self.door is not None:
            facts.extend(self.door.facts)
            facts.append(
                Proposition("link",
                            [self.src.var, self.door.var, self.dest.var]))
            facts.append(
                Proposition("link",
                            [self.dest.var, self.door.var, self.src.var]))

        return facts
Exemple #16
0
def test_logic_parsing():
    P = Variable("P", "P")
    kitchen = Variable("kitchen", "r")
    egg = Variable("egg", "f")

    assert Variable.parse("P") == P
    assert Variable.parse("kitchen: r") == kitchen

    at_kitchen = Proposition("at", [P, kitchen])
    in_kitchen = Proposition("in", [egg, kitchen])
    raw_egg = Proposition("raw", [egg])
    cooked_egg = Proposition("cooked", [egg])

    assert Proposition.parse("at(P, kitchen: r)") == at_kitchen

    assert Signature.parse("at(P, r)") == at_kitchen.signature

    cook_egg = Action("cook", [at_kitchen, in_kitchen, raw_egg], [at_kitchen, in_kitchen, cooked_egg])
    assert Action.parse("cook :: $at(P, kitchen: r) & $in(egg: f, kitchen: r) & raw(egg: f) -> cooked(egg: f)") == cook_egg

    P = Placeholder("P", "P")
    r = Placeholder("r", "r")
    d = Placeholder("d", "d")
    rp = Placeholder("r'", "r")
    assert Placeholder.parse("P") == P
    assert Placeholder.parse("r") == r
    assert Placeholder.parse("d") == d
    assert Placeholder.parse("r'") == rp

    at_r = Predicate("at", [P, r])
    link = Predicate("link", [r, d, rp])
    unlocked = Predicate("unlocked", [d])
    at_rp = Predicate("at", [P, rp])
    assert Predicate.parse("link(r, d, r')") == link

    go = Rule("go", [at_r, link, unlocked], [link, unlocked, at_rp])
    assert Rule.parse("go :: at(P, r) & $link(r, d, r') & $unlocked(d) -> at(P, r')") == go

    # Make sure the types match in the whole expression
    assert_raises(ValueError, Rule.parse, "take :: $at(P, r) & $in(c, r) & in(o: k, c) -> in(o, I)")
Exemple #17
0
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
Exemple #18
0
def test_all_instantiations():
    state = State([
        Proposition.parse("at(P, kitchen: r)"),
        Proposition.parse("in(key: o, kitchen: r)"),
        Proposition.parse("in(egg: o, kitchen: r)"),
        Proposition.parse("in(book: o, study: r)"),
        Proposition.parse("in(book: o, study: r)"),
        Proposition.parse("in(map: o, I)"),
    ])

    take = Rule.parse("take :: $at(P, r) & in(o, r) -> in(o, I)")
    actions = set(state.all_instantiations(take))
    assert actions == {
        Action.parse("take :: $at(P, kitchen: r) & in(key: o, kitchen: r) -> in(key: o, I)"),
        Action.parse("take :: $at(P, kitchen: r) & in(egg: o, kitchen: r) -> in(egg: o, I)"),
    }

    drop = take.inverse(name="drop")
    actions = set(state.all_instantiations(drop))
    assert actions == {
        Action.parse("drop :: $at(P, kitchen: r) & in(map: o, I) -> in(map: o, kitchen: r)"),
    }

    state.apply(*actions)
    actions = set(state.all_instantiations(drop))
    assert len(actions) == 0

    # The state is no longer aware of the I variable, so there are no solutions
    actions = set(state.all_instantiations(take))
    assert len(actions) == 0
Exemple #19
0
def test_backward_chaining():
    P = Variable("P", "P")
    room = Variable("room", "r")
    kitchen = Variable("kitchen", "r")
    state = State([
        Proposition("at", [P, room]),
        Proposition("north_of", [kitchen, room]),
        Proposition("south_of", [room, kitchen]),
    ])

    options = ChainingOptions()
    options.backward = True
    options.max_depth = 2
    options.subquests = True
    options.create_variables = True
    options.rules_per_depth = [
        [KnowledgeBase.default().rules["take/c"], KnowledgeBase.default().rules["take/s"]],
        [KnowledgeBase.default().rules["open/c"]],
    ]
    options.restricted_types = {"d"}

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

    options = ChainingOptions()
    options.backward = True
    options.max_depth = 3
    options.subquests = True
    options.create_variables = True
    options.rules_per_depth = [
        [KnowledgeBase.default().rules["put"]],
        [KnowledgeBase.default().rules["go/north"]],
        [KnowledgeBase.default().rules["take/c"]],
    ]
    options.restricted_types = {"d"}

    chains = list(get_chains(state, options))
    assert len(chains) == 3
Exemple #20
0
def get_failing_constraints(state):
    fail = Proposition("fail", [])

    failed_constraints = []
    constraints = state.all_applicable_actions(
        KnowledgeBase.default().constraints.values())
    for constraint in constraints:
        if state.is_applicable(constraint):
            # Optimistically delay copying the state
            copy = state.copy()
            copy.apply(constraint)

            if copy.is_fact(fail):
                failed_constraints.append(constraint)

    return failed_constraints
Exemple #21
0
    def set_player_room(self,
                        start_room: Union[None, WorldRoom,
                                          str] = None) -> None:
        if start_room is None:
            if len(self.rooms) == 0:
                start_room = WorldRoom("r_0", "r")
            else:
                start_room = self.rooms[0]

        elif start_room in self._entities:
            start_room = self._entities[start_room]
        elif isinstance(start_room,
                        Variable) and start_room.name in self._entities:
            start_room = self._entities[start_room.name]
        else:
            raise ValueError("Unknown room: {}".format(start_room))

        self.add_fact(Proposition("at", [self.player, start_room]))
Exemple #22
0
    def set_conditions(self, conditions: Iterable[Proposition]) -> Action:
        """
        Set the triggering conditions for this event.

        Args:
            conditions: Set of propositions which need to
                        be all true in order for this event
                        to get triggered.
        Returns:
            Action that can only be applied when all conditions are statisfied.
        """
        if not conditions:
            if len(self.actions) == 0:
                raise UnderspecifiedEventError()

            # The default winning conditions are the postconditions of the
            # last action in the quest.
            conditions = self.actions[-1].postconditions

        variables = sorted(set([v for c in conditions for v in c.arguments]))
        event = Proposition("event", arguments=variables)
        self.condition = Action("trigger", preconditions=conditions,
                                postconditions=list(conditions) + [event])
        return self.condition
Exemple #23
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 = tw_textlabs.generator.make_grammar({},
                                                 rng=np.random.RandomState(42))
    for k, v in grammar.grammar.items():
        grammar.grammar[k] = v[:2]  # Force reusing variables.

    game = tw_textlabs.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
Exemple #24
0
def test_make_world_with():
    r1 = Variable("r_0", "r")
    P = Variable('P')
    world = make_world_with(rooms=[r1])
    assert Proposition('at', [P, r1]) in world.facts
Exemple #25
0
def test_propositions():
    state = build_state()
    for prop in state.facts:
        data = prop.serialize()
        loaded_prop = Proposition.deserialize(data)
        assert loaded_prop == prop
Exemple #26
0
def build_state(door_state="open"):
    # Set up a world with two rooms and a few objecs.
    state = State([
        Proposition("at", [P, bedroom]),
        Proposition("south_of", [kitchen, bedroom]),
        Proposition("north_of", [bedroom, kitchen]),
        Proposition("link", [bedroom, wooden_door, kitchen]),
        Proposition("link", [kitchen, wooden_door, bedroom]),
        Proposition(door_state, [wooden_door]),
        #
        Proposition("in", [rusty_key, I]),
        Proposition("match", [rusty_key, chest]),
        Proposition("locked", [chest]),
        Proposition("at", [chest, kitchen]),
        Proposition("in", [small_key, chest]),
        #
        Proposition("match", [small_key, cabinet]),
        Proposition("locked", [cabinet]),
        Proposition("at", [cabinet, bedroom]),
        Proposition("in", [robe, cabinet]),
    ])
    return state
Exemple #27
0
    def get_win_conditions(self, chain: Chain) -> Collection[Proposition]:
        """
        Given a chain of actions comprising a quest, return the set of propositions
        which must hold in a winning state.
        
        Parameters
        ----------
        chain:
            Chain of actions leading to goal state.
            
        Returns
        -------
        win_conditions:
            Set of propositions which must hold to end the quest succesfully.
        """

        win_condition_type = self.options.win_condition

        win_conditions = set()

        final_state = chain.final_state
        pg = ProcessGraph()
        pg.from_tw_actions(chain.actions)

        if win_condition_type in [WinConditionType.OPS, WinConditionType.ALL]:

            # require all operations to have the correct inputs
            processed_props = set([
                prop for prop in final_state.facts if prop.name == 'processed'
            ])
            component_props = set([
                prop for prop in final_state.facts if prop.name == 'component'
            ])
            win_conditions.update(processed_props)
            win_conditions.update(component_props)

            # require all operations to be set to correct type
            op_type_props = set([
                prop for prop in final_state.facts
                if prop.name == 'tlq_op_type'
            ])
            win_conditions.update(op_type_props)

            # precedence propositions enforcing minimal ordering restraints between ops
            tG = nx.algorithms.dag.transitive_closure(pg.G)
            op_nodes = [
                n for n in tG.nodes()
                if KnowledgeBase.default().types.is_descendant_of(
                    n.var.type, ["op"])
            ]
            op_sg = nx.algorithms.dag.transitive_reduction(
                tG.subgraph(op_nodes))
            for e in op_sg.edges():
                op_1_node, op_2_node = e
                prec_prop = Proposition('preceeds',
                                        [op_1_node.var, op_2_node.var])
                win_conditions.update({prec_prop})

        if win_condition_type in [WinConditionType.ARGS, WinConditionType.ALL]:
            # require all descriptions to be set correctly
            desc_props = set([
                prop for prop in final_state.facts if prop.name == 'describes'
            ])
            win_conditions.update(desc_props)

        # add post-conditions from last action
        post_props = set(chain.actions[-1].postconditions)
        win_conditions.update(post_props)

        return Event(conditions=win_conditions)
Exemple #28
0
def test_constraints():
    # Declare some variables.
    P = Variable("P", "P")
    I = Variable("I", "I")
    bedroom = Variable("bedroom", "r")
    kitchen = Variable("kitchen", "r")
    rusty_key = Variable("rusty key", "k")
    small_key = Variable("small key", "k")
    wooden_door = Variable("wooden door", "d")
    glass_door = Variable("glass door", "d")
    chest = Variable("chest", "c")
    cabinet = Variable("cabinet", "c")
    counter = Variable("counter", "s")
    robe = Variable("robe", "o")

    # Make sure the number of basic constraints matches the number
    # of constraints in constraints.txt
    basic_constraints = [
        k for k in KnowledgeBase.default().constraints.keys() if "-" not in k
    ]
    # assert len(basic_constraints) == 32

    # Doors can only have one state.
    door_states = ["open", "closed", "locked"]
    for door_state in door_states:
        state = State([Proposition(door_state, [wooden_door])])
        assert check_state(state)
        for door_state2 in door_states:
            if door_state == door_state2:
                continue

            state2 = state.copy()

            state2.add_fact(Proposition(door_state2, [glass_door]))  # New door
            assert check_state(state2)

            state2.add_fact(Proposition(door_state2, [wooden_door]))
            assert not check_state(state2)

    # Containers can only have one state.
    container_states = ["open", "closed", "locked"]
    for container_state in container_states:
        state = State([Proposition(container_state, [chest])])
        assert check_state(state)
        for container_state2 in container_states:
            if container_state == container_state2:
                continue

            state2 = state.copy()

            state2.add_fact(Proposition(container_state2,
                                        [cabinet]))  # New container
            assert check_state(state2)

            state2.add_fact(Proposition(container_state2, [chest]))
            assert not check_state(state2)

    # A player/supporter/container can only be at one place.
    for obj in [P, chest, counter]:
        assert check_state(State([Proposition("at", [obj, kitchen])]))
        assert check_state(State([Proposition("at", [obj, bedroom])]))
        assert not check_state(
            State([
                Proposition("at", [obj, kitchen]),
                Proposition("at", [obj, bedroom])
            ]))

    # An object is either in the player's inventory, in a container or on a supporter
    obj_locations = [
        Proposition("in", [robe, I]),
        Proposition("in", [robe, chest]),
        Proposition("on", [robe, counter])
    ]
    for obj_location in obj_locations:
        assert check_state(State([obj_location]))
        for obj_location2 in obj_locations:
            if obj_location == obj_location2: break
            assert not check_state(State([obj_location, obj_location2
                                          ])), "{}, {}".format(
                                              obj_location, obj_location2)

    # Only one key can match a container and vice-versa.
    assert check_state(State([Proposition("match", [rusty_key, chest])]))
    assert not check_state(
        State([
            Proposition("match", [small_key, chest]),
            Proposition("match", [rusty_key, chest])
        ]))
    assert not check_state(
        State([
            Proposition("match", [small_key, cabinet]),
            Proposition("match", [small_key, chest])
        ]))

    # Only one key can match a door and vice-versa.
    assert check_state(State([Proposition("match", [rusty_key, chest])]))
    assert not check_state(
        State([
            Proposition("match", [small_key, wooden_door]),
            Proposition("match", [rusty_key, wooden_door])
        ]))
    assert not check_state(
        State([
            Proposition("match", [small_key, glass_door]),
            Proposition("match", [small_key, wooden_door])
        ]))

    # A door can't be used to link more than two rooms.
    door = Variable("door", "d")
    room1 = Variable("room1", "r")
    room2 = Variable("room2", "r")
    room3 = Variable("room3", "r")
    assert not check_state(
        State([
            Proposition("link", [room1, door, room2]),
            Proposition("link", [room1, door, room3]),
        ]))

    door1 = Variable("door1", "d")
    door2 = Variable("door2", "d")
    room1 = Variable("room1", "r")
    room2 = Variable("room2", "r")
    assert not check_state(
        State([
            Proposition("link", [room1, door1, room2]),
            Proposition("link", [room1, door2, room2]),
        ]))
Exemple #29
0
def test_room_connections():
    room0 = Variable("room0", "r")
    room1 = Variable("room1", "r")
    room2 = Variable("room2", "r")

    # Only one connection can exist between two rooms.
    # r1
    # |
    # r0 - r1
    state = State([
        Proposition("north_of", [room1, room0]),
        Proposition("south_of", [room0, room1]),
        Proposition("east_of", [room1, room0]),
        Proposition("west_of", [room0, room1])
    ])

    assert not check_state(state)

    # Non Cartesian layout are allowed.
    # r1
    # |
    # r0 - r2 - r1
    state = State([
        Proposition("north_of", [room1, room0]),
        Proposition("south_of", [room0, room1]),
        Proposition("east_of", [room2, room0]),
        Proposition("west_of", [room0, room2]),
        Proposition("east_of", [room1, room2]),
        Proposition("west_of", [room2, room1])
    ])

    assert check_state(state)

    # A room cannot have more than 4 'link' propositions.
    room3 = Variable("room3", "r")
    room4 = Variable("room4", "r")
    room5 = Variable("room5", "r")
    door1 = Variable("door1", "d")
    door2 = Variable("door2", "d")
    door3 = Variable("door3", "d")
    door4 = Variable("door4", "d")
    door5 = Variable("door5", "d")

    state = State([
        Proposition("link", [room0, door1, room1]),
        Proposition("link", [room0, door2, room2]),
        Proposition("link", [room0, door3, room3]),
        Proposition("link", [room0, door4, room4]),
        Proposition("link", [room0, door5, room5])
    ])

    assert not check_state(state)
Exemple #30
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([
        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.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