Ejemplo n.º 1
0
    def convert_mission_graph_to_spatial_subgraph_form(solution_node_order):
        def is_mission_node_spatial_subgraph_node(node):
            return not (isinstance(node, Key) or isinstance(node, End)
                        or isinstance(node, Collectable))

        subgraph_nodes = set()
        solution_nodes_to_subgraph_nodes = dict()
        for node in solution_node_order:
            if is_mission_node_spatial_subgraph_node(node):
                subgraph_node = Node(node.name)
                subgraph_nodes.add(subgraph_node)
                solution_nodes_to_subgraph_nodes[node] = subgraph_node

        for node in solution_node_order:
            if not is_mission_node_spatial_subgraph_node(node):
                solution_nodes_to_subgraph_nodes[
                    node] = solution_nodes_to_subgraph_nodes[next(
                        iter(node.parent_s))]
            else:
                subgraph_node = solution_nodes_to_subgraph_nodes[node]
                for child in node.child_s:
                    if is_mission_node_spatial_subgraph_node(child):
                        subgraph_adjacent_node = solution_nodes_to_subgraph_nodes[
                            child]
                        subgraph_node.add_adjacent_nodes(
                            subgraph_adjacent_node)

        return subgraph_nodes, solution_nodes_to_subgraph_nodes
Ejemplo n.º 2
0
    def fill_dead_ends(self):
        collectables = []

        def visit_method(node, visited_nodes):
            if len(node.child_s) == 0 and isinstance(node, Lock):
                collectable = self.add_collectable(node)
                collectables.append(collectable)

        Node.traverse_nodes_breadth_first(self.start, visit_method)
        return collectables
Ejemplo n.º 3
0
    def get_node_layout(start_node):
        def only_visit_children_of_non_keys(node, child, visited_nodes):
            return not isinstance(node, Key)

        def sort_keys_last(node):
            if isinstance(node, Collectable):
                return 2
            elif isinstance(node, Key):
                return 1
            else:
                return 0

        nodes = Node.find_all_nodes(
            node=start_node,
            method="depth-first",
            will_traverse_method=only_visit_children_of_non_keys,
            child_sort_method=sort_keys_last)
        node_positions = dict()
        rows = defaultdict(lambda: -1)
        for node in nodes:
            node_depth = GraphVisualizer.get_node_depth(node)
            if not isinstance(node, Key):
                row_width = GraphVisualizer.get_max_width_below_row(
                    rows, node_depth)
            else:
                row_width = rows[node_depth]

            node_width = np.maximum(row_width + 1, rows[node_depth - 1])

            rows[node_depth] = node_width
            node_positions[node] = np.array([node_width, node_depth])

        return node_positions
Ejemplo n.º 4
0
    def _get_lock_water_fire_lock_graph():
        start = Start()
        key_red = Key("red")
        lock_red = Lock("red")
        flippers = Key("flippers")
        water1 = Lock("water1")
        water2 = Lock("water2")
        key_green = Key("green")
        lock_green = Lock("green")
        fire_boots = Key("fireboots")
        fire1 = Lock("fire1")
        fire2 = Lock("fire2")
        end = End()
        start.add_child_s([fire2, key_red, lock_red])
        key_red.add_lock_s(lock_red)
        lock_red.add_child_s([flippers, water1])
        flippers.add_lock_s([water1, water2])
        water1.add_child_s(water2)
        water2.add_child_s([fire_boots, fire1])
        fire_boots.add_lock_s([fire1, fire2])
        fire1.add_child_s(key_green)
        key_green.add_lock_s(lock_green)
        fire2.add_child_s(lock_green)
        lock_green.add_child_s(end)

        return Node.find_all_nodes(start, method="topological-sort")
Ejemplo n.º 5
0
 def test_add(self):
     n0 = GNode("0")
     n1 = GNode("1")
     n2 = GNode("2")
     n3 = GNode("3")
     n4 = GNode("4")
     n5 = GNode("5")
     Node._add(n0, [n1], lambda x: x.child_s, lambda x: x.parent_s)
     self.assertEqual(n0.child_s, {n1})
     self.assertEqual(n1.parent_s, {n0})
     Node._add(n0, [n2, n3, n4, n5], lambda x: x.child_s,
               lambda x: x.parent_s)
     self.assertEqual(n0.child_s, {n1, n2, n3, n4, n5})
     self.assertEqual(n1.parent_s, {n0})
     self.assertEqual(n2.parent_s, {n0})
     self.assertEqual(n3.parent_s, {n0})
     self.assertEqual(n4.parent_s, {n0})
     self.assertEqual(n5.parent_s, {n0})
