“我想玩游戏!”大佬:玩啥游戏,教你做一个智能贪吃蛇游戏

“我想玩游戏!”大佬:玩啥游戏,教你做一个智能贪吃蛇游戏
文章图片

“我想玩游戏!”大佬:玩啥游戏,教你做一个智能贪吃蛇游戏
文章图片

作者|李秋键
责编|Carol
出品|AI科技大本营(ID:rgznai100)
如果说这几年网络上最为常见的词语 , 其中必然会提到的便是人工智能 。
人工智能的发展已经影响到了我们的日常生活 , 像我们生活中的刷脸支付是用的是计算机视觉中的人脸识别;网购时商品的推荐和阅读新闻时话题的推荐也是基于用户使用记录进行搜索智能优化;以及包括电脑代替游戏玩家进行游戏等等 。
“我想玩游戏!”大佬:玩啥游戏,教你做一个智能贪吃蛇游戏
文章图片

而其中AI游戏常用的方法实际上并不是神经网络首当其冲 , 因为神经网络对于复杂游戏而言需要对电脑服务器等要求较高 , 且优化复杂 。 那么针对特定的游戏搭建机器学习算法便显得尤为重要 。
在我们生活中经常会遇到机器学习搭建AI游戏的例子 。 其中《模拟人生》系列就是最好的例子 。 没错 , 在这个游戏中 , 你细致的设置过角色的星座、性格、喜好后 , 它会按照设定进行自我行动 , 配上游戏题材 , 几乎和人类无疑 。
做到这一点 , 依靠的是“行为树” 。 行为树和此前介绍过的决策树非常相似 , 通过状态枚举、流程控制来设计游戏中人物的行为 。 只是相比决策树单纯的通过各个节点进行IF , THEN的判断 , 行为树中充满了条件节点、动作节点、选择节点、顺序节点等等更复杂的东西 。 再加上一些随机动作 , 行为树下的NPC几乎可以以假乱真 。
如下图可见:
“我想玩游戏!”大佬:玩啥游戏,教你做一个智能贪吃蛇游戏
文章图片

如上图所示 , 黄色矩形为执行节点 , 白色字体为条件节点 。 模拟人生人物在“吃饭”这一组合节点中 , 首先要判断自己是否饥饿、冰箱里是否有食物 , 如果结果都是“是” , 就会执行做饭这一行为 。
这只是针对这一个游戏而言 , 但是其原理是差不多的 。 比如我们要做的智能贪吃蛇 , 我们要做的就是首先判断果实的位置 , 然后根据蛇的头部位置可以判断出果实在哪个方位 , 从而决策出各种往哪个方向行动多少格即可 , 说白了也就是简单的加减计算而已 。
介绍到这里 , 那么下面我们开始动手搭建我们的智能游戏 。
“我想玩游戏!”大佬:玩啥游戏,教你做一个智能贪吃蛇游戏
文章图片

实验前的准备首先我们使用的python版本是3.6.5所用到的库有random , 目的很明显 , 用来随机生成果实位置;pygame是用来搭建游戏框架实现游戏整体可运行;sys是为了方便操作电脑系统的框架 , 因为其中电脑需要执行动作需要有操作权限 。
“我想玩游戏!”大佬:玩啥游戏,教你做一个智能贪吃蛇游戏
文章图片

