【python A* pygame 格式化 自定义起点、终点、障碍】

pip install pygame

  • 空格键:运行 A* 算法。
  • Ctrl+C 键:清空路径。
  • Ctrl+S 键:保存当前地图到 map.json 文件。
  • Ctrl+L 键:从 map.json 文件加载地图。
import pygame
import json
from queue import PriorityQueue
from tkinter import messagebox, Tk

# Initialize pygame
pygame.init()

# Constants
WIDTH, HEIGHT = 800, 800
ROWS, COLS = 40, 40
CELL_SIZE = WIDTH // COLS
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
YELLOW = (255, 255, 0)
GREY = (200, 200, 200)

# Pygame setup
WIN = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("A* Pathfinding Visualization")


class Spot:
    def __init__(self, row, col):
        self.row = row
        self.col = col
        self.x = row * CELL_SIZE
        self.y = col * CELL_SIZE
        self.color = WHITE
        self.neighbors = []

    def is_closed(self):
        return self.color == RED

    def is_open(self):
        return self.color == YELLOW

    def is_barrier(self):
        return self.color == BLACK

    def is_start(self):
        return self.color == BLUE

    def is_end(self):
        return self.color == GREEN

    def reset(self):
        self.color = WHITE

    def make_start(self):
        self.color = BLUE

    def make_closed(self):
        self.color = RED

    def make_open(self):
        self.color = YELLOW

    def make_barrier(self):
        self.color = BLACK

    def make_end(self):
        self.color = GREEN

    def make_path(self):
        if not self.is_start() and not self.is_end():
            self.color = GREY

    def draw(self, win):
        pygame.draw.rect(win, self.color, (self.x, self.y, CELL_SIZE, CELL_SIZE))

    def update_neighbors(self, grid):
        self.neighbors = []
        if (
            self.row < ROWS - 1 and not grid[self.row + 1][self.col].is_barrier()
        ):  # Down
            self.neighbors.append(grid[self.row + 1][self.col])
        if self.row > 0 and not grid[self.row - 1][self.col].is_barrier():  # Up
            self.neighbors.append(grid[self.row - 1][self.col])
        if (
            self.col < COLS - 1 and not grid[self.row][self.col + 1].is_barrier()
        ):  # Right
            self.neighbors.append(grid[self.row][self.col + 1])
        if self.col > 0 and not grid[self.row][self.col - 1].is_barrier():  # Left
            self.neighbors.append(grid[self.row][self.col - 1])

    def __lt__(self, other):
        return False


# Utility functions
def h(p1, p2):
    x1, y1 = p1
    x2, y2 = p2
    return abs(x1 - x2) + abs(y1 - y2)


def reconstruct_path(came_from, current, draw):
    while current in came_from:
        current = came_from[current]
        current.make_path()
        draw()


def make_grid():
    return [[Spot(i, j) for j in range(COLS)] for i in range(ROWS)]


def draw_grid_line(win):
    for i in range(ROWS):
        pygame.draw.line(win, GREY, (0, i * CELL_SIZE), (WIDTH, i * CELL_SIZE))
        for j in range(COLS):
            pygame.draw.line(win, GREY, (j * CELL_SIZE, 0), (j * CELL_SIZE, HEIGHT))


def draw(win, grid):
    win.fill(WHITE)

    for row in grid:
        for spot in row:
            spot.draw(win)

    draw_grid_line(win)
    pygame.display.update()


def get_clicked_pos(pos):
    y, x = pos
    row = y // CELL_SIZE
    col = x // CELL_SIZE
    if 0 <= row < ROWS and 0 <= col < COLS:
        return row, col
    return None, None


def clear_grid(grid):
    for row in grid:
        for spot in row:
            if not (spot.is_start() or spot.is_end() or spot.is_barrier()):
                spot.reset()


def save_grid(grid, filename="map.json"):
    data = {"start": None, "end": None, "barriers": []}
    for row in grid:
        for spot in row:
            if spot.is_start():
                data["start"] = (spot.row, spot.col)
            elif spot.is_end():
                data["end"] = (spot.row, spot.col)
            elif spot.is_barrier():
                data["barriers"].append((spot.row, spot.col))
    try:
        with open(filename, "w", encoding="utf-8") as f:
            json.dump(data, f, indent=4, ensure_ascii=False)

        Tk().withdraw()
        messagebox.showinfo("Save Successful", "The grid has been saved successfully.")
        print("Save Successful", "The grid has been saved successfully.")
    except Exception as e:
        Tk().withdraw()
        messagebox.showerror("Save Error", f"Error saving grid: {e}")
        print(f"Error saving grid: {e}")


