用python做贪吃蛇的课设报告(python贪吃蛇游戏设计报告)

http://www.itjxue.com  2023-03-05 15:56  来源:未知  点击次数: 

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函数用于在 游戏 结束或关卡切换时在 游戏 界面中显示提示性文字,其源代码如下:

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

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

贪吃蛇程序设计报告

#includegraphics.h

#includestdlib.h

#includedos.h

#define LEFT 0x4b00

#define RIGHT 0x4d00

#define DOWN 0x5000

#define UP 0x4800

#define ESC 0x011b

int i,key;

int score=0;

int gamespeed=32000;

struct Food /*食物的结构体*/

{

int x; /*食物的横坐标*/

int y; /*食物的纵坐标*/

int yes; /*食物是否出现的变量*/

}food;

struct Snack /*蛇的结构体*/

{

int x[N];

int y[N];

int node; /*蛇的节数*/

int direction; /*蛇的方向*/

int life; /*蛇的生命,0活着,1死亡*/

}snake;

void Init(void); /*图形驱动*/

void Close(void); /*关闭游戏函数*/

void DrawK(void); /*画图函数*/

void GameOver(void);/*输出失败函数*/

void GamePlay(); /*游戏控制函数 主要程序*/

void PrScore(void); /*分数输出函数*/

DELAY(char ch)/*调节游戏速度*/

{

if(ch=='3')

{

delay(gamespeed); /*delay是延迟函数*/

delay(gamespeed);

}

else if(ch=='2')

{

delay(gamespeed);

}

}

Menu()/*游戏开始菜单*/

{

char ch;

printf("Please choose the gamespeed:\n");

printf("1-Fast 2-Normal 3-Slow\n");

printf("\nPlease Press The numbers..\n");

do

{ch=getch();}

while(ch!='1'ch!='2'ch!='3');

clrscr();

return(ch);

}

/*主函数*/

void main(void)

{

int ch;

ch=Menu();

Init();

DrawK();

GamePlay(ch);

Close();

}

void Init(void)

{

int gd=DETECT,gm;

initgraph(gd,gm,"c:\\tc");

cleardevice();

}

void DrawK(void)

{

setcolor(11);

setlinestyle(SOLID_LINE,0,THICK_WIDTH);

for(i=50;i=600;i+=10)

{

rectangle(i,40,i+10,49); /*画出上边框*/

rectangle(i,451,i+10,460); /*画出下边框*/

}

for(i=40;i=450;i+=10)

{

rectangle(50,i,59,i+10); /*画出左边框*/

rectangle(601,i,610,i+10); /*画出右边框*/

}

}

void GamePlay(char ch)

