一个能够自我游戏的贪吃蛇(pygame与搜索算法)

贪吃蛇小游戏再经典不过了,作为编程爱好者,代码编译的贪吃蛇,又能有怎样的成绩呢?

带着好奇,开始!

先做一个普通的贪吃蛇游戏

引入相关package

import pygame

定义相关配置变量

# 定义字体
font = pygame.font.Font(None, 36)# 定义颜色
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)# 游戏窗口大小
WINDOW_WIDTH = 640
WINDOW_HEIGHT = 480# 贪吃蛇方格大小
CELL_SIZE = 20

初始化游戏和pygame窗口

# 初始化Pygame
pygame.init()# 创建游戏窗口
window = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
pygame.display.set_caption('贪吃蛇')

定义游戏循环中的相关变量

# 定义贪吃蛇初始位置和速度
snake_x = WINDOW_WIDTH // 2
snake_y = WINDOW_HEIGHT // 2
snake_speed_x = CELL_SIZE
snake_speed_y = 0# 定义食物初始位置
food_x = random.randint(0, WINDOW_WIDTH - CELL_SIZE) // CELL_SIZE * CELL_SIZE
food_y = random.randint(0, WINDOW_HEIGHT - CELL_SIZE) // CELL_SIZE * CELL_SIZE# 定义贪吃蛇身体
snake_body = []
snake_length = 1# 游戏主循环
running = True
game_speed = 10
clock = pygame.time.Clock()

食物生成函数

def generate_food():while True:food_x = random.randint(0, WINDOW_WIDTH - CELL_SIZE) // CELL_SIZE * CELL_SIZEfood_y = random.randint(0, WINDOW_HEIGHT - CELL_SIZE) // CELL_SIZE * CELL_SIZEif (food_x, food_y) not in snake_body:   #确保食物不会生成在蛇的身体breakreturn food_x, food_y

游戏主函数

while running:for event in pygame.event.get():if event.type == pygame.QUIT:running = Falseelif event.type == pygame.KEYDOWN:    #设置各方向移动if event.key == pygame.K_UP and snake_speed_y != CELL_SIZE:snake_speed_x = 0snake_speed_y = -CELL_SIZEelif event.key == pygame.K_DOWN and snake_speed_y != -CELL_SIZE:snake_speed_x = 0snake_speed_y = CELL_SIZEelif event.key == pygame.K_LEFT and snake_speed_x != CELL_SIZE:snake_speed_x = -CELL_SIZEsnake_speed_y = 0elif event.key == pygame.K_RIGHT and snake_speed_x != -CELL_SIZE:snake_speed_x = CELL_SIZEsnake_speed_y = 0elif event.key == pygame.K_w:   #设置为加快速度game_speed+=2elif event.key == pygame.K_s:game_speed-=2# 更新贪吃蛇位置snake_x += snake_speed_xsnake_y += snake_speed_y# 检测是否吃到食物if snake_x == food_x and snake_y == food_y:food_x ,food_y = generate_food()snake_length += 1# 更新贪吃蛇身体snake_body.append((snake_x, snake_y))if len(snake_body) > snake_length:del snake_body[0]# 检测贪吃蛇是否碰到边界或自身if snake_x < 0 or snake_x >= WINDOW_WIDTH or snake_y < 0 or snake_y >= WINDOW_HEIGHT or (snake_x, snake_y) in snake_body[:-1]:print('贪吃蛇碰到了自己')running = False# 清空窗口(这里可以设置背景颜色)window.fill(BLACK)# 绘制贪吃蛇身体和食物for x, y in snake_body:pygame.draw.rect(window, GREEN, (x, y, CELL_SIZE, CELL_SIZE))pygame.draw.rect(window, RED, (food_x, food_y, CELL_SIZE, CELL_SIZE))# 绘制分数文本score_text = font.render("Score: " + str(len(snake_body)), True, WHITE)window.blit(score_text, (10, 10))speed_text = font.render("Speed: " + str(game_speed), True, WHITE)window.blit(speed_text, (200, 10))# 刷新窗口pygame.display.flip()# 控制游戏帧率clock.tick(game_speed)

至此一个普通的贪吃蛇游戏就完成了!

给贪吃蛇加上自动挡

为了让贪吃蛇能够通过代码自行判断行走方向,我们需要额外编写一个函数,根据当前的一些状态变量,输出speed_x和speed_y 也就是他的行进方向。