Ejemplo n.º 6
0
    def get_random_descendant(self, node):
        def is_valid_descendant(child):
            return not isinstance(child, Key) and not isinstance(child, End)

        possible_descendants = [
            node for node in Node.find_all_nodes(node)
            if is_valid_descendant(node)
        ]
        descendant = np.random.choice(possible_descendants)
        return descendant
Ejemplo n.º 7
0
    def _get_simple_graph():
        start = Start()
        key = Key()
        lock = Lock()
        end = End()
        start.add_child_s([key, lock])
        key.add_lock_s(lock)
        lock.add_child_s(end)

        return Node.find_all_nodes(start, method="topological-sort")
Ejemplo n.º 8
0
 def insert_rooms(self, aesthetic):
     nodes = Node.find_all_nodes(self.start, method="topological-sort")
     for node in nodes:
         keys = [n for n in node.child_s if isinstance(n, Key)]
         if len(keys) > 0 and np.random.random(
         ) < aesthetic.insert_room_probability:
             room = Room(str(self.get_room_id()), parent_s=node)
             for key in keys:
                 key.remove_parent_s(node)
                 key.add_parent_s(room)
Ejemplo n.º 9
0
    def test_find_all_nodes(self):
        a, all_nodes = TestGraphs.get_man_graph()
        nodes = Node.find_all_nodes(a)
        self.assertEqual(set(nodes), all_nodes)

        a, all_nodes = TestGraphs.get_house_graph()
        nodes = Node.find_all_nodes(a)
        self.assertEqual(set(nodes), all_nodes)

        a, all_nodes = TestGraphs.get_graph_b()
        nodes = Node.find_all_nodes(a)
        self.assertEqual(set(nodes), all_nodes)

        a, all_nodes = TestGraphs.get_graph_a()
        nodes = Node.find_all_nodes(a)
        self.assertEqual(set(nodes), all_nodes)

        a, all_nodes = TestGraphs.get_triangle_graph()
        nodes = Node.find_all_nodes(a)
        self.assertEqual(set(nodes), all_nodes)
Ejemplo n.º 10
0
    def test_topological_sort_bug(self):
        start = Start()
        key = Key("key")
        lock = Lock("lock")
        end = End()
        start.add_child_s(key)
        key.add_lock_s(lock)
        lock.add_child_s(end)

        nodes = Node.find_all_nodes(start, method="topological-sort")
        self.assertEqual(nodes, [start, key, lock, end])
Ejemplo n.º 11
0
    def test_remove_by_name(self):
        n1 = GNode("1")
        n2 = GNode("2")
        n3 = GNode("3")
        n4 = GNode("4")
        n5 = GNode("5")

        n0 = GNode("0")
        n0.child_s = {n1, n2, n3, n4, n5}
        n1.parent_s.add(n0)
        n2.parent_s.add(n0)
        n2.parent_s.add(n0)
        n3.parent_s.add(n0)
        n4.parent_s.add(n0)
        n5.parent_s.add(n0)
        Node._remove_by_name(n0, n2.name, lambda x: x.child_s,
                             lambda x: x.parent_s)
        self.assertEqual(n0.child_s, {n1, n3, n4, n5})
        self.assertEqual(n1.parent_s, {n0})
        self.assertEqual(n2.parent_s, set())
        self.assertEqual(n3.parent_s, {n0})
        self.assertEqual(n4.parent_s, {n0})
        self.assertEqual(n5.parent_s, {n0})
    def init_spatial_graph(mission_graph_start_node, random_initial_positions=True):
        nodes = Node.find_all_nodes(mission_graph_start_node)
        nodes = sorted(nodes, key=lambda x: x.name)
        if random_initial_positions:
            node_positions = np.random.random([len(nodes), 2]) * 10
        else:
            node_positions = np.transpose(np.stack([np.arange(len(nodes)), np.zeros(len(nodes))]))

        adjacency_matrix = np.zeros([len(nodes), len(nodes)])
        for i, node_start in enumerate(nodes):
            for j, node_end in enumerate(nodes):
                if node_end in node_start.child_s:
                    adjacency_matrix[(i, j)] = 1
                    adjacency_matrix[(j, i)] = 1
        return nodes, node_positions, adjacency_matrix
