首页 > 编程知识 正文

贪吃蛇python代码分析(python贪吃蛇最简单代码)

时间:2023-12-20 11:32:51 阅读:318075 作者:UPFB

本文目录一览:

100行Python代码,轻松完成贪吃蛇小游戏?

你是想让我们向你提问题?你这个放错地方了,应该发布到自己的博客或论坛上面才对

如何用Python写一个贪吃蛇AI

首先,让我们罗列一些问题: (像头脑风暴那样,想到什么就写下来即可)

蛇和食物间有路径直接就去吃,不可取。那该怎么办?

如果蛇去吃食物后,布局是安全的,是否就直接去吃?(这样最优吗?)

怎样定义布局是否安全?

蛇和食物之间如果没有路径,怎么办?

最短路径是否最优?(这个明显不是了)

那么,如果布局安全的情况下,最短路径是否最优?

除了最短路径,我们还可以怎么走?S形?最长?

怎么应对蛇身越来越长这个问题?

食物是随机出现的,有没可能出现无解的布局?

暴力法(brute force)能否得到最优序列?(让贪吃蛇尽可能地多吃食物)

只要去想,问题还挺多的。这时让我们以面向过程的思想,带着上面的问题,

把思路理一理。一开始,蛇很短(初始化长度为1),它看到了一个食物, 使用 BFS 得到矩形中每个位置到达食物的最短路径长度。在没有蛇身阻挡下,

就是曼哈顿距离。然后,我要先判断一下,贪吃蛇这一去是否安全。 所以我需要一条虚拟的蛇,它每次负责去探路。如果安全,才让真正的蛇去跑。

当然,虚拟的蛇是不会绘制出来的,它只负责模拟探路。那么, 怎么定义一个布局是安全的呢? 如果你把文章开头那张动态图片中蛇的销魂走位好好的看一下,

会发现即使到最后蛇身已经很长了,它仍然没事一般地走出了一条路。而且, 是跟着蛇尾走的!嗯,这个其实不难解释,蛇在运动的过程中,消耗蛇身,

蛇尾后面总是不断地出现新的空间。蛇短的时候还无所谓,当蛇一长, 就会发现,要想活下来,基本就只能追着蛇尾跑了。在追着蛇尾跑的过程中,