设计算法

由于贪吃蛇的行进路线实际上就是一个寻路算法,也就是搜索方法。基础的可以使用广度搜索深度搜索。但在这里,博主选择使用了a*搜索算法,设计评估函数。有关a* 算法的知识,可以自行搜索。

算法中我们可以把蛇的身体当作障碍物

可以参考下面这个blog:寻路算法——A*算法详解并附带实现代码

算法的启发函数

def heuristic(x, y):# 使用曼哈顿距离作为启发式函数return abs(x - food_x) + abs(y - food_y)

对于这个启发函数,还可以进行优化让贪吃蛇的表现更好,比如考虑到蛇头附近蛇身体的数量,以免绕入死胡同。

自动挡函数

首先需要引入一个队列包

from queue import PriorityQueue
def computer_move():# 创建一个优先级队列用于A*搜索queue = PriorityQueue()queue.put((0, (snake_x, snake_y, [])))  # (priority, (x, y, path))# 创建一个集合用于记录访问过的位置visited = set()visited.add((snake_x, snake_y))# 定义可行的移动方向directions = [(CELL_SIZE, 0), (-CELL_SIZE, 0), (0, CELL_SIZE), (0, -CELL_SIZE)]while not queue.empty():_, (x, y, path) = queue.get()if (x, y) == (food_x, food_y):if path:return path[0]  # 返回路径的第一个移动方向for dx, dy in directions:new_x = x + dxnew_y = y + dyif (new_x, new_y) not in visited and is_valid_move(new_x, new_y):queue.put((heuristic(new_x, new_y), (new_x, new_y, path + [(dx, dy)])))visited.add((new_x, new_y))valid_directions = [(dx, dy) for dx, dy in directions if is_valid_move(snake_x + dx, snake_y + dy)]# 如果无法找到最优路径,返回一个随机方向return random.choice(valid_directions) if valid_directions else None

有了computer_move()函数,我们只需要修改主循环中的按键控制部分就好:

snake_speed_x, snake_speed_y = computer_move()

 最后贪吃蛇自动挡也就完成了

自动手动可切换的贪吃蛇

添加一个computer_mode变量作为贪吃蛇是否自动的依据,通过空格按键来切换自动手动。最后的完整代码如下:

