• 基于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
    
        
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99

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

  • 相关阅读:
    FastDFS 一文读懂
    AI 帮写代码 67 元/月,GitHub Copilot 开启收费模式!
    ZigBee 3.0理论教程-通用-1-13:建网与组网
    北斗导航系统为渔船保驾护航,助力海洋渔业发展
    群晖NAS DSM7.2.1安装宝塔之后无法登陆账号密码问题解决
    AOMEI PXE Boot Free
    Rust 从入门到精通04-变量
    【正点原子STM32连载】第十二章 SYSTEM文件夹介绍 摘自【正点原子】MiniPro STM32H750 开发指南_V1.1
    HTML Component Library for Delphi
    vmware安装了centos7之后网络设置
  • 原文地址:https://blog.csdn.net/sheziqiong/article/details/126660061