示例#1
0
    def create_grid(self) -> None:
        top_left = self.START_COORDS + (UP * self.GRID_OFFSET) + (
            LEFT * self.GRID_OFFSET)
        top_right = top_left + (RIGHT * self.NUM_COLUMNS * self.vertex_offset)
        bottom_left = top_left + (DOWN * self.NUM_ROWS * self.vertex_offset)
        bottom_right = top_right + (DOWN * self.NUM_ROWS * self.vertex_offset)

        self.create_wall(top_left, top_right)
        self.create_wall(top_left, bottom_left)
        self.create_wall(bottom_left, bottom_right)
        self.create_wall(top_right, bottom_right)

        for row in range(self.NUM_ROWS):
            for column in range(self.NUM_COLUMNS):
                cell = self.maze[row, column]
                for neighbor in self.maze.neighbors(cell):
                    direction = Direction.between(cell, neighbor)
                    if direction not in cell.open_walls:
                        if direction == Direction.S:
                            start_coords = top_left + (RIGHT * column * self.vertex_offset) + \
                                           (DOWN * (row + 1) * self.vertex_offset)
                            end_coords = start_coords + RIGHT * self.vertex_offset
                            self.create_wall(start_coords, end_coords)
                        elif direction == Direction.E:
                            start_coords = top_left + (RIGHT * (column + 1) * self.vertex_offset) + \
                                           (DOWN * row * self.vertex_offset)
                            end_coords = start_coords + DOWN * self.vertex_offset
                            self.create_wall(start_coords, end_coords)
示例#2
0
    def select_cell(self, row: int, column: int) -> None:
        """Select (or deselect) the maze cell at the given row and column, toggling its color and updating the path."""
        clicked_cell = self.maze[row, column]
        add = True

        if not self.path:
            if self.validate_moves and clicked_cell != self.maze.start_cell:
                # print('Path must start at (0, 0)')
                return
        else:
            last_cell = self.path[-1]
            if clicked_cell in self.path:
                if self.validate_moves and clicked_cell != last_cell:
                    # print('Can only undo the last move')
                    return
                add = False
            elif self.validate_moves and clicked_cell not in self.maze.neighbors(
                    last_cell):
                # print('Path must be continuous')
                return
            elif self.validate_moves:
                direction = Direction.between(last_cell, clicked_cell)
                if direction not in last_cell.open_walls:
                    # print(f'Invalid move (through {direction.name} wall)')
                    return

        if add:
            self.fill_cell(clicked_cell, PATH_COLOR)
            self.path.append(clicked_cell)
        else:
            self.clear_cell(clicked_cell)
            self.path = self.path[:-1]
示例#3
0
    def solve_maze(self) -> List[Cell]:
        """Find and return a path through the current maze."""
        self.prev_cells = {}
        self.junction_graph = self.construct_junction_graph()
        self.junction_graph.depth_first_search(self.maze.start_cell,
                                               self.junction_visitor)

        end_cell = self.maze.end_cell
        path = [end_cell]
        prev_cell = end_cell
        cell = self.prev_cells.get(end_cell)

        while path[-1] != self.maze.start_cell:
            if Direction.between(prev_cell, cell) is None:
                # fill in corridors
                direction = self.junction_direction(prev_cell, cell)
                neighbor = self.maze.neighbor(prev_cell, direction)
                while neighbor != cell:
                    path.append(neighbor)
                    neighbor = self.maze.neighbor(neighbor, direction)
            path.append(cell)
            prev_cell = cell
            cell = self.prev_cells.get(cell)

        return list(reversed(path))
示例#4
0
 def get_edges_to_remove(self) -> List[Line]:
     edges = []
     for wall in self.maze.walls:
         start_cell, end_cell = wall
         direction = Direction.between(start_cell, end_cell)
         if direction not in start_cell.open_walls:
             edges.append(self.edges[((start_cell.row, start_cell.column),
                                      (end_cell.row, end_cell.column))])
     return edges