import pygame
import random
from queue import PriorityQueuecomputer_mode = True# 游戏窗口大小
WINDOW_WIDTH = 640
WINDOW_HEIGHT = 480# 贪吃蛇方格大小
CELL_SIZE = 20# 初始化Pygame
pygame.init()# 创建游戏窗口
window = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
pygame.display.set_caption('贪吃蛇')# 定义字体
font = pygame.font.Font(None, 36)# 定义颜色
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)# 定义贪吃蛇初始位置和速度
snake_x = WINDOW_WIDTH // 2
snake_y = WINDOW_HEIGHT // 2
snake_speed_x = CELL_SIZE
snake_speed_y = 0# 定义食物初始位置
food_x = random.randint(0, WINDOW_WIDTH - CELL_SIZE) // CELL_SIZE * CELL_SIZE
food_y = random.randint(0, WINDOW_HEIGHT - CELL_SIZE) // CELL_SIZE * CELL_SIZE# 定义贪吃蛇身体
snake_body = []
snake_length = 1# 游戏主循环
running = True
game_speed = 10
clock = pygame.time.Clock()def generate_food():while True:food_x = random.randint(0, WINDOW_WIDTH - CELL_SIZE) // CELL_SIZE * CELL_SIZEfood_y = random.randint(0, WINDOW_HEIGHT - CELL_SIZE) // CELL_SIZE * CELL_SIZEif (food_x, food_y) not in snake_body:   #确保食物不会生成在蛇的身体breakreturn food_x, food_ydef computer_move():# 创建一个优先级队列用于A*搜索queue = PriorityQueue()queue.put((0, (snake_x, snake_y, [])))  # (priority, (x, y, path))# 创建一个集合用于记录访问过的位置visited = set()visited.add((snake_x, snake_y))# 定义可行的移动方向directions = [(CELL_SIZE, 0), (-CELL_SIZE, 0), (0, CELL_SIZE), (0, -CELL_SIZE)]while not queue.empty():_, (x, y, path) = queue.get()if (x, y) == (food_x, food_y):if path:return path[0]  # 返回路径的第一个移动方向for dx, dy in directions:new_x = x + dxnew_y = y + dyif (new_x, new_y) not in visited and is_valid_move(new_x, new_y):queue.put((heuristic(new_x, new_y), (new_x, new_y, path + [(dx, dy)])))visited.add((new_x, new_y))valid_directions = [(dx, dy) for dx, dy in directions if is_valid_move(snake_x + dx, snake_y + dy)]# 如果无法找到最优路径,返回一个随机方向return random.choice(valid_directions) if valid_directions else Nonedef heuristic(x, y):# 使用曼哈顿距离作为启发式函数return abs(x - food_x) + abs(y - food_y)def is_valid_move(x, y):if 0 <= x < WINDOW_WIDTH and 0 <= y < WINDOW_HEIGHT and (x, y) not in snake_body:return Truereturn Falsewhile running:for event in pygame.event.get():if event.type == pygame.QUIT:running = Falseelif event.type == pygame.KEYDOWN:if event.key == pygame.K_UP and snake_speed_y != CELL_SIZE:snake_speed_x = 0snake_speed_y = -CELL_SIZEcomputer_mode = Falseelif event.key == pygame.K_DOWN and snake_speed_y != -CELL_SIZE:snake_speed_x = 0snake_speed_y = CELL_SIZEcomputer_mode = Falseelif event.key == pygame.K_LEFT and snake_speed_x != CELL_SIZE:snake_speed_x = -CELL_SIZEsnake_speed_y = 0computer_mode = Falseelif event.key == pygame.K_RIGHT and snake_speed_x != -CELL_SIZE:snake_speed_x = CELL_SIZEsnake_speed_y = 0computer_mode = Falseelif event.key == pygame.K_SPACE:computer_mode = not computer_modeelif event.key == pygame.K_w:game_speed+=2elif event.key == pygame.K_s:game_speed-=2if computer_mode:snake_speed_x, snake_speed_y = computer_move()# 更新贪吃蛇位置snake_x += snake_speed_xsnake_y += snake_speed_y# 检测是否吃到食物if snake_x == food_x and snake_y == food_y:food_x ,food_y = generate_food()snake_length += 1# 更新贪吃蛇身体snake_body.append((snake_x, snake_y))if len(snake_body) > snake_length:del snake_body[0]# 检测贪吃蛇是否碰到边界或自身if snake_x < 0 or snake_x >= WINDOW_WIDTH or snake_y < 0 or snake_y >= WINDOW_HEIGHT or (snake_x, snake_y) in snake_body[:-1]:print('贪吃蛇碰到了自己')running = False# 清空窗口window.fill(BLACK)# 绘制贪吃蛇身体和食物for x, y in snake_body:pygame.draw.rect(window, GREEN, (x, y, CELL_SIZE, CELL_SIZE))pygame.draw.rect(window, RED, (food_x, food_y, CELL_SIZE, CELL_SIZE))# 绘制分数文本score_text = font.render("Score: " + str(len(snake_body)), True, WHITE)window.blit(score_text, (10, 10))speed_text = font.render("Speed: " + str(game_speed), True, WHITE)window.blit(speed_text, (200, 10))# 刷新窗口pygame.display.flip()# 控制游戏帧率clock.tick(game_speed)# 退出游戏
pygame.quit()

欢迎大佬们改进哦!

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

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

相关文章

工匠的发展与兴衰趋势-机器人篇

这是一篇纯纯调侃的博客&#xff0c;如有雷同纯属意外。 之前&#xff0c;写过&#xff1a; 从2050回顾2020&#xff0c;职业规划与技术路径&#xff08;节选&#xff09; 从2050回顾2020&#xff0c;职业规划与技术路径&#xff08;节选&#xff09;补充 未来以“工”为主的…

MediaBox音视频终端SDK已适配鸿蒙星河版(HarmonyOS NEXT)

2024年1月&#xff0c;HarmonyOS NEXT 鸿蒙星河版系统开发者预览版开放申请&#xff0c;该系统将只能安装为鸿蒙开发的原生应用&#xff0c;而不再兼容安卓应用。对此&#xff0c;阿里云MediaBox音视频终端SDK产品已实现功能的鸿蒙化迁移和重构&#xff0c;全面适配鸿蒙系统Har…