Ejemplo n.º 13
0
    def _get_water_lock_graph():
        start = Start()
        key_red = Key("red")
        lock_red = Lock("red")
        flippers = Key("flippers")
        water = Lock("water")
        end = End()

        start.add_child_s([flippers, water, lock_red])
        flippers.add_lock_s(water)
        water.add_child_s(key_red)
        key_red.add_lock_s(lock_red)
        lock_red.add_child_s(end)

        return Node.find_all_nodes(start, method="topological-sort")
Ejemplo n.º 14
0
    def test_find_all_nodes_topological_sort(self):
        top_sort = "topological-sort"

        n0 = GNode("0")
        n1 = GNode("1")
        n2 = GNode("2")
        n3 = GNode("3")
        n4 = GNode("4")
        n5 = GNode("5")
        n5.add_child_s([n0, n2, n4])
        n2.add_child_s(n3)
        n3.add_child_s(n1)
        n4.add_child_s([n0, n1])
        nodes = Node.find_all_nodes(n5, method=top_sort)
        self.assertTrue(
            self.assert_ordered(nodes, [(n5, [n4, n3, n2, n1, n0]),
                                        (n4, [n0, n1]), (n2, [n3, n1]),
                                        (n3, [n1]), (n0, []), (n1, [])]))

        n0 = GNode("0")
        n1 = GNode("1")
        n2 = GNode("2")
        n3 = GNode("3")
        n4 = GNode("4")
        n5 = GNode("5")
        n0.add_child_s([n1, n2, n3])
        n1.add_child_s(n4)
        n2.add_child_s(n5)
        n3.add_child_s(n1)
        n4.add_child_s(n2)
        nodes = Node.find_all_nodes(n0, method=top_sort)
        self.assertTrue(
            self.assert_ordered(nodes, [(n0, [n1, n2, n3, n4, n5]),
                                        (n1, [n4, n2, n5]), (n2, [n5]),
                                        (n3, [n1, n4, n2, n5]), (n4, [n2, n5]),
                                        (n5, [])]))
    def test_works_with_branched_graphs(self):
        # return
        # S
        # |-----------
        # |    |     |
        # L1   K2    L2
        # |          |
        # E          K1
        start = Start()
        key1 = Key("1")
        key2 = Key("2")
        lock1 = Lock("1")
        lock2 = Lock("2")
        end = End()

        start.add_child_s([lock1, key2, lock2])
        lock1.add_child_s(end)
        lock2.add_child_s(key1)
        key1.add_child_s(lock1)
        key2.add_child_s(lock2)
        key1.add_lock_s(lock1)
        key2.add_lock_s(lock2)

        np.random.seed(4)

        level = Level()
        w = Tiles.wall
        e = Tiles.empty
        layer = np.array([[w, w, w, w, w, w, w, w], [w, e, e, e, e, e, e, w],
                          [w, e, e, e, e, e, e, w], [w, w, w, w, w, w, w, w],
                          [w, e, e, w, e, e, e, w], [w, e, e, w, e, e, e, w],
                          [w, e, e, w, e, e, e, w], [w, w, w, w, w, w, w, w]],
                         dtype=object)

        solution_node_order = Node.find_all_nodes(start,
                                                  method="topological-sort")

        aesthetic_settings = AestheticSettings()
        was_successful = Generator.generate(
            level=level,
            size=layer.shape,
            aesthetic_settings=aesthetic_settings,
            max_retry_count=10,
            pregenerated_level_layer=layer,
            pregenerated_solution_node_order=solution_node_order)
        self.assertTrue(was_successful)

        Log.print(level)