搭建游戏框架1、初始化变量和导入库:游戏框架所涉及到的必然参数有游戏窗口的大小 , 方向的定义、以及用来存储蛇身体长度的变量等等 。 详细代码如下:
importrandomimportpygameimportsysfrompygame.localsimport*#错误码ERR=-404#屏幕大小Window_Width=800Window_Height=500#刷新频率Display_Clock=17#一块蛇身大小Cell_Size=20assertWindow_Width%Cell_Size==0assertWindow_Height%Cell_Size==0#等价的运动区域大小Cell_W=int(Window_Width/Cell_Size)Cell_H=int(Window_Height/Cell_Size)FIELD_SIZE=Cell_W*Cell_H#背景颜色Background_Color=(0,0,0)#蛇头索引Head_index=0#运动方向best_move=ERR#不同东西在矩阵里用不同的数字表示FOOD=0FREE_PLACE=(Cell_W+1)*(Cell_H+1)SNAKE_PLACE=2*FREE_PLACE#运动方向字典move_directions={'left':-1,'right':1,'up':-Cell_W,'down':Cell_W}2、游戏框架函数:这部分函数和游戏的智能性无关 , 仅仅是游戏框架必要的函数 。 其中用到的函数为了方便调用 , 我们需要预先设定好 。 其中必然需要的是关闭界面函数;得分更新函数;获取果实位置等等功能的函数 , 详细代码如下:
#关闭游戏界面
defclose_game:
pygame.quit
sys.exit
#检测玩家的按键
defCheck_PressKey:
iflen(pygame.event.get(QUIT))>0:
close_game
KeyUp_Events=pygame.event.get(KEYUP)
iflen(KeyUp_Events)==0:
returnNone
elifKeyUp_Events[0].key==K_ESCAPE:
close_game
returnKeyUp_Events[0].key
#显示当前得分
defShow_Score(score):
score_Content=Main_Font.render('得分:%s'%(score),True,(255,255,255))
score_Rect=score_Content.get_rect
score_Rect.topleft=(Window_Width-120,10)
Main_Display.blit(score_Content,score_Rect)
#获得果实位置
defGet_Apple_Location(snake_Coords):
flag=True
whileflag:
apple_location={'x':random.randint(0,Cell_W-1),'y':random.randint(0,Cell_H-1)}
ifapple_locationnotinsnake_Coords:
flag=False
returnapple_location
#显示果实
defShow_Apple(coord):
x=coord['x']*Cell_Size
y=coord['y']*Cell_Size
apple_Rect=pygame.Rect(x,y,Cell_Size,Cell_Size)
pygame.draw.rect(Main_Display,(255,0,0),apple_Rect)
#显示蛇
defShow_Snake(coords):
x=coords[0]['x']*Cell_Size
y=coords[0]['y']*Cell_Size
Snake_head_Rect=pygame.Rect(x,y,Cell_Size,Cell_Size)
pygame.draw.rect(Main_Display,(0,80,255),Snake_head_Rect)
Snake_head_Inner_Rect=pygame.Rect(x+4,y+4,Cell_Size-8,Cell_Size-8)
pygame.draw.rect(Main_Display,(0,80,255),Snake_head_Inner_Rect)
forcoordincoords[1:]:
x=coord['x']*Cell_Size
y=coord['y']*Cell_Size
Snake_part_Rect=pygame.Rect(x,y,Cell_Size,Cell_Size)
pygame.draw.rect(Main_Display,(0,155,0),Snake_part_Rect)
Snake_part_Inner_Rect=pygame.Rect(x+4,y+4,Cell_Size-8,Cell_Size-8)
pygame.draw.rect(Main_Display,(0,255,0),Snake_part_Inner_Rect)
#画网格
defdraw_Grid:
#垂直方向
forxinrange(0,Window_Width,Cell_Size):
pygame.draw.line(Main_Display,(40,40,40),(x,0),(x,Window_Height))
#水平方向
foryinrange(0,Window_Height,Cell_Size):
pygame.draw.line(Main_Display,(40,40,40),(0,y),(Window_Width,y))
#显示开始界面
defShow_Start_Interface:
title_Font=pygame.font.Font('simkai.ttf',100)
title_content=title_Font.render('贪吃蛇',True,(255,255,255),(0,0,160))
angle=0
whileTrue:
Main_Display.fill(Background_Color)
rotated_title=pygame.transform.rotate(title_content,angle)
rotated_title_Rect=rotated_title.get_rect
rotated_title_Rect.center=(Window_Width/2,Window_Height/2)
Main_Display.blit(rotated_title,rotated_title_Rect)
pressKey_content=Main_Font.render('按任意键开始游戏!',True,(255,255,255))
pressKey_Rect=pressKey_content.get_rect
pressKey_Rect.topleft=(Window_Width-200,Window_Height-30)
Main_Display.blit(pressKey_content,pressKey_Rect)
ifCheck_PressKey:
#清除事件队列
pygame.event.get
return
pygame.display.update
Snake_Clock.tick(Display_Clock)
angle-=5
#显示结束界面
defShow_End_Interface:
title_Font=pygame.font.Font('simkai.ttf',100)
title_game=title_Font.render('Game',True,(233,150,122))
title_over=title_Font.render('Over',True,(233,150,122))
game_Rect=title_game.get_rect
over_Rect=title_over.get_rect
game_Rect.midtop=(Window_Width/2,70)
over_Rect.midtop=(Window_Width/2,game_Rect.height+70+25)
【“我想玩游戏!”大佬:玩啥游戏,教你做一个智能贪吃蛇游戏】Main_Display.blit(title_game,game_Rect)
Main_Display.blit(title_over,over_Rect)
pygame.display.update
pygame.time.wait(500)
whileTrue:
foreventinpygame.event.get:
ifevent.type==QUIT:
close_game
elifevent.type==KEYDOWN:
ifevent.key==K_ESCAPE:
close_game
#判断该位置是否为空
defIs_Cell_Free(idx,psnake):
location_x=idx%Cell_W
location_y=idx//Cell_W
idx={'x':location_x,'y':location_y}
return(idxnotinpsnake)
“我想玩游戏!”大佬:玩啥游戏,教你做一个智能贪吃蛇游戏
文章图片