示例#5
0
 def remove_edge(self, start_cell: Cell, end_cell: Cell) -> None:
     """Remove the edge between the given start cell and end cell (if rendering the maze as a graph)."""
     if self.display_mode == DisplayMode.GRAPH:
         direction = Direction.between(start_cell, end_cell)
         tag = self.get_wall_tag(start_cell.row, start_cell.column,
                                 direction)
         self.canvas.delete(tag)
         opposite_tag = self.get_wall_tag(end_cell.row, end_cell.column,
                                          direction.opposite)
         self.canvas.delete(opposite_tag)
示例#6
0
 def cell_visitor(cell: Cell) -> None:
     visited[cell] = True
     for neighbor in self.maze.neighbors(cell):
         direction = Direction.between(cell, neighbor)
         if direction in cell.open_walls and not visited[neighbor]:
             while self.is_corridor_cell(neighbor):
                 neighbor = self.maze.neighbor(neighbor, direction)
             junction_graph.add_vertex(cell)
             junction_graph.add_vertex(neighbor)
             junction_graph.add_edge(cell, neighbor)
示例#7
0
 def remove_wall(self, start_cell: Cell, end_cell: Cell) -> None:
     """Remove the wall between the given start cell and end cell, also clearing any color from the cells."""
     direction = Direction.between(start_cell, end_cell)
     wall_tag = self.get_wall_tag(start_cell.row, start_cell.column,
                                  direction)
     opposite_wall_tag = self.get_wall_tag(end_cell.row, end_cell.column,
                                           direction.opposite)
     if self.display_mode == DisplayMode.GRID:
         self.canvas.delete(wall_tag)
         self.canvas.delete(opposite_wall_tag)
         start_cell_tag = self.get_cell_tag(start_cell.row,
                                            start_cell.column)
         self.canvas.delete(start_cell_tag)
         end_cell_tag = self.get_cell_tag(end_cell.row, end_cell.column)
         self.canvas.delete(end_cell_tag)
     else:
         for tag in {wall_tag, opposite_wall_tag}:
             self.canvas.itemconfigure(tag, dash=())
示例#8
0
    def walk(self) -> List[Tuple[Cell, Direction]]:
        """Perform a random walk through unvisited cells of the maze and return the path walked."""
        start_cell = self.get_random_unvisited_cell()
        visits = {}
        cell = start_cell

        while True:
            neighbor = random.choice(list(self.maze.neighbors(cell)))  # pick a random neighbor
            direction = Direction.between(cell, neighbor)
            visits[cell] = direction
            if neighbor in self.included_cells:
                break
            cell = neighbor

        path = []
        cell = start_cell
        while cell in visits:
            direction = visits[cell]
            path.append((cell, direction))
            cell = self.maze.neighbor(cell, direction)
        return path
示例#9
0
 def create_graph(self) -> None:
     for row in range(self.NUM_ROWS):
         for column in range(self.NUM_COLUMNS):
             coords = (row, column)
             vertex = self.create_vertex(*coords)
             edges = []
             if row > 0:
                 prev_coords = (row - 1, column)
                 edges.append((self.create_edge(self.vertices[prev_coords],
                                                vertex), prev_coords))
             if column > 0:
                 prev_coords = (row, column - 1)
                 edges.append((self.create_edge(self.vertices[prev_coords],
                                                vertex), prev_coords))
             for edge, prev_coords in edges:
                 cell = self.maze[coords]
                 if self.SHOW_TREE:
                     prev_cell = self.maze[prev_coords]
                     if Direction.between(prev_cell,
                                          cell) in prev_cell.open_walls:
                         self.edges[(prev_coords, coords)] = edge
                 else:
                     self.edges[(prev_coords, coords)] = edge
示例#10
0
 def open_wall(start_cell: Cell, end_cell: Cell) -> None:
     """Open (remove) the walls between the given start and end cells, which are assumed to be adjacent."""
     direction = Direction.between(start_cell, end_cell)
     start_cell.open_walls.add(direction)
     end_cell.open_walls.add(direction.opposite)
示例#11
0
 def neighbor(self, cell: Cell, direction: Direction) -> Optional[Cell]:
     """Return the cell neighboring the given cell in the given direction, if there is one."""
     return next((n for n in self.neighbors(cell)
                  if Direction.between(cell, n) == direction), None)