Ejemplo n.º 1
0
    def create(self, row_count, col_count, algorithm):
        """Creates a maze for a given row and column count."""
        if (row_count or col_count) <= 0:
            raise utils.MazeError(
                "Row or column count cannot be smaller than zero.")

        self.maze = np.zeros((2 * row_count + 1, 2 * col_count + 1, 3),
                             dtype=np.uint8)

        if algorithm == Maze.Create.C:
            return self._recursive_backtracking_c()
        if algorithm == Maze.Create.BACKTRACKING:
            return self._recursive_backtracking()
        if algorithm == Maze.Create.HUNT:
            return self._hunt_and_kill()
        if algorithm == Maze.Create.ELLER:
            return self._eller()
        if algorithm == Maze.Create.SIDEWINDER:
            return self._sidewinder()
        if algorithm == Maze.Create.PRIM:
            return self._prim()
        if algorithm == Maze.Create.KRUSKAL:
            return self._kruskal()

        raise utils.MazeError(
            "Wrong algorithm <{}>.\n"
            "Use \"Maze.Create.<algorithm>\" to choose an algorithm.".format(
                algorithm))
Ejemplo n.º 2
0
    def solve(self, start, end, algorithm):
        """Solves a maze from start to finish."""
        if self.maze is None:
            raise utils.MazeError(
                "Maze is not assigned.\n"
                "Use the \"create\" or \"load_maze\" method to create or load a maze."
            )

        start = start if start else (0, 0)
        end = end if end else (self.row_count - 1, self.col_count - 1)

        if not (0 <= start[0] < self.row_count and 0 <= start[1] < self.col_count):
            raise utils.MazeError("Start point <{}> is out of range.".format(start))
        if not (0 <= end[0] < self.row_count and 0 <= end[1] < self.col_count):
            raise utils.MazeError("End point <{}> is out of range.".format(end))

        start = tuple([x for x in start])
        end = tuple([x  for x in end])

        self.solution = self.maze.copy()

        if algorithm == Maze.Solve.C:
            return self._depth_first_search_c(start, end)
        if algorithm == Maze.Solve.DEPTH:
            return self._depth_first_search(start, end)
        if algorithm == Maze.Solve.BREADTH:
            return self._breadth_first_search(start, end)

        raise utils.MazeError(
            "Wrong algorithm <{}>.\n"
            "Use \"Algorithm.Solve.<algorithm>\" to choose an algorithm.".format(algorithm)
        )
Ejemplo n.º 3
0
    def create(self, row_count, col_count, algorithm):
        """Creates a maze for a given row and column count."""
        if (row_count or col_count) <= 0:
            raise utils.MazeError("Row or column count cannot be smaller than zero.")

        self.maze = np.zeros((row_count, col_count , 3), dtype=np.uint8)

        if algorithm == Maze.Create.KRUSKAL:
            return self._kruskal()

        raise utils.MazeError(
            "Wrong algorithm <{}>.\n"
            "Use \"Maze.Create.<algorithm>\" to choose an algorithm.".format(algorithm)
        )
Ejemplo n.º 4
0
Archivo: maze.py Proyecto: sdsitzm/maze
    def _breadth_first_search(self, start, end):
        """
        Solves a maze using breadth-first search.

        :param start: tuple with start coordinates
        :param end: tuple with end coordinates
        :return: None
        """
        visited = self.maze.copy(
        )  # List of visited cells, value of visited cell is 0
        queue = collections.deque()  # List of cells [cell, ...]
        cell = utils.stack_empty(
        )  # Tuple of current cell with according stack ((x, y), stack)

        x, y = start
        cell = utils.stack_push(cell, (x, y))
        queue.append(cell)
        visited[x, y, 0] = 0  # Mark as visited

        while queue:
            self._enqueue(queue, visited)
            if queue[0][0] == end:  # Stop if end has been found
                cell = utils.stack_push(queue[0], end)  # Push end into cell
                return utils.draw_path(self.solution, utils.stack_deque(cell))

        raise utils.MazeError("No solution found.")
Ejemplo n.º 5
0
    def load_maze(self, file_name="maze.png"):
        """Loads the maze from png."""
        if not os.path.isfile(file_name):
            raise util.MazeError(
                "Cannot load maze because <{}> does not exist.".format(
                    file_name))

        self.maze = util.downscale(np.array(Image.open(file_name)))
Ejemplo n.º 6
0
    def save_solution(self, file_name="solution.png", scale=3):
        """Saves the solution as png."""
        if self.solution is None:
            raise util.MazeError(
                "Cannot save solution because it is not assigned.\n"
                "Use the \"solve\" method to solve a maze."
            )

        Image.fromarray(util.upscale(self.solution, scale), "RGB").save(file_name, "png")
Ejemplo n.º 7
0
    def save_maze(self, file_name="maze.png", scale=3):
        """Saves the maze as png."""
        if self.maze is None:
            raise util.MazeError(
                "Cannot save maze because it is not assigned.\n"
                "Use the \"create\" or \"load_maze\" method to create or load a maze."
            )

        Image.fromarray(util.upscale(self.maze, scale), "RGB").save(file_name, "png")
Ejemplo n.º 8
0
    def col_count_with_walls(self):
        """
        Returns column count with walls.

        :return: int
        """
        try:
            return self.maze.shape[1]
        except Exception:
            raise util.MazeError(
                "Unable to get col count. Maze and solution are not assigned.")
Ejemplo n.º 9
0
    def load_maze(self, file_name="maze.png"):
        """
        Loads maze from png.

        :param file_name: file name of file to load
        :return: None
        """
        if not os.path.isfile(file_name):
            raise util.MazeError(
                "Cannot load maze because <{}> does not exist.".format(
                    file_name))

        self.maze = util.downscale(np.array(Image.open(file_name)))
Ejemplo n.º 10
0
    def _depth_first_search(self, start, end):
        """Solves a maze using depth-first search."""
        visited = self.maze.copy()  # List of visited cells, value of visited cell is 0
        stack = collections.deque()  # List of visited cells [(x, y), ...]

        x, y = start
        visited[x, y, 0] = 0  # Mark as visited

        while x and y:
            while x and y:
                stack.append((x, y))
                if (x, y) == end:  # Stop if end has been found
                    return utils.draw_path(self.solution, stack)
                x, y = self._solve_walk(x, y, visited)
            x, y = self._solve_backtrack(stack, visited)

        raise utils.MazeError("No solution found.")
Ejemplo n.º 11
0
    def _load_dll(self):
        """
        Loads C dll and sets parameter types.

        :return: None
        """
        pth = os.path.join(os.path.dirname(os.path.abspath(__file__)), "lib",
                           "maze32.dll")
        self._dll = ctypes.cdll.LoadLibrary(pth)

        try:
            ndpointer = np.ctypeslib.ndpointer(ctypes.c_uint8,
                                               flags="C_CONTIGUOUS")
        except Exception:
            raise util.MazeError(
                "Failed loading maze32.dll from <{}>".format(pth))

        self._dll.recursive_backtracking.argtypes = [
            ndpointer, ctypes.c_int, ctypes.c_int, ctypes.c_int
        ]

        self._dll.depth_first_search.argtypes = [
            ndpointer, ndpointer, ctypes.c_int, ctypes.c_int, ctypes.c_int
        ]