예제 #1
0
def testRandomMaze():
    import random
    import matplotlib.pyplot as plt
    import time

    start_time = time.time()

    maze = Maze()
    plt.plot(0, 0, 'go')
    for i in range(10):
        x = random.randrange(0, 100)
        y = random.randrange(0, 100)
        plt.plot(x, y, 'bo')
        if Node.find_node(x, y) < 0:
            n = Node(x, y)
            r = random.choice(list(n.registry.copy()))
            n.connect_to(r)
            plt.plot([n.x, r.x], [n.y, r.y], 'r-')
            r = random.choice(list(n.registry.copy()))
            n.connect_to(r)
            plt.plot([n.x, r.x], [n.y, r.y], 'r-')
        else:
            print("Node %s already exist at (%d,%d)" %
                  (Node.registry[Node.find_node(x, y)], x, y))

    e = random.choice(Node.registry)
    maze.mark_exit(e)
    plt.plot(e.x, e.y, 'rd')

    try:
        print(maze.find_way_out())
    except NoSolution:
        print("No solution")
    print("Time spent: " + str(time.time() - start_time))
    plt.show()
예제 #2
0
 def show_cursor_coordinate(self, event):
     "Display current cursor coordinate on top-right corner"
     self.delete('coordinate')
     x = round(event.x - self.width / 2)
     y = round(self.height / 2 - event.y)
     self.create_text(60, 20, text='x=%d, y=%d' % (x, y), tag='coordinate')
     if Node.find_node(x, y) >= 0:
         self.create_text(60,
                          40,
                          text='Node %d' % Node.find_node(x, y),
                          tag='coordinate')
예제 #3
0
        def connect_nearest_manhattan(n: Node) -> bool:
            with warnings.catch_warnings():
                warnings.filterwarnings('ignore')
                possible_y = dict_x[n.x]
                loc_y = possible_y.index(n.y)
                tc = set()  # short for to be connected

                if loc_y > 0:
                    tc.add((n.index, Node.find_node(n.x,
                                                    possible_y[loc_y - 1])))

                if loc_y < len(possible_y) - 1:
                    tc.add((n.index, Node.find_node(n.x,
                                                    possible_y[loc_y + 1])))

                possible_x = dict_y[n.y]
                loc_x = possible_x.index(n.x)

                if loc_x > 0:
                    tc.add((n.index, Node.find_node(possible_x[loc_x - 1],
                                                    n.y)))

                if loc_x < len(possible_x) - 1:
                    tc.add((n.index, Node.find_node(possible_x[loc_x + 1],
                                                    n.y)))

                for n0, n1 in sorted(tc, key=sort_key):
                    n0 = Node.registry[n0]
                    n1 = Node.registry[n1]

                    if self.connect(n0.index,
                                    n1.index,
                                    show_distance=show_distance,
                                    update=update):
                        return True

                return False