def load_grid(grid, filename="map.json"):
    try:
        with open(filename, "r", encoding='utf-8') as f:
            data = json.load(f)

        for row in grid:
            for spot in row:
                spot.reset()

        if data["start"]:
            start_row, start_col = data["start"]
            grid[start_row][start_col].make_start()

        if data["end"]:
            end_row, end_col = data["end"]
            grid[end_row][end_col].make_end()

        for barrier in data["barriers"]:
            barrier_row, barrier_col = barrier
            grid[barrier_row][barrier_col].make_barrier()

        Tk().withdraw()
        messagebox.showinfo("Load Successful", "The grid has been loaded successfully.")
        print('Load Successful", "The grid has been loaded successfully.')
    except (FileNotFoundError, KeyError, json.JSONDecodeError):
        Tk().withdraw()
        messagebox.showerror(
            "Load Error", "Error loading grid: Invalid or missing map file."
        )
        print("Error loading grid: Invalid or missing map file.")


# A* Algorithm
def a_star(draw, grid, start, end):
    if not start or not end or start == end:
        print("Error: Invalid start or end node.")
        return False

    count = 0
    open_set = PriorityQueue()
    open_set.put((0, count, start))
    came_from = {}

    g_score = {spot: float("inf") for row in grid for spot in row}
    g_score[start] = 0

    f_score = {spot: float("inf") for row in grid for spot in row}
    f_score[start] = h((start.row, start.col), (end.row, end.col))

    open_set_hash = {start}

    while not open_set.empty():
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()

        current = open_set.get()[2]
        open_set_hash.remove(current)

        if current == end:
            current.make_end()
            reconstruct_path(came_from, end, draw)
            return True

        for neighbor in current.neighbors:
            temp_g_score = g_score[current] + 1

            if temp_g_score < g_score[neighbor]:
                came_from[neighbor] = current
                g_score[neighbor] = temp_g_score
                f_score[neighbor] = temp_g_score + h(
                    (neighbor.row, neighbor.col), (end.row, end.col)
                )

                if neighbor not in open_set_hash:
                    count += 1
                    open_set.put((f_score[neighbor], count, neighbor))
                    open_set_hash.add(neighbor)
                    neighbor.make_open()

        draw()

        if current != start:
            current.make_closed()

    return False


# Main function
def main(win):
    grid = make_grid()

    start = None
    end = None

    running = True
    while running:
        draw(win, grid)
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False

            if pygame.mouse.get_pressed()[0]:  # Left mouse button
                pos = pygame.mouse.get_pos()
                row, col = get_clicked_pos(pos)
                if row is not None and col is not None:
                    spot = grid[row][col]
                    if not start and spot != end:
                        start = spot
                        start.make_start()
                    elif not end and spot != start:
                        end = spot
                        end.make_end()
                    elif spot != start and spot != end:
                        spot.make_barrier()

            elif pygame.mouse.get_pressed()[2]:  # Right mouse button
                pos = pygame.mouse.get_pos()
                row, col = get_clicked_pos(pos)
                if row is not None and col is not None:
                    spot = grid[row][col]
                    spot.reset()
                    if spot == start:
                        start = None
                    elif spot == end:
                        end = None

            if event.type == pygame.KEYDOWN:
                print(f"KEYDOWN")
                if event.key == pygame.K_SPACE and start and end:

                    clear_grid(grid)

                    for row in grid:
                        for spot in row:
                            spot.update_neighbors(grid)

                    a_star(lambda: draw(win, grid), grid, start, end)

                if event.key == pygame.K_c:
                    print("press ctrl+c")
                    clear_grid(grid)

                if event.key == pygame.K_s:
                    print("press ctrl+s")
                    save_grid(grid)

                if event.key == pygame.K_l:
                    print("press ctrl+l")
                    load_grid(grid)

    pygame.quit()


