예제 #1
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([2 * x + 1 for x in start])
        end = tuple([2 * x + 1 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)
        )
예제 #2
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.ones((row_count, col_count), dtype=np.uint8) * -1

        if algorithm == Maze.Create.BACKTRACKING or algorithm == 0:
            return self._recursive_backtracking()
        # if algorithm == Maze.Create.HUNT:
        #     return self._hunt_and_kill()
        if algorithm == Maze.Create.ELLER or algorithm == 1:
            return self._eller()
        if algorithm == Maze.Create.SIDEWINDER or algorithm == 2:
            return self._sidewinder()
        if algorithm == Maze.Create.PRIM or algorithm == 3:
            return self._prim()
        if algorithm == Maze.Create.KRUSKAL or algorithm == 4:
            return self._kruskal()
        if algorithm == Maze.Create.RANDOM or algorithm == 5:
            return self._randomGenerate()

        raise utils.MazeError(
            "Wrong algorithm <{}>.\n"
            "Use \"Maze.Create.<algorithm>\" to choose an algorithm.".format(
                algorithm))
예제 #3
0
    def create(self, col_count,row_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)
        )
예제 #4
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)))
예제 #5
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")
예제 #6
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")
예제 #7
0
    def save_maze(self, file_name="maze.png", line=5, path=15):
        """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."
            )

        img = Image.fromarray(util.upscale(self.maze, line, path), "RGB")
        img.save("uncropped.png")
        print(img)
        img = PIL.ImageOps.invert(img).convert("L")
        newImage = Image.new("L", (1085, 720))
        newImage.paste(img, (0, 7, 1085, 7 + 705))
        newImage.save(file_name, "png")
        return newImage
예제 #8
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.")
예제 #9
0
    def _breadth_first_search(self, start, end):
        """Solves a maze using breadth-first search."""
        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.")