def get_grid(): WINDOW = pygame.display.set_mode((settings.WIDTH, settings.WIDTH)) GRID = picasso.make_grid(settings.ROWS, settings.WIDTH) pygame.display.set_caption(settings.WINDOW_TITLE) start_pos = None end_pos = None run = True while run: picasso.draw(WINDOW, GRID) for event in pygame.event.get(): if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE): run = False elif pygame.mouse.get_pressed()[0]: row, col = picasso.get_clicked_pos(pygame.mouse.get_pos()) square = GRID[row][col] if not start_pos and square != end_pos and square.state != SquareState.WALL: start_pos = square start_pos.change_state(SquareState.START) elif not end_pos and square != start_pos and square.state != SquareState.WALL: end_pos = square end_pos.change_state(SquareState.END) elif square not in (start_pos, end_pos): square.change_state(SquareState.WALL) elif pygame.mouse.get_pressed()[2]: row, col = picasso.get_clicked_pos(pygame.mouse.get_pos()) square = GRID[row][col] square.reset() if square == start_pos: start_pos = None elif square == end_pos: end_pos = None elif event.type == pygame.KEYDOWN: if event.key == pygame.K_RETURN: if start_pos and end_pos: return GRID pygame.quit()
def find_path(): def _get_valid_neighbours(r: int, c: int): """ Find valid neighbours for a square: valid means it's not a wall, has not been visited :param r: row :param c: column :return: valid neighbours :rtype: list() """ up_neighbour = (r, c + 1) down_neighbour = (r, c - 1) left_neighbour = (r - 1, c) right_neighbour = (r + 1, c) neighbours = [up_neighbour, down_neighbour, left_neighbour, right_neighbour] v_neighbours = list() for neighbour in neighbours: r, c = neighbour if r in range(settings.ROWS) and c in range(settings.ROWS): if grid[r][c].state not in [SquareState.VISITED, SquareState.WALL, SquareState.START]: v_neighbours.append(neighbour) return v_neighbours def _get_heuristic(p1: tuple, p2: tuple): """ Get approximate distance to p2 :param p1: position 1 :param p2: end position :return: approximate distance :rtype: int """ x1, y1 = p1 x2, y2 = p2 return abs(x1 - x2) + abs(y1 - y2) def _reconstruct_path(r, c): rr, cc = r, c moves = list() while True: try: rr, cc = came_from[rr][cc].get_pos() moves.append((rr, cc)) except: moves.reverse() return moves WINDOW = pygame.display.set_mode((800, 800)) grid = Creator.get_grid() pq = PriorityQueue() end_pos = None start_pos = None start_row, start_col = None, None for row in grid: for square in row: if square.state == SquareState.START: start_pos = square.row, square.col start_row, start_col = start_pos elif square.state == SquareState.END: end_pos = square.row, square.col print() print(f'Starting position: {start_pos}') print(f'Ending position: {end_pos}') print() came_from = defaultdict(dict) g_score = defaultdict(dict) f_score = defaultdict(dict) for rq in grid: for cq in rq: r, c = cq.get_pos() g_score[r][c] = float("inf") f_score[r][c] = float("inf") g_score[start_row][start_col] = 0 f_score[start_row][start_col] = _get_heuristic(start_pos, end_pos) pq.put((f_score[start_row][start_col], grid[start_row][start_col])) finished = False while not finished: current = pq.get() current_square = current[1] current_row, current_col = current_square.get_pos() for n in _get_valid_neighbours(*current_square.get_pos()): n_row, n_col = n te_g_score = g_score[current_row][current_col] + 1 grid[n_row][n_col].change_state(SquareState.PATH) if (n_row, n_col) == end_pos: finished = True grid[n_row][n_col].change_state(SquareState.PATH) display_path = True final_moves = _reconstruct_path(current_row, current_col) final_moves.append((current_row, current_col)) final_moves.append((n_row, n_col)) print(f'Path found, took {len(final_moves)} moves') print(f'Moves: {final_moves}') print() for r, c in final_moves: grid[r][c].change_state(SquareState.PATH) picasso.draw(WINDOW, grid) sleep(0.1) while display_path: for event in pygame.event.get(): if event.type == pygame.QUIT: if event.type == pygame.QUIT or ( event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE): display_path = False break if te_g_score < g_score[n_row][n_col]: came_from[n_row][n_col] = current_square g_score[n_row][n_col] = te_g_score f_score[n_row][n_col] = g_score[n_row][n_col] + _get_heuristic((n_row, n_col), end_pos) if (f_score[n_row][n_col], grid[n_row][n_col]) not in pq.queue: pq.put((f_score[n_row][n_col], grid[n_row][n_col])) grid[n_row][n_col].change_state(SquareState.VISITED) picasso.draw(WINDOW, grid) pygame.quit()
def find_path(): def _get_valid_neighbours(r: int, c: int): """ Find valid neighbours for a square: valid means it's not a wall, has not been visited :param r: row :param c: column :return: valid neighbours :rtype: list() """ rs = r cs = c up_neighbour = (r, c + 1) down_neighbour = (r, c - 1) left_neighbour = (r - 1, c) right_neighbour = (r + 1, c) neighbours = [ up_neighbour, down_neighbour, left_neighbour, right_neighbour ] v_neighbours = list() for neighbour in neighbours: r, c = neighbour if r in range(settings.ROWS) and c in range(settings.ROWS): if grid[r][c].state not in [ SquareState.VISITED, SquareState.WALL, SquareState.START ]: v_neighbours.append(neighbour) return v_neighbours WINDOW = pygame.display.set_mode((800, 800)) grid = Creator.get_grid() finished = False for row in grid: for square in row: if square.state == SquareState.START: start_pos = square.row, square.col elif square.state == SquareState.END: end_pos = square.row, square.col print() print(f'Starting position: {start_pos}') print(f'Ending position: {end_pos}') final_moves = None q = LifoQueue() q.put([start_pos]) while not finished: moves_so_far = q.get() rx, cy = moves_so_far[len(moves_so_far) - 1] valid_neighbours = _get_valid_neighbours(rx, cy) for vn in valid_neighbours: moves_so_far_copy = moves_so_far.copy() rvn, cvn = vn moves_so_far_copy.append(vn) q.put(moves_so_far_copy) if (rvn, cvn) == end_pos: final_moves = moves_so_far_copy print() print(f'Path found, took {len(final_moves)} moves') print(f'Moves: {final_moves}') print() finished = True [ grid[r][c].change_state(SquareState.PATH) for r, c in final_moves ] picasso.draw(WINDOW, grid) display_path = True while display_path: for event in pygame.event.get(): if event.type == pygame.QUIT or ( event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE): display_path = False break grid[rvn][cvn].change_state(SquareState.VISITED) picasso.draw(WINDOW, grid) pygame.quit()
def find_path(): def _get_start_and_end_pos(): start_pos, end_pos = None, None for row in grid: for square in row: if square.state == SquareState.START: start_pos = square.row, square.col elif square.state == SquareState.END: end_pos = square.row, square.col return start_pos, end_pos def _get_valid_neighbours(r: int, c: int): """ Find valid neighbours for a square: valid means it's not a wall, has not been visited :param r: row :param c: column :return: valid neighbours :rtype: list() """ up_neighbour = (r, c + 1) down_neighbour = (r, c - 1) left_neighbour = (r - 1, c) right_neighbour = (r + 1, c) neighbours = [up_neighbour, down_neighbour, left_neighbour, right_neighbour] v_neighbours = list() for neighbour in neighbours: r, c = neighbour if r in range(settings.ROWS) and c in range(settings.ROWS): if grid[r][c].state not in [SquareState.VISITED, SquareState.WALL, SquareState.START]: v_neighbours.append(neighbour) return v_neighbours def _reconstruct_path(): path = [end_pos] current = end_pos while prev[current]: path.append(prev[current]) current = prev[current] # print(u) path.reverse() return path WINDOW = pygame.display.set_mode((800, 800)) grid = Creator.get_grid() start_pos, end_pos = _get_start_and_end_pos() print() print(f'Starting position: {start_pos}') print(f'Ending position: {end_pos}') print() dist = {} prev = {} q = list() finished = False while not finished: for row in grid: for square in row: pos = square.get_pos() dist[square.get_pos()] = float("inf") prev[square.get_pos()] = None if square.state in [SquareState.EMPTY, SquareState.START, SquareState.END]: q.append(pos) dist[start_pos] = 0 while q: u = min(q, key=dist.__getitem__) q.remove(u) for v in _get_valid_neighbours(*u): alt = dist[u] + 1 if alt < dist[v]: dist[v] = alt prev[v] = u vr, vc = v grid[vr][vc].change_state(SquareState.VISITED) if v == end_pos: q = list() break picasso.draw(WINDOW, grid) for event in pygame.event.get(): if event.type == pygame.QUIT: finished = True q = list() break path = _reconstruct_path() for square in path: row, col = square grid[row][col].change_state(SquareState.PATH) picasso.draw(WINDOW, grid) for event in pygame.event.get(): if event.type == pygame.QUIT: finished = True break print(f'Path found, took {len(path)} moves') print(f'Moves: {path}') print() pygame.quit()