基于A-Star搜索算法的迷宫小游戏的设计

这篇文章是作者人工智能导论课的大作业,发出来供大家学习参考(有完整代码)。想要论文WORD文件的可以在本文资源处下载(可能还在审核)。

摘要: 本文章聚焦于基于A-Star搜索算法的迷宫小游戏设计,通过深入剖析A-Star算法的核心理论,涵盖当前代价、预估代价、启发函数等关键概念,同时结合Pygame技术的实际应用,展示了A-Star算法在路径规划中的高效和准确表现。
关键词: A-Star搜索算法,耗散值,启发函数,曼哈顿距离,Pygame

一、相关理论

A-star搜索算法是一种常用于图搜索和路径规划的启发式搜索算法。它结合了Dijkstra算法的最短路径搜索和贪婪最优化搜索的优势,通过引入一个启发式评估函数来加速搜索过程。A-Star搜索算法是在搜索A算法的基础上,对启发函数进行条件限制得来的。

(一)A搜索算法

  1. 为了尽快找到从初始节点到目标节点的一条耗散值比较小的路径,我们希望所选择的节点尽可能在最佳路径上。为了评价一个节点在最佳路径上的可能性,A算法给出了评价函数的定义: f ( n ) = g ( n ) + h ( n ) f(n)=g(n)+h(n) f(n)=g(n)+h(n)
  2. 其中 n n n为待评价的节点, g ( n ) g(n) g(n)为从初始节点 s s s到节点 n n n的最佳路径耗散值的估计值,也叫做当前代价; h ( n ) h(n) h(n)为从节点 n n n到目标节点 t t t的最佳路径耗散值的估计值,也叫做预估代价, h ( n ) h(n) h(n)即为启发函数。 f ( n ) f(n) f(n)为从初始节点 s s s经过节点 n n n到达目标节点 t t t的最佳路径耗散值的估计值。这里的耗散值指的是路径的代价,根据求解问题的不同,耗散值可以是路径的长度或者是需要的时间等。

(二)A-Star搜索算法

  1. 在A搜索算法中,由于没有对启发函数 h ( n ) h(n) h(n)做出任何规定和限制,所以A搜索算法得到的结果并不好评定。在A-Star搜索算法中,对启发函数 h ( n ) h(n) h(n)做出以下规定: h ( n ) < h ∗ ( n ) h(n)<h^*(n) h(n)<h(n)
  2. h ∗ ( n ) h^*(n) h(n)表示从节点 n n n到目标节点 t t t的所有路径中的最小耗散值,即最小代价。启发函数满足以上条件的A搜索算法就称作A-Star搜索算法,简称 A ∗ A^* A算法。 h ∗ ( n ) h^*(n) h(n)为启发函数的上限值,如果启发函数大于这个上限值,搜索算法就会出现发散,就不能保证总能找到最优解。

(三)曼哈顿距离

  1. 曼哈顿距离也称为L1范数,是空间中两点之间的距离度量方式。在二维空间中,曼哈顿距离是两点在水平和垂直方向上的距离总和,而不考虑斜线距离。在三维或更高维空间中,曼哈顿距离是各坐标差的绝对值之和。曼哈顿距离是一种常用的启发函数,对于平面网格地图,曼哈顿距离计算从当前节点到目标节点沿着方格网格的最短路径的步数。
  2. 公式: h ( n ) = ∣ c u r r e n t x − g o a l x ∣ + ∣ c u r r e n t y − g o a l y ∣ h(n)=|current_x-goal_x |+|current_y-goal_y | h(n)=currentxgoalx+currentygoaly

二、结果展示:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

三、详细代码

这里直接附上完整代码,直接放到pycharm里就能运行(要提前下载pygame包)。