main(WIN)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/953037.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Mac——Docker desktop安装与使用教程

摘要 本文是一篇关于Mac系统下Docker Desktop安装与使用教程的博文。首先介绍连接WiFi网络&#xff0c;然后详细阐述了如何在Mac上安装Docker&#xff0c;包括下载地址以及不同芯片版本的选择。接着讲解了如何下载基础镜像和指定版本镜像&#xff0c;旨在帮助用户在Mac上高效使…

OpenCV的对比度受限的自适应直方图均衡化算法

OpenCV的对比度受限的自适应直方图均衡化&#xff08;CLAHE&#xff09;算法是一种图像增强技术&#xff0c;旨在改善图像的局部对比度&#xff0c;同时避免噪声的过度放大。以下是CLAHE算法的原理、步骤以及示例代码。 1 原理 CLAHE是自适应直方图均衡化&#xff08;AHE&…

解决Qt打印中文字符出现乱码

在 Windows 平台上&#xff0c;默认的控制台编码可能不是 UTF-8&#xff0c;这可能会导致中文字符的显示问题。 下面是在 Qt 应用程序中设置中文字体&#xff0c;并确保控制台输出为 UTF-8 编码&#xff1a; 1. Qt 应用程序代码 在 Qt 中&#xff0c;我们可以使用 QApplic…

腾讯云AI代码助手编程挑战赛-厨房助手之AI大厨

腾讯云AI代码助手编程挑战赛-厨房助手之AI大厨 作品简介 身处当今如火箭般迅猛发展的互联网时代&#xff0c;智能聊天助手已然化身成为提升用户体验的关键利器&#xff0c;全方位渗透至人们的数字生活。 紧紧跟随着这股汹涌澎湃的时代浪潮&#xff0c;我毅然投身于极具挑战性…

Soildworks的学习【2025/1/12】

右键空白处&#xff0c;点击选项卡&#xff0c;即可看到所有已调用的选项卡&#xff1a; 点击机械小齿轮选项卡&#xff0c;选择文档属性&#xff0c;选择GB国标&#xff1a; 之后点击单位&#xff0c;选择MMGS毫米单位&#xff1a; 窗口右下角有MMGS&#xff0c;这里也可以选择…

BUUCTF:web刷题记录(1)

目录 [极客大挑战 2019]EasySQL1 [极客大挑战 2019]Havefun1 [极客大挑战 2019]EasySQL1 根据题目以及页面内容&#xff0c;这是一个sql注入的题目。 直接就套用万能密码试试。 admin or 1 # 轻松拿到flag 换种方式也可以轻松拿到flag 我们再看一下网页源码 这段 HTML 代码…

Flask----前后端不分离-登录

文章目录 扩展模块flask-wtf 的简单使用定义用户数据模型注册与登录会话保持cookie方式session方式基于session的登录 flask-login实现登录、登出代码目录 扩展模块 flask-sqlalchmy&#xff0c;连接数据库flask-login&#xff0c;处理用户的登录&#xff0c;认证flask-sessio…

springboot + vue+elementUI图片上传流程

1.实现背景 前端上传一张图片&#xff0c;存到后端数据库&#xff0c;并将图片回显到页面上。上传组件使用现成的elementUI的el-upload。、 2.前端页面 <el-uploadclass"upload-demo"action"http://xxxx.xxx.xxx:9090/file/upload" :show-file-list&q…

深度学习张量的秩、轴和形状

深度学习张量的秩、轴和形状 秩、轴和形状是在深度学习中我们最关心的张量属性。 秩轴形状 秩、轴和形状是在深度学习中开始使用张量时我们最关心的三个属性。这些概念相互建立&#xff0c;从秩开始&#xff0c;然后是轴&#xff0c;最后构建到形状&#xff0c;所以请注意这…

Observability:将 OpenTelemetry 添加到你的 Flask 应用程序

作者&#xff1a;来自 Elastic jessgarson 待办事项列表可以帮助管理与假期计划相关的所有购物和任务。使用 Flask&#xff0c;你可以轻松创建待办事项列表应用程序&#xff0c;并使用 Elastic 作为遥测后端&#xff0c;通过 OpenTelemetry 对其进行监控。 Flask 是一个轻量级…