Ejemplo n.º 16
0
    def test_traverse_breadth_first(self):
        node, all_nodes = TestGraphs.get_man_graph()
        visited_expected = ["Start", "b", "c", "d", "e", "End", "g", "h", "i"]

        def visit_method(node, visited_nodes):
            visited.append(node)

        def will_traverse_method(node, visited_nodes):
            return True

        # Traverse with no will_traverse_method specified
        visited = []
        Node.traverse_nodes_breadth_first(node, visit_method)
        visited_names = [x.name for x in visited]
        self.assertTrue(
            self.assert_ordered(
                visited_names,
                [("Start", ["b", "c", "d", "e", "End", "g", "h", "i"]),
                 ("b", ["e", "End", "g", "h", "i"]),
                 ("c", ["e", "End", "g", "h", "i"]),
                 ("d", ["e", "End", "g", "h", "i"]), ("h", []), ("g", []),
                 ("e", []), ("End", [])]))

        # Traverse with will_traverse_method that allows all nodes
        visited = []
        Node.traverse_nodes_breadth_first(node, visit_method,
                                          will_traverse_method)
        visited_names = [x.name for x in visited]
        self.assertTrue(
            self.assert_ordered(
                visited_names,
                [("Start", ["b", "c", "d", "e", "End", "g", "h", "i"]),
                 ("b", ["e", "End", "g", "h", "i"]),
                 ("c", ["e", "End", "g", "h", "i"]),
                 ("d", ["e", "End", "g", "h", "i"]), ("h", []), ("g", []),
                 ("e", []), ("End", [])]))

        # Traverse with will_traverse_method that ignores node "c"
        def will_traverse_method2(node, visited_nodes):
            return node.name != "c"

        visited = []
        Node.traverse_nodes_breadth_first(node, visit_method,
                                          will_traverse_method2)
        visited_names = [x.name for x in visited]
        visited_expected = ["Start", "b", "d", "e"]
        self.assertTrue(
            self.assert_ordered(visited_names, [("Start", ["b", "d", "e"]),
                                                ("b", ["e"]), ("d", []),
                                                ("e", [])]))

        self.assertFalse(
            self.are_values_in_list(visited_names, ["c", "g", "h", "i"]))
Ejemplo n.º 17
0
    def generate_mission(level, mission_aesthetic):
        node_to_tile = dict()
        solution_node_order = Node.find_all_nodes(level.mission,
                                                  method="topological-sort")

        spatial_graph = SpatialGraph(level.upper_layer)
        mission_spatial_nodes, mission_to_mission_spatial = MissionGenerator.convert_mission_graph_to_spatial_subgraph_form(
            solution_node_order)
        mission_to_spaces_mapping = SubgraphFinder.get_subgraph_mapping(
            spatial_graph.nodes, mission_spatial_nodes)
        if mission_to_spaces_mapping is not None:
            MissionGenerator.apply_mission_mapping_to_level(
                level, solution_node_order, mission_to_mission_spatial,
                mission_to_spaces_mapping, node_to_tile, mission_aesthetic)

            level.required_collectable_count = np.count_nonzero(
                level.upper_layer == Tiles.collectable)
            return Solver.does_level_follow_mission(level)
        return False, None
Ejemplo n.º 18
0
    def add_multi_lock(self, lock_count=2):
        def is_node_multilock_candidate(node):
            is_candidate = (isinstance(node, Key) and len(node.lock_s) == 1
                            and len(next(iter(node.lock_s)).key_s) == 1)
            return is_candidate

        multilock_key_candidates = [
            node for node in Node.find_all_nodes(self.start)
            if is_node_multilock_candidate(node)
        ]
        multilock_key = np.random.choice(multilock_key_candidates)
        lock = next(iter(multilock_key.lock_s))

        for _ in range(lock_count):
            current_node = self.get_random_descendant(lock)

            child = None
            if len(current_node.child_s) > 0:
                child = np.random.choice(list(current_node.child_s))

            lock = self.add_lock(current_node, multilock_key, child)
Ejemplo n.º 19
0
    def show_graph(start_node,
                   draw_straight_lines=True,
                   draw_key_connections=True):
        sorted_nodes = Node.find_all_nodes(start_node,
                                           method="topological-sort")
        node_positions = GraphVisualizer.get_node_layout(start_node)

        im = Image.new('RGB', GraphVisualizer.get_image_size(node_positions),
                       GraphVisualizer.background_color)
        draw = ImageDraw.Draw(im)

        # Draw Connections
        for node in sorted_nodes:
            parent_node = GraphVisualizer.get_not_key_parent(node)
            if parent_node is not None:
                GraphVisualizer.draw_connection(draw,
                                                node_positions[parent_node],
                                                node_positions[node],
                                                straight=draw_straight_lines,
                                                is_key_connection=False)
            if isinstance(node, Key) and draw_key_connections:
                for lock in node.lock_s:
                    GraphVisualizer.draw_connection(draw,
                                                    node_positions[node],
                                                    node_positions[lock],
                                                    straight=True,
                                                    is_key_connection=True)

        # Draw Nodes
        for node in sorted_nodes:
            if isinstance(node, Key):
                node_type = "key"
            else:
                node_type = "lock"
            GraphVisualizer.draw_node(draw,
                                      node_positions[node],
                                      node.name,
                                      n_type=node_type)

        im.show()