游戏智能性设计1、根据果实位置判断执行方向:#检查位置idx是否可以向当前move方向运动
defis_move_possible(idx,move_direction):
flag=False
ifmove_direction=='left':
ifidx%Cell_W>0:
flag=True
else:
flag=False
elifmove_direction=='right':
ifidx%Cell_W<Cell_W-1:
flag=True
else:
flag=False
elifmove_direction=='up':
ifidx>Cell_W-1:
flag=True
else:
flag=False
elifmove_direction=='down':
ifidx<FIELD_SIZE-Cell_W:
flag=True
else:
flag=False
returnflag
2、最短路径的选择:
到达果实的位置道路是千万条的 , 我们需要做的是最有效的方法 , 即需要找到最短的路径 。
详细定义函数如下:
#从蛇头周围4个领域点中选择最短路径
defchoose_shortest_safe_move(psnake,pboard):
best_move=ERR
min_distance=SNAKE_PLACE
formove_directionin['left','right','up','down']:
idx=psnake[Head_index]['x']+psnake[Head_index]['y']*Cell_W
ifis_move_possible(idx,move_direction)and(pboard[idx+move_directions[move_direction]]
min_distance=pboard[idx+move_directions[move_direction]]
best_move=move_direction
returnbest_move
#找到移动后蛇头的位置
deffind_snake_head(snake_Coords,direction):
ifdirection=='up':
newHead={'x':snake_Coords[Head_index]['x'],
'y':snake_Coords[Head_index]['y']-1}
elifdirection=='down':
newHead={'x':snake_Coords[Head_index]['x'],
'y':snake_Coords[Head_index]['y']+1}
elifdirection=='left':
newHead={'x':snake_Coords[Head_index]['x']-1,
'y':snake_Coords[Head_index]['y']}
elifdirection=='right':
newHead={'x':snake_Coords[Head_index]['x']+1,
'y':snake_Coords[Head_index]['y']}
returnnewHead
3、决策优化:
当蛇身过长等问题出现时可能会导致程序找不到合适的解决方案 , 故我们需要对此进行处理 , 即找不到合适的行为吃到果实 。 代码如下:
#如果蛇和食物间有路径
#则需要找一条安全的路径
deffind_safe_way(psnake,pboard,pfood):
safe_move=ERR
real_snake=psnake[:]
real_board=pboard[:]
v_psnake,v_pboard=virtual_move(psnake,pboard,pfood)
#如果虚拟运行后 , 蛇头蛇尾间有通路 , 则选最短路运行
ifis_tail_inside(v_psnake,v_pboard,pfood):
safe_move=choose_shortest_safe_move(real_snake,real_board)
else:
safe_move=follow_tail(real_snake,real_board,pfood)
returnsafe_move
#各种方案均无效时 , 随便走一步
defany_possible_move(psnake,pboard,pfood):
best_move=ERR
reset_board=board_reset(psnake,pboard,pfood)
pboard=reset_board
result,refresh_board=board_refresh(psnake,pfood,pboard)
pboard=refresh_board
min_distance=SNAKE_PLACE
formove_directionin['left','right','up','down']:
idx=psnake[Head_index]['x']+psnake[Head_index]['y']*Cell_W
ifis_move_possible(idx,move_direction)and(pboard[idx+move_directions[move_direction]]
min_distance=pboard[idx+move_directions[move_direction]]
best_move=move_direction
returnbest_move
游戏运行
调用主函数初始化运行即可:
#主函数defmain:globalMain_Display,Main_Font,Snake_Clockpygame.initSnake_Clock=pygame.time.ClockMain_Display=pygame.display.set_mode((Window_Width,Window_Height))Main_Font=pygame.font.Font('simkai.ttf',18)pygame.display.set_caption('AI_snake')Show_Start_InterfacewhileTrue:Run_GameShow_End_Interfaceif__name__=='__main__':main最终效果图如下可见:
“我想玩游戏!”大佬:玩啥游戏,教你做一个智能贪吃蛇游戏
文章图片

到此就完成了 , 如果你感兴趣的话不妨试试看 , 欢迎在评论区和我一起讨论!
作者介绍:
李秋键 , CSDN博客专家 , CSDN达人课作者 。 硕士在读于中国矿业大学 , 开发有taptap安卓武侠游戏一部 , vip视频解析 , 文意转换工具 , 写作机器人等项目 , 发表论文若干 , 多次高数竞赛获奖等等 。
“我想玩游戏!”大佬:玩啥游戏,教你做一个智能贪吃蛇游戏
文章图片

“我想玩游戏!”大佬:玩啥游戏,教你做一个智能贪吃蛇游戏
文章图片

那个分分钟处理10亿节点图计算的Plato , 现在怎么样了?
黑客用上机器学习你慌不慌?这7种窃取数据的新手段快来认识一下!
大促下的智能运维挑战:阿里如何抗住“双11猫晚”?
“谷歌杀手”发明者 , 科学天才Wolfram
数据库激荡40年 , 深入解析PostgreSQL、NewSQL演进历程
超详细!一文告诉你SparkStreaming如何整合Kafka!附代码可实践
5分钟!就能学会以太坊JSONAPI基础知识!


    推荐阅读