一个能够自我游戏的贪吃蛇(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_SIZE
        food_y = random.randint(0, WINDOW_HEIGHT - CELL_SIZE) // CELL_SIZE * CELL_SIZE

        if (food_x, food_y) not in snake_body:   #确保食物不会生成在蛇的身体
            break

    return food_x, food_y

游戏主函数

while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.KEYDOWN:    #设置各方向移动
            if event.key == pygame.K_UP and snake_speed_y != CELL_SIZE:
                snake_speed_x = 0
                snake_speed_y = -CELL_SIZE
            elif event.key == pygame.K_DOWN and snake_speed_y != -CELL_SIZE:
                snake_speed_x = 0
                snake_speed_y = CELL_SIZE
            elif event.key == pygame.K_LEFT and snake_speed_x != CELL_SIZE:
                snake_speed_x = -CELL_SIZE
                snake_speed_y = 0
            elif event.key == pygame.K_RIGHT and snake_speed_x != -CELL_SIZE:
                snake_speed_x = CELL_SIZE
                snake_speed_y = 0
            elif event.key == pygame.K_w:   #设置为加快速度
                game_speed+=2
            elif event.key == pygame.K_s:
                game_speed-=2
    # 更新贪吃蛇位置
    snake_x += snake_speed_x
    snake_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 + dx
            new_y = y + dy

            if (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 PriorityQueue

computer_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_SIZE
        food_y = random.randint(0, WINDOW_HEIGHT - CELL_SIZE) // CELL_SIZE * CELL_SIZE

        if (food_x, food_y) not in snake_body:   #确保食物不会生成在蛇的身体
            break

    return food_x, food_y

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 + dx
            new_y = y + dy

            if (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

def 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 True
    return False

while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_UP and snake_speed_y != CELL_SIZE:
                snake_speed_x = 0
                snake_speed_y = -CELL_SIZE
                computer_mode = False
            elif event.key == pygame.K_DOWN and snake_speed_y != -CELL_SIZE:
                snake_speed_x = 0
                snake_speed_y = CELL_SIZE
                computer_mode = False
            elif event.key == pygame.K_LEFT and snake_speed_x != CELL_SIZE:
                snake_speed_x = -CELL_SIZE
                snake_speed_y = 0
                computer_mode = False
            elif event.key == pygame.K_RIGHT and snake_speed_x != -CELL_SIZE:
                snake_speed_x = CELL_SIZE
                snake_speed_y = 0
                computer_mode = False
            elif event.key == pygame.K_SPACE:
                computer_mode = not computer_mode
            elif event.key == pygame.K_w:
                game_speed+=2
            elif event.key == pygame.K_s:
                game_speed-=2

    if computer_mode:
        snake_speed_x, snake_speed_y = computer_move()

    # 更新贪吃蛇位置
    snake_x += snake_speed_x
    snake_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()

欢迎大佬们改进哦!

  • 8
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,我可以尝试为您提供一些指导。 首先,您需要安装pygame库。您可以使用以下命令在命令行中进行安装: ``` pip install pygame ``` 然后您可以使用以下代码生成一个基本的贪吃蛇: ``` python import pygame pygame.init() # 设置游戏窗口大小 window_size = (400, 400) screen = pygame.display.set_mode(window_size) # 设置游戏标题 pygame.display.set_caption("Snake Game") # 定义颜色 white = (255, 255, 255) black = (0, 0, 0) green = (0, 255, 0) red = (255, 0, 0) # 初始化蛇的位置和长度 snake_size = 20 snake_x = 200 snake_y = 200 snake_list = [[snake_x, snake_y]] # 初始化随机食物的位置 food_x = round((random.randrange(0, 400 - snake_size) / 10)) * 10 food_y = round((random.randrange(0, 400 - snake_size) / 10)) * 10 # 游戏主循环 game_over = False while not game_over: # 获取用户键盘输入 for event in pygame.event.get(): if event.type == pygame.QUIT: game_over = True elif event.type == pygame.KEYDOWN: if event.key == pygame.K_LEFT: # 让蛇左移 pass elif event.key == pygame.K_RIGHT: # 让蛇右移 pass elif event.key == pygame.K_UP: # 让蛇上移 pass elif event.key == pygame.K_DOWN: # 让蛇下移 pass # 绘制游戏背景 screen.fill(white) # 绘制蛇和食物 pygame.draw.rect(screen, green, [food_x, food_y, snake_size, snake_size]) for x_y in snake_list: pygame.draw.rect(screen, black, [x_y[0], x_y[1], snake_size, snake_size]) # 更新蛇的位置,并检测碰撞 if snake_x == food_x and snake_y == food_y: # 如果蛇头碰到了食物,增加蛇的长度 pass # 更新屏幕 pygame.display.update() # 退出 pygame pygame.quit() ``` 这是一个简单的贪吃蛇游戏,您可以根据自己的需要进行修改和改进。如果您想要实现一个AI来抓人,那么您需要使用一些基础的算法,如深度优先搜索或贪心算法。这些算法可以帮助AI找到最短路径来抓住被追赶的人。但是,在实现这个AI之前,您需要先完整地实现贪吃蛇游戏的基本功能,以及一些高级功能,如蛇的碰撞检测和吃食物等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Freshman小白

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值