import pygame import random from queue import PriorityQueue import time WIDTH = 600 ROWS = 20 CELL_SIZE = WIDTH // ROWS FPS = 60 DELAY = 0 WHITE = (255, 255, 255) BLACK = (0, 0, 0) GREEN = (0, 255, 0) RED = (255, 0, 0) BLUE = (0, 0, 255) GRAY = (200, 200, 200) YELLOW = (255, 255, 0) class Cell: def __init__(self, row, col): self.row = row self.col = col self.x = col * CELL_SIZE self.y = row * CELL_SIZE self.walls = [True, True, True, True] # top, right, bottom, left self.visited = False def draw(self, win): if self.visited: pygame.draw.rect(win, WHITE, (self.x, self.y, CELL_SIZE, CELL_SIZE)) if self.walls[0]: pygame.draw.line(win, BLACK, (self.x, self.y), (self.x+CELL_SIZE, self.y), 2) if self.walls[1]: pygame.draw.line(win, BLACK, (self.x+CELL_SIZE, self.y), (self.x+CELL_SIZE, self.y+CELL_SIZE), 2) if self.walls[2]: pygame.draw.line(win, BLACK, (self.x+CELL_SIZE, self.y+CELL_SIZE), (self.x, self.y+CELL_SIZE), 2) if self.walls[3]: pygame.draw.line(win, BLACK, (self.x, self.y+CELL_SIZE), (self.x, self.y), 2) def highlight(self, win, color): pygame.draw.rect(win, color, (self.x, self.y, CELL_SIZE, CELL_SIZE)) def generate_maze(grid, current): stack = [] current.visited = True while True: neighbors = [] r, c = current.row, current.col if r > 0 and not grid[r-1][c].visited: neighbors.append(grid[r-1][c]) if r < ROWS-1 and not grid[r+1][c].visited: neighbors.append(grid[r+1][c]) if c > 0 and not grid[r][c-1].visited: neighbors.append(grid[r][c-1]) if c < ROWS-1 and not grid[r][c+1].visited: neighbors.append(grid[r][c+1]) if neighbors: next_cell = random.choice(neighbors) stack.append(current) remove_walls(current, next_cell) next_cell.visited = True current = next_cell elif stack: current = stack.pop() else: break def remove_walls(a, b): dx = a.col - b.col dy = a.row - b.row if dx == 1: a.walls[3] = False b.walls[1] = False elif dx == -1: a.walls[1] = False b.walls[3] = False if dy == 1: a.walls[0] = False b.walls[2] = False elif dy == -1: a.walls[2] = False b.walls[0] = False def heuristic(a, b): return abs(a.row - b.row) + abs(a.col - b.col) def astar(grid, start, end, win): count = 0 open_set = PriorityQueue() open_set.put((0, count, start)) came_from = {} g_score = {cell: float("inf") for row in grid for cell in row} g_score[start] = 0 f_score = {cell: float("inf") for row in grid for cell in row} f_score[start] = heuristic(start, end) open_set_hash = {start} while not open_set.empty(): for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() return [] current = open_set.get()[2] open_set_hash.remove(current) if current == end: path = [] while current in came_from: current = came_from[current] path.append(current) return path for neighbor in get_neighbors(grid, current): temp_g = g_score[current] + 1 if temp_g < g_score[neighbor]: came_from[neighbor] = current g_score[neighbor] = temp_g f_score[neighbor] = temp_g + heuristic(neighbor, end) if neighbor not in open_set_hash: count += 1 open_set.put((f_score[neighbor], count, neighbor)) open_set_hash.add(neighbor) # visualize draw_grid(win, grid) for cell in open_set_hash: cell.highlight(win, GREEN) pygame.display.update() time.sleep(DELAY) return [] def get_neighbors(grid, cell): neighbors = [] r, c = cell.row, cell.col if not cell.walls[0] and r > 0: neighbors.append(grid[r-1][c]) if not cell.walls[1] and c < ROWS-1: neighbors.append(grid[r][c+1]) if not cell.walls[2] and r < ROWS-1: neighbors.append(grid[r+1][c]) if not cell.walls[3] and c > 0: neighbors.append(grid[r][c-1]) return neighbors # --- DRAWING --- def draw_grid(win, grid): win.fill(WHITE) for row in grid: for cell in row: cell.draw(win) # --- MAIN --- def main(): global ROWS, CELL_SIZE pygame.init() win = pygame.display.set_mode((WIDTH, WIDTH)) pygame.display.set_caption("A*") clock = pygame.time.Clock() def create_maze(rows): global CELL_SIZE CELL_SIZE = WIDTH // rows grid = [[Cell(r, c) for c in range(rows)] for r in range(rows)] generate_maze(grid, grid[0][0]) return grid grid = create_maze(ROWS) start = grid[0][0] end = grid[ROWS-1][ROWS-1] path = [] running = True while running: clock.tick(FPS) draw_grid(win, grid) start.highlight(win, BLUE) end.highlight(win, RED) for cell in path: cell.highlight(win, YELLOW) pygame.display.update() for event in pygame.event.get(): if event.type == pygame.QUIT: running = False if event.type == pygame.KEYDOWN: if event.key == pygame.K_SPACE: path = astar(grid, start, end, win) if event.key == pygame.K_UP: ROWS += 1 grid = create_maze(ROWS) start = grid[0][0] end = grid[ROWS-1][ROWS-1] path = [] if event.key == pygame.K_DOWN and ROWS > 5: ROWS -= 1 grid = create_maze(ROWS) start = grid[0][0] end = grid[ROWS-1][ROWS-1] path = [] pygame.quit() if __name__ == "__main__": main()