{

randomize(); /*随机数发生器*/

food.yes=1; /*1代表要出现食物,0表示以存在食物*/

snake.life=0;

snake.direction=1;

snake.x[0]=100;snake.y[0]=100;

snake.x[1]=110;snake.y[1]=100;

snake.node=2;

PrScore();

while(1) /*可以重复游戏*/

{

while(!kbhit()) /*在没有按键的情况下蛇自己移动*/

{

if(food.yes==1) /*需要食物*/

{

food.x=rand()%400+60;

food.y=rand()%350+60; /*使用rand函数随机产生食物坐标*/

while(food.x%10!=0)

food.x++;

while(food.y%10!=0)

food.y++; /*判断食物是否出现在整格里*/

food.yes=0; /*现在有食物了*/

}

if(food.yes==0) /*有食物了就要显示出来*/

{

setcolor(GREEN);

rectangle(food.x,food.y,food.x+10,food.y-10);

}

for(i=snake.node-1;i0;i--) /*贪吃蛇的移动算法*/

{

snake.x[i]=snake.x[i-1];

snake.y[i]=snake.y[i-1]; /*贪吃蛇的身体移动算法*/

}

switch(snake.direction) /*贪吃蛇的头部移动算法,以此来控制移动*/

{

case 1:snake.x[0]+=10;break;

case 2:snake.x[0]-=10;break;

case 3:snake.y[0]-=10;break;

case 4:snake.y[0]+=10;break;

}

for(i=3;isnake.node;i++) /*判断是否头部与身体相撞*/

{

if(snake.x[i]==snake.x[0]snake.y[i]==snake.y[0])

{

GameOver();

snake.life=1;

break;

}

}

/*下面是判断是否撞到墙壁*/

if(snake.x[0]55||snake.x[0]595||snake.y[0]55||snake.y[0]455)

{

GameOver();

snake.life=1;

}

if(snake.life==1) /*如果死亡就退出循环*/

break;

if(snake.x[0]==food.xsnake.y[0]==food.y) /*判断蛇是否吃到食物*/

{

setcolor(0);

rectangle(food.x,food.y,food.x+10,food.y-10); /*吃的食物后用黑色将食物擦去*/

snake.x[snake.node]=-20;snake.y[snake.node]=-20; /*现把增加的一节放到看不到的地方去*/

snake.node++;

food.yes=1;

score+=10;

PrScore();

}

setcolor(4); /*每次移动后将后面的身体擦去*/

for(i=0;isnake.node;i++)

rectangle(snake.x[i],snake.y[i],snake.x[i]+10,snake.y[i]-10);

delay(gamespeed);

DELAY(ch);

setcolor(0);

rectangle(snake.x[snake.node-1],snake.y[snake.node-1],snake.x[snake.node-1]+10,snake.y[snake.node-1]-10);

}

if(snake.life==1)

break;

key=bioskey(0); /*接受按键*/

if(key==ESC)

break;

else

if(key==UPsnake.direction!=4)/*判断是否改变方向*/

snake.direction=3;

else

if(key==RIGHTsnake.direction!=2)

snake.direction=1;

else

if(key==LEFTsnake.direction!=1)

snake.direction=2;

else

if(key==DOWNsnake.direction!=3)

snake.direction=4;

}

}

void GameOver(void)

{

cleardevice();

setcolor(RED);

settextstyle(0,0,4);

outtextxy(200,200,"GAME OVER");

getch();

}

void PrScore(void)

{

char str[10];

setfillstyle(SOLID_FILL,YELLOW);

bar(50,15,220,35);

setcolor(6);

settextstyle(0,0,2);

sprintf(str,"scord:%d",score);

outtextxy(55,20,str);

}

void Close(void)

{

getch();

closegraph();

}

贪吃蛇

#include "graphics.h"

#include "stdio.h"

#define MAX 200

#define MAXX 30

#define MAXY 30

#define UP 18432

#define DOWN 20480

#define LEFT 19200

#define RIGHT 19712

#define ESC 283

#define ENTER 7181

#define PAGEUP 18688

#define PAGEDOWN 20736

#define KEY_U 5749

#define KEY_K 9579

#define CTRL_P 6512

#define TRUE 1

#define FALSE 0

#define GAMEINIT 1

#define GAMESTART 2

#define GAMEHAPPY 3

#define GAMEOVER 4

struct SPlace

{

int x;

int y;

int st;

} place[MAX];

int speed;

int count;

int score;

int control;

int head;

int tear;

int x,y;

int babyx,babyy;

int class;

int eat;

int game;

int gamedelay[]={5000,4000,3000,2000,1000,500,250,100};

int gamedelay2[]={1000,1};

static int hitme=TRUE,hit = TRUE;

void init(void);

void nextstatus(void);

void draw(void);

void init(void)

{

int i;

for(i=0;iMAX;i++)

{

place[i].x = 0;

place[i].y = 0;

place[i].st = FALSE;

}

place[0].st = TRUE;

place[1].st = TRUE;

place[1].x = 1;

speed = 9;

count = 0;

score = 0;

control = 4;

head = 1;

tear = 0;

x = 1;

y = 0;

babyx = rand()%MAXX;

babyy = rand()%MAXY;

eat = FALSE;

game = GAMESTART;

}

void nextstatus(void)