项目开发实践——基于SpringBoot+Vue3实现的在线考试系统(五)

文章目录 一、学生管理模块功能实现1、添加学生功能实现1.1 页面设计1.2 前端功能实现1.3 后端功能实现1.4 效果展示2、学生管理功能实现2.1 页面设计2.2 前端功能实现2.3 后端功能实现2.3.1 后端查询接口实现2.3.2 后端编辑接口实现2.3.3 后端删除接口实现2.4 效果展示二、代码…

使用Cilium/eBPF实现大规模云原生网络和安全

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 目录 抽象 1 Trip.com 云基础设施 1.1 分层架构 1.2 更多细节 2 纤毛在 Trip.com 2.1 推出时间表 2.2 自定义 2.3 优化和调整 2.3.1 解耦安装 2.3.2 避免重试/重启风暴 2.3.3 稳定性优先 2…

CTFshow—文件包含

Web78-81 Web78 这题是最基础的文件包含&#xff0c;直接?fileflag.php是不行的&#xff0c;不知道为啥&#xff0c;直接用下面我们之前在命令执行讲过的payload即可。 ?filephp://filter/readconvert.base64-encode/resourceflag.php Web79 这题是过滤了php&#xff0c;…

62.在 Vue 3 中使用 OpenLayers 设置不同的坐标点,用不同的颜色区分

前言 在现代 Web 开发中&#xff0c;地图功能已经成为许多应用的重要组成部分。OpenLayers 是一个强大的开源地图库&#xff0c;支持多种地图源和地图操作。结合 Vue 3 的响应式特性&#xff0c;我们可以轻松实现地图的交互功能。本文将详细介绍如何在 Vue 3 中使用 OpenLayer…

Spring 项目 基于 Tomcat容器进行部署

文章目录 一、前置知识二、项目部署1. 将写好的 Spring 项目先打包成 war 包2. 查看项目工件&#xff08;Artifact&#xff09;是否存在3. 配置 Tomcat3.1 添加一个本地 Tomcat 容器3.2 将项目部署到 Tomcat 4. 运行项目 尽管市场上许多新项目都已经转向 Spring Boot&#xff0…

【学习笔记】数据结构(十一)

外部排序 文章目录 外部排序11.1 外存信息的存取11.2 外部排序的方法11.3 多路平衡归并的实现 - 增加k11.4 置换-选择排序 - 减少m11.5 最佳归并树 外部排序 指的是大文件的排序&#xff0c;即待排序的记录存储在外存储器 上&#xff0c;在排序过程中需进行多次的内、外存之间的…

《跟我学Spring Boot开发》系列文章索引❤(2025.01.09更新)

章节文章名备注第1节Spring Boot&#xff08;1&#xff09;基于Eclipse搭建Spring Boot开发环境环境搭建第2节Spring Boot&#xff08;2&#xff09;解决Maven下载依赖缓慢的问题给火车头提提速第3节Spring Boot&#xff08;3&#xff09;教你手工搭建Spring Boot项目纯手工玩法…

【Linux笔记】Day1

基于韩顺平老师课程记录&#xff1a; https://www.bilibili.com/video/BV1Sv411r7vd 安装CentOS 给CentOS手动分区 分为三个区&#xff1a; boot分区&#xff08;给1G就行&#xff09; 交换分区&#xff08;和内存相关&#xff0c;这里和虚拟机的内存2G一致&#xff09; …

【网络】:网络编程套接字

目录 源IP地址和目的IP地址 源MAC地址和目的MAC地址 源端口号和目的端口号 端口号 VS 进程ID TCP协议和UDP协议 网络字节序 字符串IP和整数IP相互转换 查看当前网络的状态 socket编程接口 socket常见API 创建套接字 绑定端口号 发送数据 接收数据 sockaddr结构…

使用 Multer 上传图片到阿里云 OSS

文件上传到哪里更好&#xff1f; 上传到服务器本地 上传到服务器本地&#xff0c;这种方法在现今商业项目中&#xff0c;几乎已经见不到了。因为服务器带宽&#xff0c;磁盘 IO 都是非常有限的。将文件上传和读取放在自己服务器上&#xff0c;并不是明智的选择。 上传到云储存…