예제 #4
0
    def generate_maze(self,
                      n,
                      s=10,
                      c=0.55,
                      show_distance=True,
                      update=True,
                      show_node_num=True):
        """
        :param n: number of nodes to be generated
        :param s: size of the maze. The function will run infinitely if n>s**2
        :param c: chance of two nodes connecting each other when they don't have to
        :param update: Update canvas after each drawing
        :param show_distance: show distance on the coordinate plane between two connected nodes
        :return: None
        This function generate a maze on the coordinate plane so that
        1. there is no isolated nodes
        2. there is no diagonal connection between nodes
        3. there is no overlapping edges
        """
        _n = n
        size = s

        zoom = (
            self.coordinate_plane.height - 20
        ) // size  # scale the maze to be size*size, height should be the same as min(height,width)

        for i in range(n):  # add n of nodes to the map
            flag = False
            while not flag:
                x = random.randrange(0, size) - size // 2
                y = random.randrange(0, size) - size // 2
                if Node.find_node(x * zoom, y * zoom) < 0:
                    flag = True
                    self.add_node(x * zoom,
                                  y * zoom,
                                  update=update,
                                  show_number=show_node_num)

        # The part below is super inefficient and badly written but I DON'T CARE

        dict_x = {}  # stored value will be x:y
        dict_y = {}  # stored value will be y:x

        for x, y in Node.map_origin.keys():
            try:
                dict_x[x].append(y)
                dict_x[x].sort()
            except KeyError:
                dict_x[x] = [y]

            try:
                dict_y[y].append(x)
                dict_y[y].sort()
            except KeyError:
                dict_y[y] = [x]

        to_be_connected = set(
        )  # in a tuple (n0,n1) where n0 and n1 are index number of a node
        nodes_with_edge = set()

        for x in dict_x:
            i = 0
            while i < len(dict_x[x]) - 1:
                y0 = dict_x[x][i]
                y1 = dict_x[x][i + 1]
                if (not Node.find_node(x, y0) in nodes_with_edge
                        and not Node.find_node(x, y1) in nodes_with_edge
                    ) or random.random(
                    ) <= c:  # to ensure each node has at least one edge
                    n0 = Node.find_node(x, y0)
                    n1 = Node.find_node(x, y1)
                    to_be_connected.add((n0, n1))
                    nodes_with_edge.add(n0)
                    nodes_with_edge.add(n1)
                i += 1

        for y in dict_y:
            i = 0
            while i < len(dict_y[y]) - 1:
                x0 = dict_y[y][i]
                x1 = dict_y[y][i + 1]
                if (not Node.find_node(x0, y) in nodes_with_edge
                        and not Node.find_node(x1, y) in nodes_with_edge
                    ) or random.random(
                    ) <= c:  # to ensure each node has at least one edge
                    n0 = Node.find_node(x0, y)
                    n1 = Node.find_node(x1, y)
                    to_be_connected.add((n0, n1))
                    nodes_with_edge.add(n0)
                    nodes_with_edge.add(n1)
                i += 1

        # Try to find intersections in the maze that is not a node

        hlines = {}  # in format y:(x0,x1) where x0<x1
        vlines = {}

        for n0, n1 in to_be_connected:
            n0 = Node.registry[n0]
            n1 = Node.registry[n1]
            if n0.x == n1.x:  # this is a vertical line
                try:
                    vlines[n0.x].append((n0.y,
                                         n1.y) if n0.y < n1.y else (n1.y,
                                                                    n0.y))
                except KeyError:
                    vlines[n0.x] = [(n0.y, n1.y) if n0.y < n1.y else
                                    (n1.y, n0.y)]
            else:  # horizontal
                try:
                    hlines[n0.y].append((n0.x,
                                         n1.x) if n0.x < n1.x else (n1.x,
                                                                    n0.x))
                except KeyError:
                    hlines[n0.y] = [(n0.x, n1.x) if n0.x < n1.x else
                                    (n1.x, n0.x)]

        for x in vlines:
            for v in vlines[x]:
                y0, y1 = v  # y0<y1
                for y in hlines:
                    if y0 <= y <= y1:
                        for h in hlines[y]:
                            x0, x1 = h
                            if x0 <= x <= x1:  # this two lines intersect at (x,y)
                                if Node.find_node(x, y) < 0:
                                    n = self.add_node(
                                        x,
                                        y,
                                        update=update,
                                        show_number=show_node_num)
                                    to_be_connected.add(
                                        (n.index, Node.find_node(x, y0)))
                                    to_be_connected.add(
                                        (n.index, Node.find_node(x, y1)))
                                    to_be_connected.add(
                                        (n.index, Node.find_node(x0, y)))
                                    to_be_connected.add(
                                        (n.index, Node.find_node(x1, y)))

        dict_x = {}
        dict_y = {}

        for x, y in Node.map_origin.keys():
            try:
                dict_x[x].append(y)
                dict_x[x].sort()
            except KeyError:
                dict_x[x] = [y]

            try:
                dict_y[y].append(x)
                dict_y[y].sort()
            except KeyError:
                dict_y[y] = [x]

        def sort_key(t):  # sort the edges by length
            n0 = Node.registry[t[0]]
            n1 = Node.registry[t[1]]
            return self.calculate_distance(n0.x, n0.y, n1.x, n1.y)

        with warnings.catch_warnings():
            warnings.filterwarnings('ignore')
            for n0, n1 in sorted(to_be_connected, key=sort_key):
                self.connect(n0,
                             n1,
                             show_distance=show_distance,
                             update=update)

        def connect_nearest_manhattan(n: Node) -> bool:
            with warnings.catch_warnings():
                warnings.filterwarnings('ignore')
                possible_y = dict_x[n.x]
                loc_y = possible_y.index(n.y)
                tc = set()  # short for to be connected

                if loc_y > 0:
                    tc.add((n.index, Node.find_node(n.x,
                                                    possible_y[loc_y - 1])))

                if loc_y < len(possible_y) - 1:
                    tc.add((n.index, Node.find_node(n.x,
                                                    possible_y[loc_y + 1])))

                possible_x = dict_y[n.y]
                loc_x = possible_x.index(n.x)

                if loc_x > 0:
                    tc.add((n.index, Node.find_node(possible_x[loc_x - 1],
                                                    n.y)))

                if loc_x < len(possible_x) - 1:
                    tc.add((n.index, Node.find_node(possible_x[loc_x + 1],
                                                    n.y)))

                for n0, n1 in sorted(tc, key=sort_key):
                    n0 = Node.registry[n0]
                    n1 = Node.registry[n1]

                    if self.connect(n0.index,
                                    n1.index,
                                    show_distance=show_distance,
                                    update=update):
                        return True

                return False

        def connect_nearest(n: Node) -> bool:
            with warnings.catch_warnings():
                warnings.filterwarnings('ignore')

                for n0, n1 in sorted(zip(itertools.repeat(n), Node.registry),
                                     key=sort_key):

                    if self.connect(n0,
                                    n1,
                                    show_distance=show_distance,
                                    update=update):
                        return True

                return False

        import itertools
        for node in Node.registry.values(
        ):  # Make sure every node is connected to the main maze
            try:
                self.search_route(node, self.origin)
            except NoSolution:
                t = 0
                flag = connect_nearest_manhattan(node)
                while not flag:
                    try:
                        node = node.get_edge(
                            random.choice([k for k in node._edges.keys()])
                        ).get_other(
                            node.index
                        )  # try to connect to the main maze from its neighbours
                        flag = connect_nearest_manhattan(node)
                    except IndexError:  # An isolated node. Give up
                        print('Isolated: Giving up on node' + str(node.index))
                        break

                    t += 1
                    if t > _n:
                        print('Timeout:  Giving up on node' + str(node.index))
                        break  # attempted more than the maze size. Give up.
                else:
                    print("Succeeded: Fixed connection for node" +
                          str(node.index))