{

int i;

int exit;

int xx,yy;

xx = x;

yy = y;

switch(control)

{

case 1: y--; yy = y-1; break;

case 2: y++; yy = y+1; break;

case 3: x--; xx = x-1; break;

case 4: x++; xx = x+1; break;

}

hit = TRUE;

if ( ((control == 1) || (control ==2 )) ( (y 1) ||(y = MAXY-1)) ||

(((control == 3) || (control == 4)) ((x 1) ||(x = MAXX-1) ) ) )

{

hit = FALSE;

}

if ( (y 0) ||(y = MAXY) ||

(x 0) ||(x = MAXX) )

{

game = GAMEOVER;

control = 0;

return;

}

for (i = 0; i MAX; i++)

{

if ((place[i].st)

(x == place[i].x)

(y == place[i].y) )

{

game = GAMEOVER;

control = 0;

return;

}

if ((place[i].st)

(xx == place[i].x)

(yy == place[i].y) )

{

hit = FALSE;

goto OUT;

}

}

OUT:

if ( (x == babyx) (y == babyy) )

{

eat = TRUE;

count ++;

score += (1+class) * 10;

}

head ++;

if (head = MAX) head = 0;

place[head].x = x;

place[head].y = y;

place[head].st= TRUE;

if (eat == FALSE)

{

place[tear].st = FALSE;

tear ++;

if (tear = MAX) tear = 0;

}

else

{

eat = FALSE;

exit = TRUE;

while(exit)

{

babyx = rand()%MAXX;

babyy = rand()%MAXY;

exit = FALSE;

for( i = 0; i MAX; i++ )

if( (place[i].st)( place[i].x == babyx) (place[i].y == babyy))

exit ++;

}

}

if (head == tear) game = GAMEHAPPY;

}

void draw(void)

{

char temp[50];

int i,j;

for (i = 0; i MAX; i++ )

{

setfillstyle(1,9);

if (place[i].st)

bar(place[i].x*15+1,place[i].y*10+1,place[i].x*15+14,place[i].y*10+9);

}

setfillstyle(1,4);

bar(babyx*15+1,babyy*10+1,babyx*15+14,babyy*10+9);

setcolor(8);

setfillstyle(1,8);

bar(place[head].x*15+1,place[head].y*10+1,place[head].x*15+14,place[head].y*10+9);

/* for( i = 0; i = MAXX; i++ )

line( i*15,0, i*15, 10*MAXY);

for( j = 0; j = MAXY; j++ )

line( 0, j*10, 15*MAXX, j*10);

*/

rectangle(0,0,15*MAXX,10*MAXY);

sprintf(temp,"Count: %d",count);

settextstyle(1,0,2);

setcolor(8);

outtextxy(512,142,temp);

setcolor(11);

outtextxy(510,140,temp);

sprintf(temp,"1P: %d",score);

settextstyle(1,0,2);

setcolor(8);

outtextxy(512,102,temp);

setcolor(12);

outtextxy(510,100,temp);

sprintf(temp,"Class: %d",class);

setcolor(8);

outtextxy(512,182,temp);

setcolor(11);

outtextxy(510,180,temp);

}

main()

{

int pause = 0;

char temp[50];

int d,m;

int key;

int p;

static int keydown = FALSE;

int exit = FALSE;

int stchange = 0;

d = VGA;

m = VGAMED;

initgraph( d, m, "" );

setbkcolor(3);

class = 3;

init();

p = 1;

while(!exit)

{

if (kbhit())

{

key = bioskey(0);

switch(key)

{

case UP: if( (control != 2) !keydown)

control = 1;

keydown = TRUE;

break;

case DOWN: if( (control != 1) !keydown)

control = 2;

keydown = TRUE;

break;

case LEFT: if( (control != 4) !keydown)

control = 3;

keydown = TRUE;

break;

case RIGHT: if( (control != 3) !keydown)

control = 4;

keydown = TRUE;

break;

case ESC: exit = TRUE;break;

case ENTER: init();break;

case PAGEUP: class --; if (class0) class = 0; break;

case PAGEDOWN: class ++;if (class7) class = 7; break;

case KEY_U: if( ( (control ==1) ||(control ==2)) !keydown)

control = 3;

else if(( (control == 3) || (control == 4)) !keydown)

control = 1;

keydown = TRUE;

break;

case KEY_K: if( ( (control ==1) ||(control ==2)) !keydown)

control = 4;

else if(( (control == 3) || (control == 4)) !keydown)

control = 2;

keydown = TRUE;

break;

case CTRL_P:pause = 1 - pause; break;

}

}

stchange ++ ;

putpixel(0,0,0);

if (stchange gamedelay[class] + gamedelay2[hit])

{

stchange = 0;

keydown = FALSE;

p = 1 - p;

setactivepage(p);

cleardevice();

if (!pause)

nextstatus();

else

{

settextstyle(1,0,4);

setcolor(12);

outtextxy(250,100,"PAUSE");

}

draw();

if(game==GAMEOVER)

{

settextstyle(0,0,6);

setcolor(8);

outtextxy(101,101,"GAME OVER");

setcolor(15);

outtextxy(99,99,"GAME OVER");

setcolor(12);

outtextxy(100,100,"GAME OVER");

sprintf(temp,"Last Count: %d",count);

settextstyle(0,0,2);

outtextxy(200,200,temp);

}

if(game==GAMEHAPPY)

{

settextstyle(0,0,6);

setcolor(12);

outtextxy(100,300,"YOU WIN");

sprintf(temp,"Last Count: %d",count);

settextstyle(0,0,2);

outtextxy(200,200,temp);

}

setvisualpage(p);

}

}

closegraph();

}

