class PrimGenerator(MazeGenerator): used = [] walls = [Cell(2, 1), Cell(1, 2)] @classmethod def get_divided(cls, cell, maze): # записывает в divided непосещённые клетки, соседствующие со стеной divided = [] x = cell.x y = cell.y if cls.used[x + 1][y] == 0 and maze.matrix[x + 1][y] == State.space: divided.append(Cell(x + 1, y)) if cls.used[x][y + 1] == 0 and maze.matrix[x][y + 1] == State.space: divided.append(Cell(x, y + 1)) if cls.used[x - 1][y] == 0 and maze.matrix[x - 1][y] == State.space: divided.append(Cell(x - 1, y)) if cls.used[x][y - 1] == 0 and maze.matrix[x][y - 1] == State.space: divided.append(Cell(x, y - 1)) return divided @classmethod def add_walls(cls, cell, maze): # добавляет в walls внутренние стены лабиринта, соседние с cell x = cell.x y = cell.y if x + 1 < maze.height - 1 and maze.matrix[x + 1][y] == State.wall: cls.walls.append(Cell(x + 1, y)) if y + 1 < maze.width - 1 and maze.matrix[x][y + 1] == State.wall: cls.walls.append(Cell(x, y + 1)) if x - 1 >= 1 and maze.matrix[x - 1][y] == State.wall: cls.walls.append(Cell(x - 1, y)) if y - 1 >= 1 and maze.matrix[x][y - 1] == State.wall: cls.walls.append(Cell(x, y - 1)) @classmethod @abstractmethod def create(cls, width, height, rand): maze = Maze(width, height) for i in range(maze.height): cls.used.append([0 for i in range(maze.width)]) cls.used[1][1] = 1 while len(cls.walls) > 0: num = random.randint(0, len(cls.walls) - 1) divided = cls.get_divided(cls.walls[num], maze) if len(divided) == 1: cls.used[divided[0].x][divided[0].y] = 1 maze.set(cls.walls[num], State.space) cls.add_walls(divided[0], maze) divided.clear() cls.walls.pop(num) cls.used = [] cls.walls = [Cell(2, 1), Cell(1, 2)] maze.set_doors(rand) return maze
def add_walls(cls, cell, maze): # добавляет в walls внутренние стены лабиринта, соседние с cell x = cell.x y = cell.y if x + 1 < maze.height - 1 and maze.matrix[x + 1][y] == State.wall: cls.walls.append(Cell(x + 1, y)) if y + 1 < maze.width - 1 and maze.matrix[x][y + 1] == State.wall: cls.walls.append(Cell(x, y + 1)) if x - 1 >= 1 and maze.matrix[x - 1][y] == State.wall: cls.walls.append(Cell(x - 1, y)) if y - 1 >= 1 and maze.matrix[x][y - 1] == State.wall: cls.walls.append(Cell(x, y - 1))
def get_next(cell, maze): # записывает в next соседние с cell пустые клетки next = [] x = cell.x y = cell.y if x + 1 < maze.height and maze.matrix[x + 1][y] == State.space: next.append(Cell(x + 1, y)) if y + 1 < maze.width and maze.matrix[x][y + 1] == State.space: next.append(Cell(x, y + 1)) if x - 1 >= 0 and maze.matrix[x - 1][y] == State.space: next.append(Cell(x - 1, y)) if y - 1 >= 0 and maze.matrix[x][y - 1] == State.space: next.append(Cell(x, y - 1)) return next
def get_divided(cls, cell, maze): # записывает в divided непосещённые клетки, соседствующие со стеной divided = [] x = cell.x y = cell.y if cls.used[x + 1][y] == 0 and maze.matrix[x + 1][y] == State.space: divided.append(Cell(x + 1, y)) if cls.used[x][y + 1] == 0 and maze.matrix[x][y + 1] == State.space: divided.append(Cell(x, y + 1)) if cls.used[x - 1][y] == 0 and maze.matrix[x - 1][y] == State.space: divided.append(Cell(x - 1, y)) if cls.used[x][y - 1] == 0 and maze.matrix[x][y - 1] == State.space: divided.append(Cell(x, y - 1)) return divided
def get_neighbours(cls, cell, width, height): # записывает в neighbours непосещённых соседей cell neighbours = [] x = cell.x y = cell.y if x + 2 < height and cls.used[x + 2][y] == 0: neighbours.append(Cell(x + 2, y)) if y + 2 < width and cls.used[x][y + 2] == 0: neighbours.append(Cell(x, y + 2)) if x - 2 >= 0 and cls.used[x - 2][y] == 0: neighbours.append(Cell(x - 2, y)) if y - 2 >= 0 and cls.used[x][y - 2] == 0: neighbours.append(Cell(x, y - 2)) return neighbours
def solution(maze: Maze): # решение лабиринта методом bfs maze1 = copy.deepcopy(maze) if maze1.entry == maze1.exit: maze1.set(maze.entry, State.way) return maze1 parents = [] for i in range(maze1.height): parents.append([Cell(-2, -2) for i in range(maze1.width)]) parents[maze1.entry.x][maze1.entry.y] = Cell(-1, -1) used = [] for i in range(maze1.height): used.append([0 for i in range(maze1.width)]) queue = deque() queue.appendleft(maze1.entry) used[maze.entry.x][maze.entry.y] = 1 while len(queue) > 0: curr = queue.pop() if curr == maze1.exit: prev = parents[curr.x][curr.y] maze1.set(curr, State.way) while not prev == maze1.entry: maze1.set(prev, State.way) curr = prev prev = parents[curr.x][curr.y] maze1.set(maze1.entry, State.way) break else: next = get_next(curr, maze1) for i in next: if used[i.x][i.y] == 0 and parents[curr.x][curr.y] != i: parents[i.x][i.y] = curr queue.appendleft(i) used[i.x][i.y] = 1 next.clear() if not maze1.get(maze1.exit) == State.way: return False return maze1
def create(cls, width, height, rand): maze = Maze(width, height) for i in range(maze.height): cls.used.append([0 for i in range(maze.width)]) cls.used[1][1] = 1 while len(cls.walls) > 0: num = random.randint(0, len(cls.walls) - 1) divided = cls.get_divided(cls.walls[num], maze) if len(divided) == 1: cls.used[divided[0].x][divided[0].y] = 1 maze.set(cls.walls[num], State.space) cls.add_walls(divided[0], maze) divided.clear() cls.walls.pop(num) cls.used = [] cls.walls = [Cell(2, 1), Cell(1, 2)] maze.set_doors(rand) return maze
def create(cls, width, height, rand): maze = Maze(width, height) stack = [Cell(1, 1)] for i in range(maze.height): cls.used.append([0 for i in range(maze.width)]) cls.used[1][1] = 1 curr = Cell(1, 1) while len(stack) > 0: neighbours = cls.get_neighbours(curr, maze.width, maze.height) if len(neighbours) > 0: stack.append(curr) k = neighbours[random.randint(0, len(neighbours) - 1)] new = Cell((curr.x + k.x) // 2, (curr.y + k.y) // 2) # стена между двумя клетками maze.set(new, State.space) cls.used[k.x][k.y] = 1 curr = k else: curr = stack.pop() maze.set_doors(rand) cls.used = [] return maze