SQLiteC/C++接口详细介绍之sqlite3类(八)

返回目录&#xff1a;SQLite—免费开源数据库系列文章目录 上一篇&#xff1a;SQLiteC/C接口详细介绍之sqlite3类&#xff08;七&#xff09; 下一篇&#xff1a; SQLiteC/C接口详细介绍之sqlite3类&#xff08;八&#xff09;&#xff08;暂未发表&#xff09; 24.sqlite3_cr…

FPGA静态时序分析与约束(二)、时序分析

系列文章目录 FPGA静态时序分析与约束&#xff08;一&#xff09;、理解亚稳态 FPGA静态时序分析与约束&#xff08;三&#xff09;、读懂vivado时序报告 文章目录 系列文章目录前言一、时序分析基本概念1.1 时钟抖动1.2 时钟偏斜1.3 时钟不确定性Uncertainty1.4 建立时间和保…

开启新能源新时代,未来金江能源计划港交版上市

近年来,随着人们对环保和可持续发展的关注日益增加,新能源行业迎来了蓬勃发展的机遇。作为楚雄州领先的新能源企业,楚雄州金江能源集团有限公司凭借其卓越的技术实力和丰富的项目经验,成功地实现了在资本市场的上市。金江能源集团成功在楚雄州股票交易所挂牌上市,成为该地区首家…

JVM高频面试点(一):Java类加载过程

1.概述 在 Java 中&#xff0c;类加载过程是指将 Java 类的字节码加载到内存中&#xff0c;并转换为 Java 虚拟机能够识别和执行的数据结构的过程。类加载是 Java 虚拟机执行 Java 程序的必要步骤之一&#xff0c;它负责加载程序中用到的类和接口。下图所示是 ClassLoader 加载…

Python读取Excel工作表数据写入CSV、XML、文本

Excel工作簿是常用的表格格式&#xff0c;许多数据呈现、数据分析和数据汇报都是以Excel工作表的形式进行。然而&#xff0c;在实际的数据管理、分析或自动化流程构建过程中&#xff0c;我们常常需要将这些Excel中的数据迁移至更其他数据系统&#xff0c;或者以文本形式存储以便…

【LeetCode】升级打怪之路 Day 24:回溯算法的解题框架

今日题目&#xff1a; 46. 全排列51. N 皇后78. 子集 目录 LC 46. 全排列LC 51. N 皇后LC 78. 子集 【classic】1&#xff09;思路一2&#xff09;思路二 今天学习了回溯算法的解题框架&#xff1a;回溯算法解题套路框架 | labuladong 回溯算法的整体框架都是&#xff1a; re…

day-20 跳跃游戏 II

思路&#xff1a;用一个数字来存储到对应索引i的最少跳跃次数&#xff0c;ans[j]Math.min(ans[j],ans[i]1) code: class Solution {public int jump(int[] nums) {int nnums.length;int ans[]new int[n];for(int i0;i<n;i){ans[i]Integer.MAX_VALUE;}ans[0]0;for(int i0;i…

ThingsBoard Edge 设备连接

文章目录 一、创建设备1.创建设备配置2.创建设备 二、上传遥测1.MQTTX 工具2.上传遥测 三、属性1.属性类型2.上传客户端属性3.下载共享属性4.订阅共享数据 四、设备告警1.配置告警规则2.清除报警规则3.测试3.1.设备告警3.1.清除告警 五、规则链1.规则管理2.Edge 查看规则链 Thi…

Centos strema 9 环境部署Glusterfs9

本文档只是创建复制卷&#xff0c;分布式卷&#xff0c;分布式复制卷&#xff0c;纠删卷 操作系统 内核 角色 Ip地址 说明 CentOS Stream 9 x86_64 5.14.0-427.el9.x86_64 客户端 client 192.168.80.119 挂载存储业务机器 CentOS Stream 9 x86_64 5.14.0-427.el9.x8…

突破编程_前端_ACE编辑器(概述)

1 ACE 框架简介 ACE 框架是一个强大且灵活的前端文本编辑器框架&#xff0c;它提供了一套全面的 API 和丰富的功能&#xff0c;使得开发者能够轻松地在 Web 应用中集成功能强大的代码编辑器。ACE 编辑器不仅适用于在线代码编辑&#xff0c;还广泛应用于文档编辑、实时协作、富…