具体的编译和界面还是要靠你。

如何用Python写一个贪吃蛇AI

但如果仅仅是贪吃蛇游戏,那么它就没有什么让人涨姿势的地方了。问题的关键在于,图片中的贪吃蛇真的很贪吃XD,它把矩形中出现的食物吃了个遍,然后华丽丽地把整个矩形填满,真心是看得赏心悦目。作为一个CSer,第一个想到的是,这东西是写程序实现的(因为,一般人干不出这事。果断是要让程序来干的)第二个想到的是,写程序该如何实现,该用什么算法?既然开始想了,就开始做。因为Talk is cheap,要show me the code才行。 (从耗子叔那学来的)开始之前,让我们再欣赏一下那只让人涨姿势的贪吃蛇吧:( 如果下面的动态图片浏览效果不佳的话,可以右键保存下来查看)语言选择Life is short, use python! 所以,根本就没多想,直接上python。最初版本先让你的程序跑起来首先,我们第一件要做的就是先不要去分析这个问题。你好歹先写个能运行起来的贪吃蛇游戏,然后再去想AI部分。这个应该很简单, c\c++也就百来行代码(如果我没记错的话。不弄复杂界面,直接在控制台下跑), python就更简单了,去掉注释和空行,5、60行代码就搞定了。而且,最最关键的,这个东西网上肯定写滥了,你没有必要重复造轮子,去弄一份来按照你的意愿改造一下就行了。简单版本我觉得直接写perfect版本不是什么好路子。因为perfect版本往往要考虑很多东西,直接上来就写这个一般是bug百出的。所以,一开始我的目标仅仅是让程序去控制贪吃蛇运动,让它去吃食物,仅此而已。现在让我们来陈述一下最初的问题:在一个矩形中,每一时刻有一个食物,贪吃蛇要在不撞到自己的条件下,找到一条路(未必要最优),然后沿着这条路运行,去享用它的美食 我们先不去想蛇会越来越长这个事实,问题基本就是,给你一个起点(蛇头)和一个终点( 食物),要避开障碍物(蛇身),从起点找到一条可行路到达终点。我们可以用的方法有:BFSDFSA*只要有选择,就先选择最简单的方案,我们现在的目标是要让程序先跑起来,优化是后话。so,从BFS开始。我们最初将蛇头位置放入队列,然后只要队列非空,就将队头位置出队,然后把它四领域内的4个点放入队列,不断地循环操作,直到到达食物的位置。这个过程中,我们需要注意几点:1.访问过的点不再访问。 2.保存每个点的父结点(即每个位置是从哪个位置走到它的,这样我们才能把可行路径找出来)。3.蛇身所在位置和四面墙不可访问。通过BFS找到食物后,只需要让蛇沿着可行路径运动即可。这个简单版本写完后,贪吃蛇就可以很欢快地运行一段时间了。看图吧:(不流畅的感觉来自录屏软件@_@)为了尽量保持简单,我用的是curses模块,直接在终端进行绘图。从上面的动态图片可以看出,每次都单纯地使用BFS,最终有一天,贪吃蛇会因为这种不顾后果的短视行为而陷入困境。而且,即使到了那个时候,它也只会BFS一种策略,导致因为当前看不到目标(食物),认为自己这辈子就这样了,破罐子破摔,最终停在它人生中的某一个点,不再前进。(我好爱讲哲理XD)BFS+Wander上一节的简单版本跑起来后,我们认识到,只教贪吃蛇一种策略是不行的。它这么笨一条蛇,你不多教它一点,它分分钟就会挂掉的。所以,我写了个Wander函数,顾名思义,当贪吃蛇陷入困境后,就别让它再BFS了,而是让它随便四处走走,散散心,思考一下人生什么的。这个就好比你困惑迷茫的时候还去工作,效率不佳不说,还可能阻碍你走出困境;相反,这时候你如果放下手中的工作,停下来,出去旅个游什么的。回来时,说不定就豁然开朗,土地平旷,屋舍俨然了。Wander函数怎么写都行,但是肯定有优劣之分。我写了两个版本,一个是在可行的范围内,朝随机方向走随机步。也就是说,蛇每次运动的方向是随机出来的,总共运动的步数也是随机的。Wander完之后,再去BFS一下,看能否吃到食物,如果可以那就皆大欢喜了。如果不行,说明思考人生的时间还不够,再Wander一下。这样过程不断地循环进行。可是就像“随机过程随机过”一样,你“随机Wander就随机挂”。会Wander的蛇确实能多走好多步。可是有一天,它就会把自己给随机到一条死路上了。陷入困境还可以Wander,进入死胡同,那可没有回滚机制。所以,第二个版本的Wander函数,我就让贪吃蛇贪到底。在BFS无解后,告诉蛇一个步数step(随机产生step),让它在空白区域以S形运动step步。这回运动方向就不随机了,而是有组织有纪律地运动。先看图,然后再说说它的问题:没错,最终还是挂掉了。S形运动也是无法让贪吃蛇避免死亡的命运。贪吃蛇可以靠S形运动多存活一段时间,可是由于它的策略是:while 没有按下ESC键: if 蛇与食物间有路径: 走起,吃食物去 else: Wander一段时间 问题就出在蛇发现它自己和食物间有路径,就二话不说跑去吃食物了。它没有考虑到,你这一去把食物给吃了后形成的局势(蛇身布局),完全就可能让你挂掉。(比如进入了一个自己蛇身围起来的封闭小空间)so,为了能让蛇活得久一些,它还要更高瞻远瞩才行。高瞻远瞩版本我们现在已经有了一个比较低端的版本,而且对问题的认识也稍微深入了一些。现在可以进行一些比较慎密和严谨的分析了。首先,让我们罗列一些问题: (像头脑风暴那样,想到什么就写下来即可)蛇和食物间有路径直接就去吃,不可取。那该怎么办?如果蛇去吃食物后,布局是安全的,是否就直接去吃?(这样最优吗?)怎样定义布局是否安全?蛇和食物之间如果没有路径,怎么办?最短路径是否最优?(这个明显不是了)那么,如果布局安全的情况下,最短路径是否最优?除了最短路径,我们还可以怎么走?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键为止。由于食物是随机出现的,所以有可能出现上面这种无解的布局。当然了,你也可以得到完满的结局,贪吃蛇把整个矩形都填充满。上面的最后一个问题,暴力法是否能得到最优序列。从上面的分析看来,可以得到,但不能保证一定得到。最后,看看高瞻远瞩的蛇是怎么跑的吧:矩形大小10*20,除去外面的边框,也就是8*18。Linux下录完屏再转成GIF格式的图片,优化前40多M,真心是没法和Windows的比。用下面的命令优化时,有一种系统在用生命做优化的感觉:convert output.gif -fuzz 10% -layers Optimize optimised.gif 最后还是拿到Windows下用AE,三下五除二用图片序列合成的动态图片 (记得要在format options里选looping,不然图片是不会循环播放的)Last but not least如果对源代码感兴趣,请戳以下的链接: Code goes here另外,本文的贪吃蛇程序使用了curses模块,类Unix系统都默认安装的,使用Windows的童鞋需要安装一下这个模

怎样从零开始用 Python 写一个贪吃蛇

主要分为3个部分: 用一个线程控制游戏的逻辑(如何移动蛇、何时会输等) 用GUI库把当前局面输出到屏幕上 想办法把用户的输入传递到控制线程上

(责任编辑:IT教学网)

更多

推荐PowerPoint文章