import pygame  
import math  
from queue import PriorityQueue  
import tkinter as tk  
from tkinter import messagebox  # pygame初始化  
pygame.init()  # 设置窗口大小  
WIDTH = 900 # 高度与宽度一致  
WIN = pygame.display.set_mode((WIDTH, WIDTH)) # pygame窗口大小  
pygame.display.set_caption("A-star")  # 定义颜色  
RED = (255, 0, 0) # close表  
GREEN = (0, 255, 0) # open表  
BLUE = (0, 0, 255) # end  
YELLOW = (255, 255, 0) # start  
WHITE = (255, 255, 255)  
BLACK = (0, 0, 0) # 障碍  
PURPLE = (128, 0, 128) # A-star算法下的最短路径  
ORANGE = (255, 165, 0) # Start点  
GREY = (128, 128, 128) # 灰色的网格线  
PINK = (255, 0, 255) # End点  # 提示弹窗  
def show_popup_message(message):  
root = tk.Tk()  
root.withdraw() # 隐藏主窗口  # 弹出窗口  
messagebox.showinfo("A-star最短路径搜索·操作介绍", message)  # 文字内容  
message_content = "1. 第一次点击鼠标左键,放置“Sta”方块\n2. 第二次点击鼠标左键,放置“End”方块\n3. 继续点击鼠标左键,放置“障碍物”方块\n4. 选中方块点击鼠标右键,清除方块\n5. 按下空格开始寻找最短路径\n6. 按下q键清空当前页面"  # 创建方格类  
class Spot:  
def __init__(self, row, col, width, total_rows):  
self.row = row # 行  
self.col = col # 列  
self.x = row * width # 行坐标  
self.y = col * width # 列坐标  
self.color = WHITE  
self.neighbors = [] # 相邻点的列表  
self.width = width  
self.total_rows = total_rows  
self.text = "" # 用于存储文字内容  def get_pos(self):  
return self.row, self.col  def is_closed(self):  
return self.color == RED # close表  def is_open(self):  
return self.color == GREEN # open表  def is_barrier(self):  
return self.color == BLACK # 障碍  def is_start(self):  
return self.color == ORANGE # 起点  def is_end(self):  
return self.color == TURQUOISE # 终点  def make_start(self):  
self.color = ORANGE  def make_closed(self):  
self.color = RED  def make_open(self):  
self.color = GREEN  def make_barrier(self):  
self.color = BLACK  
self.text = "" # 用来清除原先留下的文本  def make_end(self):  
self.color = PINK  def make_path(self): # 回溯路径使用  
self.color = PURPLE  def make_clear(self):# 重置对应方格(重置为WHITE)  
self.color = WHITE  
self.text = "" # 用来清除原先留下的文本  def set_text(self, text): # 标记文本  
self.text = text  def draw(self, win):  
pygame.draw.rect(win, self.color, (self.x, self.y, self.width, self.width))  
if self.text:  
font = pygame.font.Font(None, 24)  
text_surface = font.render(self.text, True, WHITE)  
text_rect = text_surface.get_rect(center=(self.x + self.width // 2, self.y + self.width // 2))  
win.blit(text_surface, text_rect)  def update_neighbors(self, grid):  
self.neighbors = []  
if self.row < self.total_rows - 1 and not grid[self.row + 1][self.col].is_barrier(): # 向下搜索,添加下方格到neighbors  
self.neighbors.append(grid[self.row + 1][self.col])  if self.row > 0 and not grid[self.row - 1][self.col].is_barrier(): # 向上搜索,添加上方格到neighbors  
self.neighbors.append(grid[self.row - 1][self.col])  if self.col < self.total_rows - 1 and not grid[self.row][self.col + 1].is_barrier(): # 向右搜索,添加右方格到neighbors  
self.neighbors.append(grid[self.row][self.col + 1])  if self.col > 0 and not grid[self.row][self.col - 1].is_barrier(): # 向左搜索,添加左方格到neighbors  
self.neighbors.append(grid[self.row][self.col - 1])  def __lt__(self, other):  
return False  # 计算两个点的曼哈顿距离  
def Mh(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()  # A* 算法实现  
# 参考链接:https://www.redblobgames.com/pathfinding/a-star/introduction.html#graphs(写的很好)  
def A_star_algorithm(draw, grid, start, end):  
count = 0  
open_set = PriorityQueue() # open表,用于存储待探索的节点  
open_set.put((0, count, start)) # 将起点放入优先队列,优先级为0  
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] = Mh(start.get_pos(), end.get_pos())  open_set_hash = {start} # keep trace of the nodes  while not open_set.empty(): # open表非空  current = open_set.get()[2]  
open_set_hash.remove(current) # 移出open表  if current == end:  
reconstruct_path(came_from, end, draw)  
end.make_end()  
start.make_start()  
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 + Mh(neighbor.get_pos(), end.get_pos())  
if neighbor != start and neighbor != end :  
neighbor.set_text(str(f_score[neighbor])) # 标记总代价  
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  # 创建方格网格  
def make_grid(rows, width):  
grid = [] # 创建一个空列表,用于存储方格  
gap = width // rows # 一个单元格的大小  
for i in range(rows):  
grid.append([])  
for j in range(rows):  
spot = Spot(i, j, gap, rows)  
grid[i].append(spot)  
return grid # 返回创建的列表  # 绘制网格线  
def draw_grid(win, rows, width):  
gap = width // rows  
for i in range(rows):  
pygame.draw.line(win, GREY, (0, i * gap), (width, i * gap))  
for j in range(rows):  
pygame.draw.line(win, GREY, (j * gap, 0), (j * gap, width))  # 绘制最优路径  
def draw(win, grid, rows, width):  
win.fill(WHITE)  for row in grid:  
for spot in row:  
spot.draw(win)  draw_grid(win, rows, width)  
pygame.display.update()  # 获取鼠标点击的位置  
def get_clicked_pos(pos, rows, width):  
gap = width // rows  
y, x = pos  row = y // gap  
col = x // gap  return row, col  # 主函数  
def main(win, width):  
ROWS = 25 # 一列中方格的个数  
grid = make_grid(ROWS, width)  
# clear_flag = False # 按下空格清屏  start = None  
end = None  run = True  
started = False  show_popup_message(message_content)  
while run:  draw(win, grid, ROWS, width)  
for event in pygame.event.get():  
if event.type == pygame.QUIT:  
run = False  if started:  
continue  if pygame.mouse.get_pressed()[0]: # 左键  
pos = pygame.mouse.get_pos()  
row, col = get_clicked_pos(pos, ROWS, width)  
spot = grid[row][col]  
if not start and spot != end: # 第一次按下对应的是Star  
start = spot  
start.make_start()  
start.set_text("Sta") # 标记Start点  elif not end and spot != start: # 第二次按下对应的是End  
end = spot  
end.make_end()  
end.set_text("End") # 标记End点  elif spot != end and spot != start: # 之后按下的对应的是障碍  
spot.make_barrier()  elif pygame.mouse.get_pressed()[2]: # 右键  
pos = pygame.mouse.get_pos()  
row, col = get_clicked_pos(pos, ROWS, width)  
spot = grid[row][col]  
spot.make_clear()  
if spot == start:  
start = None  
elif spot == end:  
end = None  if event.type == pygame.KEYDOWN: # 检测按键按下  
if event.key == pygame.K_SPACE and start and end : # 空格键对应开始寻找最短路径  
for row in grid:  
for spot in row:  
if spot != start and spot != end and spot.color != BLACK:  
spot.make_clear()  for row in grid:  
for spot in row:  
spot.update_neighbors(grid)  A_star_algorithm(lambda: draw(win, grid, ROWS, width), grid, start, end)  elif event.key == pygame.K_q: # 按下英文字母q键对应清空屏幕  
start = None  
end = None  
grid = make_grid(ROWS, width)  
pygame.event.clear()  pygame.quit()  # 运行主函数  
main(WIN, WIDTH)

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python学习路线 - Python高阶技巧 - PySpark案例实战

Python学习路线 - Python高阶技巧 - PySpark案例实战 前言介绍Spark是什么Python On SparkPySparkWhy PySpark 基础准备PySpark库的安装构建PySpark执行环境入口对象PySpark的编程模型 数据输入RDD对象Python数据容器转RDD对象读取文件转RDD对象 数据计算map方法flatMap方法red…

HuggingFace库中BERTForxxx模型代码详细分析 使用BERT进行无监督预训练

HuggingFace库中BERTForxxx模型代码详细分析 使用BERT进行无监督预训练 引言 HF库封装的各种任务列举 BertModel的结构分析 BertForPreTraining的结构分析 BertForMaskedLM的结构分析 BertForNextSentencePrediction的结构分析 BertForSequenceClassification的结构分析 …

sqli.labs靶场(23关到28a关)

23、第二十三关 id1单引号闭合 找位置1 and 12 union select 1,2,3 爆库&#xff1a;1 and 12 union select 1,2,database() 爆表名&#xff1a;1 and 12 union select 1,2,group_concat(table_name) from information_schema.tables where table_schemasecurity 爆字段&#…

推动海外云手机发展的几个因素

随着科技的不断发展&#xff0c;海外云手机作为一种新兴技术&#xff0c;在未来呈现出令人瞩目的发展趋势。本文将在用户需求、技术创新和全球市场前景等方面&#xff0c;探讨海外云手机在未来的发展。 1. 用户需求的引领&#xff1a; 随着人们对移动性和便捷性的需求不断增长&…

Linux|Grep 命令的 12 个实用示例

您是否曾经遇到过在文件中查找特定字符串或模式的任务&#xff0c;但不知道从哪里开始查找&#xff1f;那么&#xff0c;grep 命令可以拯救你&#xff01; grep 是一个功能强大的文件模式搜索器&#xff0c;每个 Linux 发行版都配备了它。如果出于某种原因&#xff0c;它没有安…

JavaScript运行机制

在web前端开发中&#xff0c;JavaScript无疑是一种非常重要的编程语言。它能够为网页添加动态交互功能&#xff0c;提升用户体验。然而&#xff0c;要充分发挥JavaScript的威力&#xff0c;我们需要对它的运行机制有一定的了解。 JavaScript是一种解释执行的脚本语言&#xff…

【LeetCode力扣】单调栈解决Next Greater Number(下一个更大值)问题

目录 1、题目介绍 2、解题思路 2.1、暴力破解法 2.2、经典Next Greater Number问题解法 1、题目介绍 原题链接&#xff1a;496. 下一个更大元素 I - 力扣&#xff08;LeetCode&#xff09; 示例1&#xff1a; 输入&#xff1a;nums1 [4,1,2], nums2 [1,3,4,2].输出&…

SpringSecurity(17)——OAuth2令牌管理策略

刷新令牌策略 注意&#xff1a;刷新令牌只有在授权码模式和密码模式中才有&#xff0c;对应的指定这两种模式时&#xff0c;在类型上加上refresh_token <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-se…

Prometheus 采集Oracle监控数据

前言 oracledb_exporter是一个开源的Prometheus Exporter,用于从Oracle数据库中收集关键指标并将其暴露给Prometheus进行监控和告警。它可以将Oracle数据库的性能指标转换为Prometheus所需的格式,并提供一些默认的查询和指标。 download Oracle Oracle Windows Install …

【前端web入门第四天】02 CSS三大特性+背景图

文章目录: 1. CSS三大特性 1.1继承性 1.2 层叠性 1.3 优先级 1.3.1 优先级1.3.2 优先级-叠加计算规则 2. 背景图 2.1 背景属性2.2 背景图2.3 背景图的平铺方式2.4 背景图位置2.5 背景图缩放2.6 背景图固定2.7 背景复合属性 1. CSS三大特性 1.1继承性 什么是继承性? 子级默…

2023_中国零售业人工智能行业应用 发展图谱

01 零售人工智能行业应用发展背景 02 零售人工智能行业应用发展图谱及行业应用案例 案例&#xff1a;京东云、蓝色光标、京东言犀智能服务、腾讯企点、 案例&#xff1a;淘天集团、极睿科技、百度电商数字人直播 案例&#xff1a;中国联通、云拿科技AI智能商店&#xff1b; 0…

[设计模式Java实现附plantuml源码~结构型]实现对象的复用——享元模式

前言&#xff1a; 为什么之前写过Golang 版的设计模式&#xff0c;还在重新写Java 版&#xff1f; 答&#xff1a;因为对于我而言&#xff0c;当然也希望对正在学习的大伙有帮助。Java作为一门纯面向对象的语言&#xff0c;更适合用于学习设计模式。 为什么类图要附上uml 因为很…

【Iceberg学习二】Branch和Tag在Iceberg中的应用

Iceberg 表元数据保持一个快照日志&#xff0c;记录了对表所做的更改。快照在 Iceberg 中至关重要&#xff0c;因为它们是读者隔离和时间旅行查询的基础。为了控制元数据大小和存储成本&#xff0c;Iceberg 提供了快照生命周期管理程序&#xff0c;如 expire_snapshots&#xf…

基于Vue的移动端UI框架整理

一、Vant 官方地址&#xff1a;https://youzan.github.io/vant/#/zh-CN/ 简介&#xff1a;有赞公司开发。 特性&#xff1a;60 高质量组件、90% 单元测试覆盖率、完善的中英文文档和示例、支持按需引入、支持主题定制、支持国际化、支持 TS、支持 SSR。 特别说明&#xff1…

RabbitMQ-2.SpringAMQP

SpringAMQP 2.SpringAMQP2.1.创建Demo工程2.2.快速入门2.1.1.消息发送2.1.2.消息接收2.1.3.测试 2.3.WorkQueues模型2.2.1.消息发送2.2.2.消息接收2.2.3.测试2.2.4.能者多劳2.2.5.总结 2.4.交换机类型2.5.Fanout交换机2.5.1.声明队列和交换机2.5.2.消息发送2.5.3.消息接收2.5.4…

C语言第十八弹---指针(二)

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】 指针 1、const修饰指针 1.1、const修饰变量 1.2、const修饰指针变量 2、指针运算 2.1、指针- 整数 2.2、指针-指针 2.3、指针的关系运算 3、野指针 3.1、…

Stable Diffusion 模型下载:国风3 GuoFeng3

文章目录 模型介绍生成案例案例一案例二案例三案例四案例五案例六案例七案例八案例九案例十推荐提示词下载地址模型介绍 欢迎使用GuoFeng3模型 - 这是一个中国华丽古风风格模型,也可以说是一个古风游戏角色模型,具有2.5D的质感。 条目内

2024年Java面试题大全 面试题附答案详解,BTA内部面试题

基础篇 1、 Java语言有哪些特点 1、简单易学、有丰富的类库 2、面向对象&#xff08;Java最重要的特性&#xff0c;让程序耦合度更低&#xff0c;内聚性更高&#xff09; 阿里内部资料 基本类型 大小&#xff08;字节&#xff09; 默认值 封装类 6、Java自动装箱与拆箱 装箱就是…

Python中的while循环,知其然知其所以然

文章目录 while循环结构1.用循环打印1 ~ 100步骤解析2. 1 ~ 100的累加和3.死循环1. 用死循环的方法实现 1 ~ 100累加和 4. 单向循环(1)打印 一行十个小星星*(2)通过打印一个变量的形式,展现一行十个小星星(3)一行十个换色的星星 ★☆★☆★☆★☆★☆(4)用一个循环,打印十行十列…

Docker 一小时从入门到实战 —— Docker commands | Create your own image | vs VM ... 基本概念扫盲

Docker crash course 文章目录 Docker crash course1. What and Why of Docker?2.1 What2.2 What problem does it solve?2.2.1 before containers2.1.2 with containers 2. Docker vs Virtual Machines2.1 Difference2.2 Benefits 3. Install docker locally4. Images vs Co…