基于python的贪吃蛇游戏设计与实现

目录
1.1 贪吃蛇游戏 1
1.2 自动寻路算法 2
3.1 运行环境介绍 3
3.2 运行方法和使用方法 3
3.2.1 程序运行 3
3.2.2 配置文件 3
3.2.3 游戏键位 4
4.1 主文件 main.py 4
5.1 常亮定义 5
5.2 Snake 类的具体实现 5
5.4 Drawer 和相关类的具体实现 7
6.4 算法实现 15
6.5 最短路算法 16
3.2运行方法和使用方法

3.2.1程序运行
使用小节 3.1介绍的方式(或其他等价方式)安装环境并运行 main.py 代码。以下假设程序已正常运行。
3.2.2配置文件
本游戏给予玩家很大的可配置性,许多参数都存放在配置文件 (config.json) 中。这里提供了一份默认 的配置文件
(代码 2), 但用户可以随意按需修改。
NOTE:在 main.py 文件的同一目录下,必须存在一份 config.json 文件,否则游戏因缺少参数而无法运行。
在配置文件中,window-width 和 window-height 分别指定游戏窗口的大小。block-size 指定游戏中一个 ‘‘块’’ 的大小(贪吃蛇每次以块为单位移动)。块必须能整除 window-width 和 window-height。speed 是 游戏速度,决定贪吃蛇的移动间隔时间(秒)。auto 指是否开启 AI 自动寻路。

3.2.3游戏键位
使用 W,S,A,D 分别控制贪吃蛇向上、下、左、右运动。使用 U 和 I 控制游戏的速度,U 加快游戏速度, I 减慢游戏速度。使用 Q 退出游戏。
(按下空格键以产生一份"output_.log" 文件,用于 debug)。
4代码文件介绍
4.1主文件 main.py

main.py 调用了其他所有的文件,是玩家直接运行的程序。
该文件使用 Snake 类和 Fruit 类存储了地图信息,使用 Pygame 绘制了游戏窗口,使用 SnakeDrawer 和
FruitDrawer 为不断变化的 snake 和 fruit 更新绘制图像。同时,Pygame 还负责监听键盘事件,响 应玩家的操控。main.py 还负责使用延时来处理游戏速度。
4.2游戏类 snake.py 和 fruit.py
Snake 类和 Fruit 类分别定义在 snake.py 和 fruit.py 上。
Snake 类存储了贪吃蛇的内部状态,例如所有蛇身所在的坐标(特别地,蛇头看做第一段蛇身),蛇的 当前方位等。Snake 类暴露了若干接口,用于设置蛇的当前走向、控制蛇向前一步,检验蛇是否处于非法状态等。
Fruit 类存储了水果的内部状态,例如水果的当前坐标。Fruit 类还实现了 generate 函数,产生下一个 水果的出现位置。由于水果不能出现在蛇身占用的格子上,故 Fruit 的 generate 函数可能会被反复调用,直到得到的结果符合游戏要求。
4.3寻路类 pather.py 和 solver.py
pather.py 是寻路类的主要模块,其中的类 PathSolve 是辅助工具,用于求出蛇头距离水果的最短路, 以及蛇头距离水果和蛇尾的最长路。
NOTE: 无向图中的两点最长路是 NP-Hard 问题,但本项目使用了近似算法,在小规模数据中取得了 等价于精确解的效果。
PathSolve 使用了广度优先搜索算法得到最短路。可以容易地将其拓展为 A-Star 算法获得更好的性能。 但广搜的性能在此处已经足够好。同时,其采用了‘‘最短路拓展”的方法找到近似最长路,具体地说,它在 最短路的基础上反复尝试将路拓展延长 2 个单位,直到无法进行任何的拓展为止。更详细的介绍见节 6。
本文转载自http://www.biyezuopin.vip/onews.asp?id=15739
solver.py 定义了 GredySolver 类。如名字所见,该类采用改良的贪心算法进行寻路。当蛇可以轻易吃 到水果时, 蛇会优先以最短路走向水果,否则,蛇会以最长路走向蛇尾。更详细的介绍见节 6。

import pygame
import json 
import timeit
import time
from solver import GreedySolver
from snake import Snake
from drawer import SnakeDrawer
from drawer import FruitDrawer
from fruit import Fruit
from pather import PathSolve
if __name__ == '__main__':
    jsdt = None
    with open('config.json', 'r') as f:
        jsdt = json.load(f)
    WIDTH = int(jsdt['window-width'])
    HEIGHT = int(jsdt['window-height'])
    BLK = int(jsdt['block-size'])
    WID_BLK = WIDTH / BLK
    HEI_BLK = HEIGHT / BLK
    if WIDTH % BLK != 0 or HEIGHT % BLK != 0:
        raise Exception('Error block-size should divide window-width and window-height')
    SPEED = float(jsdt['speed'])
    AUTO = bool(jsdt['auto'])

    pygame.init()
    logo = pygame.image.load('assets/logo.jpg')
    pygame.display.set_icon(logo)
    pygame.display.set_caption('Snake Game!')
    screen = pygame.display.set_mode((WIDTH, HEIGHT))
    screen.fill((255, 255, 255))
    pygame.display.flip()

    snake = Snake()
    snakedrawer = SnakeDrawer(screen, jsdt, snake)
    fruit = Fruit(jsdt)
    fruitdrawer = FruitDrawer(screen, jsdt, fruit)

    while snake.at(fruit.where()):
        fruit.generate()

    snakedrawer.draw()
    fruitdrawer.draw()

    running = True
    beg_time = timeit.default_timer()
    while running:
        # time.sleep(SPEED / 100)
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_w:
                    snake.turnUp()
                if event.key == pygame.K_s:
                    snake.turnDown()
                if event.key == pygame.K_a:
                    snake.turnLeft()
                if event.key == pygame.K_d:
                    snake.turnRight()
                if event.key == pygame.K_q:
                    running = False
                if event.key == pygame.K_SPACE:
                    dif = hash(snake)
                    snake.dump('output_{}.log'.format(str(abs(dif))))
                if event.key == pygame.K_RETURN:
                    AUTO = not AUTO
                if event.key == pygame.K_u:
                    SPEED *= 0.5 if AUTO else 0.8
                if event.key == pygame.K_i:
                    SPEED /= 0.5 if AUTO else 0.8
        now_time = timeit.default_timer()
        if now_time - beg_time >= SPEED:
            beg_time = now_time

            if AUTO:
                solver = GreedySolver(snake, fruit, jsdt)
                d = solver.nextDirection()
                snake.turn(d)

            # check eat fruit
            if snake.nextHead() == fruit.where():
                fruitdrawer.remove()
                snake.eatFruit()
                while snake.at(fruit.where()) or snake.nextHead() == fruit.where():
                    fruit.generate() # TODO:


            snakedrawer.next()
            fruitdrawer.draw()
            if not snake.valid():
                running = False
            x, y = snake.head()
            if x < 0 or x >= WID_BLK or y < 0 or y >= HEI_BLK:
                running = False
            pygame.display.flip()

        # do my work

    

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

猜你喜欢

转载自blog.csdn.net/sheziqiong/article/details/126660061