Ejemplo n.º 20
0
    def get_efficient_node_order(mission_start_node):
        def sort_keys_last(node):
            if isinstance(node, Collectable):
                return 5
            elif isinstance(node, SokobanKey):
                return 3
            elif isinstance(node, Key):
                return 4
            elif isinstance(node, SokobanLock):
                return 2
            elif isinstance(node, Lock):
                return 1
            else:
                return 0

        solution_node_order = Node.find_all_nodes(
            mission_start_node,
            method="topological-sort",
            child_sort_method=sort_keys_last)
        solution_node_order = [
            n for n in solution_node_order if not isinstance(n, Room)
        ]
        return solution_node_order
Ejemplo n.º 21
0
    def fill_rooms_with_collectables(self, aesthetic):
        def can_node_contain_collectable(node):
            return isinstance(node, Start) or isinstance(
                node, Lock) or isinstance(node, Room)

        collectables = []
        possible_collectable_room_nodes = [
            node for node in Node.find_all_nodes(self.start)
            if can_node_contain_collectable(node)
        ]
        collectable_rooms = [
            room for room in possible_collectable_room_nodes
            if np.random.random() < aesthetic.collectable_in_room_probability
        ]
        for collectable_room in collectable_rooms:
            collectable = self.add_collectable(collectable_room)
            collectables.append(collectable)

        collectables.extend(self.fill_dead_ends())

        end_parent = next(iter(self.end.parent_s))
        self.end.remove_parent_s(end_parent)
        collectable_barrier = CollectableBarrier("B", end_parent, self.end,
                                                 collectables)
    def test_works_with_difficult_graph(self):
        return

        start = Start()
        key_red = Key("red")
        lock_red = Lock("red")
        flippers = Key("flippers")
        water1 = Lock("water1")
        water2 = Lock("water2")
        key_green = Key("green")
        lock_green = Lock("green")
        fire_boots = Key("fireboots")
        fire1 = Lock("fire1")
        fire2 = Lock("fire2")
        end = End()
        start.add_child_s([fire2, key_red, lock_red])
        key_red.add_lock_s(lock_red)
        lock_red.add_child_s([flippers, water1])
        flippers.add_lock_s([water1, water2])
        water1.add_child_s(water2)
        water2.add_child_s([fire_boots, fire1])
        fire_boots.add_lock_s([fire1, fire2])
        fire1.add_child_s(key_green)
        key_green.add_lock_s(lock_green)
        fire2.add_child_s(lock_green)
        lock_green.add_child_s(end)

        np.random.seed(12)

        level = Level()
        w = Tiles.wall
        e = Tiles.empty

        layer = np.array(
            [[w, w, w, w, w, w, w, w, w, w, w, w, w, w, w, w, w, w, w],
             [w, e, e, w, e, e, w, e, e, w, e, e, w, e, e, w, e, e, w],
             [w, e, e, w, e, e, w, e, e, w, e, e, w, e, e, w, e, e, w],
             [w, w, w, w, w, w, w, w, w, w, w, w, w, w, w, w, w, w, w],
             [w, e, e, w, e, e, w, e, e, w, e, e, w, e, e, w, e, e, w],
             [w, e, e, w, e, e, w, e, e, w, e, e, w, e, e, w, e, e, w],
             [w, w, w, w, w, w, w, w, w, w, w, w, w, w, w, w, w, w, w],
             [w, e, e, w, e, e, w, e, e, w, e, e, w, e, e, w, e, e, w],
             [w, e, e, w, e, e, w, e, e, w, e, e, w, e, e, w, e, e, w],
             [w, w, w, w, w, w, w, w, w, w, w, w, w, w, w, w, w, w, w]],
            dtype=object)

        solution_node_order = Node.find_all_nodes(start,
                                                  method="topological-sort")

        start_time = time.time()
        aesthetic_settings = AestheticSettings()
        aesthetic_settings.mission_aesthetic.single_lock_is_hazard_probability = 0
        aesthetic_settings.mission_aesthetic.hazard_spread_probability[
            Tiles.water] = 0
        aesthetic_settings.mission_aesthetic.hazard_spread_probability[
            Tiles.fire] = 0
        was_successful = Generator.generate(
            level=level,
            size=layer.shape,
            aesthetic_settings=aesthetic_settings,
            max_retry_count=10,
            pregenerated_level_layer=layer,
            pregenerated_solution_node_order=solution_node_order)
        end_time = time.time()
        self.assertTrue(was_successful)

        Log.print(level)
        Log.print("Generated in {} seconds".format(end_time - start_time))