再去考虑能否安全地吃到食物。(下图是某次 BFS 后,得到的一个布局, 0 代表食物,数字代表该位置到达食物的距离,+号代表蛇头,*号代表蛇身,

-号代表蛇尾,#号代表空格,外面的一圈#号代表围墙)

# # # # # # #

# 0 1 2 3 4 #

# 1 2 3 # 5 #

# 2 3 4 - 6 #

# 3 + * * 7 #

# 4 5 6 7 8 #

# # # # # # #

经过上面的分析,我们可以将布局是否安全定义为蛇是否可以跟着蛇尾运动, 也就是蛇吃完食物后,蛇头和蛇尾间是否存在路径,如果存在,我就认为是安全的。

OK,继续。真蛇派出虚拟蛇去探路后,发现吃完食物后的布局是安全的。那么,

真蛇就直奔食物了。等等,这样的策略好吗?未必。因为蛇每运动一步, 布局就变化一次。布局一变就意味着可能存在更优解。比如因为蛇尾的消耗,

原本需要绕路才能吃到的食物,突然就出现在蛇眼前了。所以,真蛇走一步后, 更好的做法是,重新做 BFS。然后和上面一样进行安全判断,然后再走。

接下来我们来考虑一下,如果蛇和食物之间不存在路径怎么办? 上文其实已经提到了做法了,跟着蛇尾走。只要蛇和食物间不存在路径, 蛇就一直跟着蛇尾走。同样的,由于每走一步布局就会改变, 所以每走一步就重新做 BFS 得到最新布局。

好了,问题又来了。如果蛇和食物间不存在路径且蛇和蛇尾间也不存在路径,

怎么办?这个我是没办法了,选一步可行的路径来走就是了。还是一个道理, 每次只走一步,更新布局,然后再判断蛇和食物间是否有安全路径;

没有的话,蛇头和蛇尾间是否存在路径;还没有,再挑一步可行的来走。

上面列的好几个问题里都涉及到蛇的行走策略,一般而言, 我们会让蛇每次都走最短路径。这是针对蛇去吃食物的时候,

可是蛇在追自己的尾巴的时候就不能这么考虑了。我们希望的是蛇头在追蛇尾的过程中,

尽可能地慢。这样蛇头和蛇尾间才能腾出更多的空间,空间多才有得发展。 所以蛇的行走策略主要分为两种:

1. 目标是食物时,走最短路径

2. 目标是蛇尾时,走最长路径

那第三种情况呢?与食物和蛇尾都没路径存在的情况下, 这个时候本来就只是挑一步可行的步子来走,最短最长关系都不大了。

至于人为地让蛇走S形,我觉得这不是什么好策略,最初版本中已经分析过它的问题了。 (当然,除非你想使用最最无懈可击的那个版本,就是完全不管食物,

让蛇一直走S,然后在墙边留下一条过道即可。这样一来, 蛇总是可以完美地把所有食物吃完,然后占满整个空间,可是就很 boring 了。

没有任何的意思)

上面还提到一个问题:因为食物是随机出现的,有没可能出现无解的局面? 答案是:有。我运行了程序,然后把每一次布局都输出到 log,发现会有这样的情况:

# # # # # # #

# * * * * * #

# * * - 0 * #

# * * # + * #

# * * * * * #

# * * * * * #

# # # # # # #

其中,+号是蛇头,-号是蛇尾,*号是蛇身,0 是食物,#号代表空格,外面一圈# 号代表墙。这个布局上,食物已经在蛇头面前了,可是它能吃吗?不能! 因为它吃完食物后,长度加1,蛇头就会把 0 的位置填上,布局就变成:

# # # # # # #

# * * * * * #

# * * - + * #

# * * # * * #

# * * * * * #

# * * * * * #

# # # # # # #

此时,由于蛇的长度加1,蛇尾没有动,而蛇头被自己围着,挂掉了。可是, 我们却还有一个空白的格子#没有填充。按照我们之前教给蛇的策略,

面对这种情况,蛇头就只会一直追着蛇尾跑,每当它和食物有路径时, 它让虚拟的蛇跑一遍发现,得到的新布局是不安全的,所以不会去吃食物,

而是选择继续追着蛇尾跑。然后它就这样一直跑,一直跑。死循环, 直到你按 ESC 键为止。

由于食物是随机出现的,所以有可能出现上面这种无解的布局。当然了, 你也可以得到完满的结局,贪吃蛇把整个矩形都填充满。

上面的最后一个问题,暴力法是否能得到最优序列。从上面的分析看来, 可以得到,但不能保证一定得到。

最后,看看高瞻远瞩的蛇是怎么跑的吧:

python有趣的编程代码

class Point:

  row=0

  col=0

  def __init__(self, row, col):

    self.row=row

    self.col=col

  def copy(self):

    return Point(row=self.row, col=self.col)

#初始框架

import pygame

import random

#初始化

pygame.init()

W=800

H=600

ROW=30

COL=40

size=(W,H)

window=pygame.display.set_mode(size)

pygame.display.set_caption('贪吃蛇')

bg_color=(255,255,255)

snake_color=(200,200,200)

head=Point(row=int(ROW/2), col=int(COL/2))

head_color=(0,128,128)

snakes=[

  Point(row=head.row, col=head.col+1),

  Point(row=head.row, col=head.col+2),

  Point(row=head.row, col=head.col+3)

]

#生成食物

def gen_food():

  while 1:

    pos=Point(row=random.randint(0,ROW-1), col=random.randint(0,COL-1))

    #

    is_coll=False

    #是否跟蛇碰上了

    if head.row==pos.row and head.col==pos.col:

      is_coll=True

    #蛇身子

    for snake in snakes:

      if snake.row==pos.row and snake.col==pos.col:

        is_coll=True

        break

    if not is_coll:

      break

  return pos

#定义坐标

food=gen_food()

food_color=(255,255,0)

direct='left'       #left,right,up,down

#

def rect(point, color):

  cell_width=W/COL

  cell_height=H/ROW

  left=point.col*cell_width

  top=point.row*cell_height

  pygame.draw.rect(

    window, color,

    (left, top, cell_width, cell_height)

  )

  pass

#游戏循环

quit=True

clock=pygame.time.Clock()

while quit:

  #处理事件

  for event in pygame.event.get():

    if event.type==pygame.QUIT:

      quit=False

    elif event.type==pygame.KEYDOWN:

      if event.key==273 or event.key==119:

        if direct=='left' or direct=='right':

          direct='up'

      elif event.key==274 or event.key==115:

        if direct == 'left' or direct == 'right':

          direct='down'

      elif event.key==276 or event.key==97:

        if direct == 'up' or direct == 'down':

          direct='left'

      elif event.key==275 or event.key==100:

        if direct == 'up' or direct == 'down':

          direct='right'

  #吃东西

  eat=(head.row==food.row and head.col==food.col)

  #重新产生食物

  if eat:

    food = gen_food()

  #处理身子

  #1.把原来的头,插入到snakes的头上

  snakes.insert(0, head.copy())

  #2.把snakes的最后一个删掉

  if not eat:

    snakes.pop()

  #移动

  if direct=='left':

    head.col-=1

  elif direct=='right':

    head.col+=1

  elif direct=='up':

    head.row-=1

  elif direct=='down':

    head.row+=1

  #检测

  dead=False

  #1.撞墙

  if head.col0 or head.row0 or head.col=COL or head.row=ROW:

    dead=True

  #2.撞自己

  for snake in snakes:

    if head.col==snake.col and head.row==snake.row:

      dead=True

      break

  if dead:

    print('死了')

    quit=False

  #渲染——画出来

  #背景

  pygame.draw.rect(window, bg_color, (0,0,W,H))

  #蛇头

  for snake in snakes:

    rect(snake, snake_color)

  rect(head, head_color)

  rect(food, food_color)

  #

  pygame.display.flip()

  #设置帧频(速度)

  clock.tick(8)

#收尾工作

这是一个简易版贪吃蛇的代码,虽然结构简单,但是该有的功能都是完整的,可玩性也不错

Python游戏开发,Python实现贪吃蛇小游戏与吃豆豆 附带源码

Python版本: 3.6.4

相关模块:

pygame模块;

以及一些Python自带的模块。

安装Python并添加到环境变量,pip安装需要的相关模块即可。

贪吃蛇的 游戏 规则应该不需要我多做介绍了吧T_T。写个贪吃蛇 游戏 其实还是很简单的。首先,我们进行一下 游戏 初始化:

然后定义一个贪吃蛇类:

其中head_coord用来记录蛇头所在位置,而tail_coords是一个二维数组,用来记录所有蛇身的位置。一开始,贪吃蛇长为3,并且位置是随机生成的。用户通过 键来控制贪吃蛇的行动:

需要注意的是,贪吃蛇不能180 大拐弯,只能90 地拐弯。例如正在向左行动的贪吃蛇不能瞬间变成向右行动。具体而言,代码实现如下:

然后,我们需要随机生成一个食物,且需要保证该食物的位置不与贪吃蛇的位置相同:

在更新贪吃蛇的时候,如果它吃到了食物,则蛇身长加一,否则只是简单的按照给定的方向行动而不改变蛇身长度:

同时,当贪吃蛇吃到食物时,需要重新生成一个新的食物:

最后,当贪吃蛇碰到墙壁或者蛇头碰到蛇身时, 游戏 结束:

并显示一下 游戏 结束界面:

玩家通过 键控制 游戏 的主角吃豆人吃掉藏在迷宫内的所有豆子,并且不能被鬼魂抓到。

若能顺利吃完迷宫内的所有豆子并且不被鬼魂抓到,则 游戏 胜利,否则 游戏 失败。

逐步实现:

Step1:定义 游戏 精灵类

首先,让我们先来明确一下该 游戏 需要哪些 游戏 精灵类。

① 墙类

② 食物类(即豆豆)

③ 角色类

角色类包括吃豆人和鬼魂,鬼魂由电脑控制其运动轨迹,吃豆人由玩家控制其运动轨迹。

显然,其均需具备更新角色位置和改变角色运动方向的能力,其源代码如下:

Step2:设计 游戏 地图

利用Step1中定义的 游戏 精灵类,我们就可以开始设计 游戏 地图了。由于时间有限,我只写了一个关卡的 游戏 地图,有兴趣的小伙伴可以在此基础上进行扩展(在我的源代码基础上进行扩展是很方便滴~)。 游戏 地图的设计包括以下四方面内容:

① 创建墙

② 创建门(一开始关幽灵用的)

image.gif

③ 创建角色

④ 创建食物

因为食物不能和墙、门以及角色的位置重叠,所以为了方便设计 游戏 地图,要先创建完墙、门以及角色后再创建食物:

Step3:设计 游戏 主循环

接下来开始设计 游戏 主循环。首先是初始化:

然后定义主函数:

其中startLevelGame函数用于开始某一关 游戏 ,其源代码如下:

showText函数用于在 游戏 结束或关卡切换时在 游戏 界面中显示提示性文字,其源代码如下:

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。