Python游戏开发 制作AI贪吃蛇!

前提:本文实现AI贪吃蛇自行对战,加上人机对战,读者可再次基础上自行添加电脑VS电脑和玩家VS玩家(其实把人机对战写完,这2个都没什么了,思路都一样)

实现效果:

具体功能:

1.智能模式:电脑自己玩(自己吃食物)

2.人机对战:电脑和人操作(在上步的基础上加一个键盘控制的贪吃蛇即可)

实现环境:

Pycharm + Python3.6 + Curses + Win10

具体过程:

一:配置环境:

Curses: 参考链接 (Cp后面代表本地Python环境,别下错了)

( Stackoverflow 真的是个非常好的地方)

二:

1.灵感来源+参考链接:

http://www.hawstein.com/posts/snake-ai.html (Chrome有时候打不开,Firefox可以打开)

2.算法思路:

A*算法: https://www.cnblogs.com/21207-iHome/p/6048969.html (本人之前接触过,当时讲课老师说是自动寻路算法,我感觉和BFS+DFS一样,结果没想到居然是A*算法)

BFS+DFS(略)

第一步是能制作一个 基本的贪吃蛇 ,熟悉Curses的相关环境(最好别对蛇和食物使用特殊字符,在windows环境下会导致像素延迟,非常丑)

#curses官方手册:https://docs.python.org/3.5/library/curses.html#module-curses  
#curses参考手册:https://blog.csdn.net/chenxiaohua/article/details/2099304  

具体思路:

熟悉Curses中相关指令后基本就没什么了, 保证按的下一个键不导致蛇死亡,保证蛇吃食物后食物不在蛇身上,保证蛇碰到自己和边框就死亡,如果按其他键,会导致头被插入2次,从而让蛇死亡。(具体见代码分析)

 1 #!/usr/bin/env python  
 2 # -\*- coding: utf-8 -\*-  
 3 # @Time : 2018/11/5 17:08  
 4 # @Author : Empirefree  
 5 # @File : 贪吃蛇-01.py  
 6 # @Software: PyCharm Community Edition  
 7  
 8 #curses官方手册:https://docs.python.org/3.5/library/curses.html#module-curses  
 9 #curses参考手册:https://blog.csdn.net/chenxiaohua/article/details/2099304  
 10  
 11 # 基本思路:while循环,让蛇一直右走(直到按键,如果按了其他键就会导致蛇头被重复插入1次到snake中,  
 12 # 继而第二次循环就会退出),蛇是每次自动增长,但是每次没吃到食物就会pop尾部(snake放在dict中,类似链表),按键检查就是只能按方向键  
 13 # 按方向键也存在判别是否出错(按了up后又按down),然后对于死亡情况就是碰到周围和自己  
 14  
 15 # 1.蛇的移动和吃食物后的变化  
 16 # 2.按键:按其他键和方向键  
 17 # 3.死亡判断  
 18  
 19 import curses  
 20 import random  
 21  
 22 # 开启curses  
 23 def Init\_Curse():  
 24 global s  
 25 s = curses.initscr()  
 26 curses.curs\_set(0) #能见度光标,写错了哇  
 27 curses.noecho()  
 28 curses.cbreak() #立即得到响应  
 29 s.keypad(True) #特殊处理键位,返回KEY\_LEFT  
 30  
 31 #关闭并回到终端  
 32 def Exit\_Curse():  
 33 curses.echo()  
 34 curses.nocbreak()  
 35 s.keypad(False)  
 36 curses.endwin()  
 37  
 38 def Start\_Game():  
 39 # 窗口化操作  
 40 y, x = s.getmaxyx() # curses中是y,x  
 41 w = curses.newwin(y, x, 0, 0)  
 42 w.keypad(1)  
 43 w.timeout(100)  
 44  
 45 # 初始化蛇的位置,并用dict存储  
 46 snake\_x = int(x / 4)  
 47 snake\_y = int(y / 2)  
 48 snake = \[\[snake\_y, snake\_x\], \[snake\_y, snake\_x - 1\], \[snake\_y, snake\_x - 2\]\]  
 49  
 50 # 初始化食物  
 51 food\_pos = \[int(y / 2), int(x / 2)\]  
 52 w.addch(food\_pos\[0\], food\_pos\[1\], '@') # 用@显示食物字元  
 53  
 54 key = curses.KEY\_RIGHT # 得到右方向键  
 55  
 56 # 开始,为什么我感觉True比1看的爽一些  
 57 while True:  
 58 next\_key = w.getch() # 等待输入,传回整数  
 59 print(next\_key, 'QAQ')  
 60 # 防止Error  
 61 if next\_key != -1:  
 62 if key == curses.KEY\_RIGHT and next\_key != curses.KEY\_LEFT  
 63 or key == curses.KEY\_LEFT and next\_key != curses.KEY\_RIGHT  
 64 or key == curses.KEY\_DOWN and next\_key != curses.KEY\_UP  
 65 or key == curses.KEY\_UP and next\_key != curses.KEY\_DOWN:  
 66 key = next\_key  
 67  
 68 # 蛇死亡, 当蛇头碰到蛇身或墙壁  
 69 if snake\[0\]\[0\] in \[0, y\] or snake\[0\]\[1\] in \[0, x\] or snake\[0\] in snake\[1:\]:  
 70 # print(snake\[0\], snake\[1\]) 按下其他键就会导致,new\_head被插入2次,从而退出  
 71 curses.endwin()  
 72 print('!!!游戏结束!!!')  
 73 quit()  
 74  
 75 #按键移动  
 76 tempy = snake\[0\]\[0\]  
 77 tempx = snake\[0\]\[1\]  
 78 new\_head = \[tempy, tempx\]  
 79 if key == curses.KEY\_RIGHT:  
 80 new\_head\[1\] += 1  
 81 elif key == curses.KEY\_LEFT:  
 82 new\_head\[1\] -= 1  
 83 elif key == curses.KEY\_UP:  
 84 new\_head\[0\] -= 1  
 85 elif key == curses.KEY\_DOWN:  
 86 new\_head\[0\] += 1  
 87 snake.insert(0, new\_head) #保留蛇头,根据按键更新蛇头  
 88  
 89 #食物位置  
 90 if snake\[0\] == food\_pos:  
 91 food\_pos = None  
 92 while food\_pos is None:  
 93 new\_food = \[random.randint(1, y - 1), random.randint(1, x - 1)\]  
 94 if new\_food not in snake:  
 95 food\_pos = new\_food  
 96 w.addch(food\_pos\[0\], food\_pos\[1\], '@') #再次添加食物,保证食物不在蛇上  
 97 else:  
 98 tail = snake.pop() #dict直接pop尾部  
 99 w.addch(tail\[0\], tail\[1\], ' ')  
100  
101 w.addch(snake\[0\]\[0\], snake\[0\]\[1\], 'Q')  
102  
103 if \_\_name\_\_ == '\_\_main\_\_':  
104 Init\_Curse()  
105 Start\_Game()  
106  
107 print('QAQ')  
108 Exit\_Curse()  
基本贪吃蛇  

3.代码剖析:

[红色为代码所需函数]

(蛇每走一步,就更新snake距离food的board距离,涉及 board_rest (更新每个非snake元素距离food的距离)和 board_refresh (本文这里采用BFS算法)),寻找到best_move,然后让蛇移动即可

如果吃的到食物( find_safe_way ):----> 放出虚拟蛇( virtual_shortest_move )(防止蛇吃完食物就被自己绕死)

如果虚拟蛇吃完食物还可以找到 蛇尾(出的去)( is_tail_inside )

直接吃食物( choose_shortest_safe_move )

反之,出不去:

就跟着尾巴走( follow_tail )就好比一直上下绕,就绝对不会死,但是蛇就完全没有灵性

如果吃不到食物

跟着尾巴(走最远的路(

choose_longest_safe_move

)),四个方向走(如果是A*算法需要将8个方向改成4个方向)

如果上诉方法都不行,就涉及到a ny_possible_move ,挑选距离最小的走(这里就会涉及到将自己吃死,有待改进)

(通过以上方法,就可以制造一个基本AI贪吃蛇了,当然,还有很多细节方面东西需要考虑)

报错:

win = curses.newwin(HEIGHT, WIDTH, 0, 0)

_curses.error: curses function returned NULL

原因:Pycharm下面(或者cmd、exe太小,需要拉大点)

	 1 #!/usr/bin/env python  
 2 # -\*- coding: utf-8 -\*-  
 3 # @Time : 2018/11/16 14:26  
 4 # @Author : Empirefree  
 5 # @File : 贪吃蛇-03.py  
 6 # @Software: PyCharm Community Edition  
 7  
 8 import curses  
 9 from curses import KEY\_RIGHT, KEY\_LEFT, KEY\_UP, KEY\_DOWN  
 10 from random import randint  
 11  
 12 # 必须要弄成全局哇,不然需要用到的数据太多了  
 13 # 1.初始化界面  
 14 # 2.更新地图,判断是否可以吃到食物  
 15 # 3.如果可以吃到,放出虚拟蛇(这里又设计到地图更新(board\_reset),记录距离(board\_refresh)操作)  
 16 # 3.1虚拟蛇若吃食物距离蛇尾有路径(直接吃),否则,追蛇尾  
 17 # 3.2若吃不到,则追蛇尾  
 18 # 4.更新best\_move,改变距离  
 19 ###########################################################################################  
 20 #作者:  
 21 print('\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*')  
 22 print('\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*!!!欢迎使用AI贪吃蛇 !!!\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*')  
 23 print('\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*作者:胡宇乔 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*')  
 24 print('\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*工具: Pycharm \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*')  
 25 print('\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*时间: 2018/11/16 14:26 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*')  
 26 print('\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* (按Esc结束贪吃蛇游戏) \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*')  
 27 print('\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*')  
 28 # 场地  
 29 HEIGHT, WIDTH = map(int, input('请输入长度长宽\[20 40\]:').split())  
 30 FIELD\_SIZE = HEIGHT \* WIDTH  
 31  
 32 #蛇和食物  
 33 HEAD = 0  
 34 FOOD = 0  
 35 UNDEFINED = (HEIGHT + 1) \* (WIDTH + 1)  
 36 SNAKE = 2 \* UNDEFINED  
 37  
 38 # 四个方向的移动  
 39 LEFT = -1  
 40 RIGHT = 1  
 41 UP = -WIDTH  
 42 DOWN = WIDTH  
 43  
 44 # 错误码  
 45 ERR = -1111  
 46  
 47 # 用一维数组来表示二维的东西  
 48 # board表示蛇运动的矩形场地  
 49 # 初始化蛇头在(1,1)的地方,第0行,HEIGHT行,第0列,WIDTH列为围墙,不可用  
 50 # 初始蛇长度为1  
 51 board = \[0\] \* FIELD\_SIZE  
 52 snake = \[0\] \* (FIELD\_SIZE + 1)  
 53 snake\[HEAD\] = 1 \* WIDTH + 1  
 54 snake\_size = 1  
 55 # tmpsnake即虚拟蛇  
 56 tmpboard = \[0\] \* FIELD\_SIZE  
 57 tmpsnake = \[0\] \* (FIELD\_SIZE + 1)  
 58 tmpsnake\[HEAD\] = 1 \* WIDTH + 1  
 59 tmpsnake\_size = 1  
 60  
 61 # food:食物位置(0~FIELD\_SIZE-1),初始在(3, 3)  
 62 # best\_move: 运动方向  
 63 food = 3 \* WIDTH + 3  
 64 best\_move = ERR  
 65  
 66 # 运动方向数组  
 67 mov = \[LEFT, RIGHT, UP, DOWN\]  
 68 # 接收到的键 和 分数  
 69 key = KEY\_RIGHT  
 70 score = 1 # 分数也表示蛇长  
 71  
 72 #cueses初始化  
 73 curses.initscr()  
 74 win = curses.newwin(HEIGHT, WIDTH, 0, 0)  
 75 win.keypad(1)  
 76 curses.noecho()  
 77 curses.curs\_set(0)  
 78 win.border(0)  
 79 win.nodelay(1)  
 80 win.addch(food // WIDTH, food % WIDTH, '@')  
 81  
 82 ###########################################################################################  
 83 #判断是否为空(可走)  
 84 def is\_cell\_free(idx, psize, psnake):  
 85 return not (idx in psnake\[:psize\])  
 86  
 87  
 88 # 检查某个位置idx是否可向move方向运动  
 89 def is\_move\_possible(idx, move):  
 90 flag = False  
 91 if move == LEFT:  
 92 flag = True if idx % WIDTH > 1 else False  
 93 elif move == RIGHT:  
 94 flag = True if idx % WIDTH < (WIDTH - 2) else False  
 95 elif move == UP:  
 96 flag = True if idx > (2 \* WIDTH - 1) else False # 即idx/WIDTH > 1  
 97 elif move == DOWN:  
 98 flag = True if idx < (FIELD\_SIZE - 2 \* WIDTH) else False # 即idx/WIDTH < HEIGHT-2  
 99 return flag  
100  
101  
102 # 计算出board中每个非SNAKE元素到达食物的路径长度,并判断是否可以找到食物  
103 def board\_reset(psnake, psize, pboard):  
104 for i in range(FIELD\_SIZE):  
105 if i == food:  
106 pboard\[i\] = FOOD  
107 elif is\_cell\_free(i, psize, psnake): # 该位置为空  
108 pboard\[i\] = UNDEFINED  
109 else: # 该位置为蛇身  
110 pboard\[i\] = SNAKE  
111  
112  
113 # 广度优先搜索遍历整个board,  
114 # 计算出board中每个非SNAKE元素到达食物的路径长度  
115 def board\_refresh(pfood, psnake, pboard):  
116 queue = \[\]  
117 queue.append(pfood)  
118 inqueue = \[0\] \* FIELD\_SIZE  
119 found = False  
120 # while循环结束后,除了蛇的身体,  
121 # 其它每个方格中的数字代码从它到食物的路径长度  
122 while len(queue) != 0:  
123 idx = queue.pop(0)  
124 if inqueue\[idx\] == 1: continue  
125 inqueue\[idx\] = 1  
126 for i in range(4):  
127 if is\_move\_possible(idx, mov\[i\]):  
128 if idx + mov\[i\] == psnake\[HEAD\]:  
129 found = True  
130 if pboard\[idx + mov\[i\]\] < SNAKE: # 如果该点不是蛇的身体  
131  
132 if pboard\[idx + mov\[i\]\] > pboard\[idx\] + 1:  
133 pboard\[idx + mov\[i\]\] = pboard\[idx\] + 1  
134 if inqueue\[idx + mov\[i\]\] == 0:  
135 queue.append(idx + mov\[i\])  
136  
137 return found  
138  
139  
140 #蛇头开始,根据蛇的4个领域选择最远路径(安全一点)  
141 def choose\_shortest\_safe\_move(psnake, pboard):  
142 best\_move = ERR  
143 min = SNAKE  
144 for i in range(4):  
145 if is\_move\_possible(psnake\[HEAD\], mov\[i\]) and pboard\[psnake\[HEAD\] + mov\[i\]\] < min:  
146 min = pboard\[psnake\[HEAD\] + mov\[i\]\]  
147 best\_move = mov\[i\]  
148 return best\_move  
149  
150  
151 # 从蛇头开始,根据board中元素值,  
152 # 从蛇头周围4个领域点中选择最远路径  
153 def choose\_longest\_safe\_move(psnake, pboard):  
154 best\_move = ERR  
155 max = -1  
156 for i in range(4):  
157 if is\_move\_possible(psnake\[HEAD\], mov\[i\]) and pboard\[psnake\[HEAD\] + mov\[i\]\] < UNDEFINED and pboard\[psnake\[HEAD\] + mov\[i\]\] > max:  
158 max = pboard\[psnake\[HEAD\] + mov\[i\]\]  
159 best\_move = mov\[i\]  
160 return best\_move  
161  
162  
163 # 检查是否可以追着蛇尾运动,即蛇头和蛇尾间是有路径的  
164 # 为的是避免蛇头陷入死路  
165 # 虚拟操作,在tmpboard,tmpsnake中进行  
166 def is\_tail\_inside():  
167 global tmpboard, tmpsnake, food, tmpsnake\_size  
168 tmpboard\[tmpsnake\[tmpsnake\_size - 1\]\] = 0 # 虚拟地将蛇尾变为食物(因为是虚拟的,所以在tmpsnake,tmpboard中进行)  
169 tmpboard\[food\] = SNAKE # 放置食物的地方,看成蛇身  
170 result = board\_refresh(tmpsnake\[tmpsnake\_size - 1\], tmpsnake, tmpboard) # 求得每个位置到蛇尾的路径长度  
171 for i in range(4): # 如果蛇头和蛇尾紧挨着,则返回False。即不能follow\_tail,追着蛇尾运动了  
172 if is\_move\_possible(tmpsnake\[HEAD\], mov\[i\]) and tmpsnake\[HEAD\] + mov\[i\] == tmpsnake\[  
173 tmpsnake\_size - 1\] and tmpsnake\_size > 3:  
174 result = False  
175 return result  
176  
177  
178 # 让蛇头朝着蛇尾运行一步  
179 # 不管蛇身阻挡,朝蛇尾方向运行  
180 def follow\_tail():  
181 global tmpboard, tmpsnake, food, tmpsnake\_size  
182 tmpsnake\_size = snake\_size  
183 tmpsnake = snake\[:\]  
184 board\_reset(tmpsnake, tmpsnake\_size, tmpboard) # 重置虚拟board  
185 tmpboard\[tmpsnake\[tmpsnake\_size - 1\]\] = FOOD # 让蛇尾成为食物  
186 tmpboard\[food\] = SNAKE # 让食物的地方变成蛇身  
187 board\_refresh(tmpsnake\[tmpsnake\_size - 1\], tmpsnake, tmpboard) # 求得各个位置到达蛇尾的路径长度  
188 tmpboard\[tmpsnake\[tmpsnake\_size - 1\]\] = SNAKE # 还原蛇尾  
189  
190 return choose\_longest\_safe\_move(tmpsnake, tmpboard) # 返回运行方向(让蛇头运动1步)  
191  
192  
193 # 在各种方案都不行时,随便找一个可行的方向来走(1步),  
194 def any\_possible\_move():  
195 global food, snake, snake\_size, board  
196 best\_move = ERR  
197 board\_reset(snake, snake\_size, board)  
198 board\_refresh(food, snake, board)  
199 min = SNAKE  
200  
201 for i in range(4):  
202 if is\_move\_possible(snake\[HEAD\], mov\[i\]) and board\[snake\[HEAD\] + mov\[i\]\] < min:  
203 min = board\[snake\[HEAD\] + mov\[i\]\]  
204 best\_move = mov\[i\]  
205 return best\_move  
206  
207 #虚拟蛇蛇移动  
208 def shift\_array(arr, size):  
209 for i in range(size, 0, -1):  
210 arr\[i\] = arr\[i - 1\]  
211  
212 #产生新食物  
213 def new\_food():  
214 global food, snake\_size  
215 cell\_free = False  
216 while not cell\_free:  
217 w = randint(1, WIDTH - 2)  
218 h = randint(1, HEIGHT - 2)  
219 food = h \* WIDTH + w  
220 cell\_free = is\_cell\_free(food, snake\_size, snake)  
221 win.addch(food // WIDTH, food % WIDTH, '@')  
222  
223  
224 # 真正的蛇在这个函数中,朝pbest\_move走1步  
225 def make\_move(pbest\_move):  
226 global key, snake, board, snake\_size, score  
227 shift\_array(snake, snake\_size)  
228 snake\[HEAD\] += pbest\_move  
229  
230 # 按esc退出,getch同时保证绘图的流畅性,没有它只会看到最终结果  
231 win.timeout(10)  
232 event = win.getch()  
233 key = key if event == -1 else event  
234 if key == 27: return  
235  
236 p = snake\[HEAD\]  
237 win.addch(p // WIDTH, p % WIDTH, '\*')  
238  
239 # 如果新加入的蛇头就是食物的位置  
240 # 蛇长加1,产生新的食物,重置board(因为原来那些路径长度已经用不上了)  
241 if snake\[HEAD\] == food:  
242 board\[snake\[HEAD\]\] = SNAKE # 新的蛇头  
243 snake\_size += 1  
244 score += 1  
245 if snake\_size < FIELD\_SIZE: new\_food()  
246 else: # 如果新加入的蛇头不是食物的位置  
247 board\[snake\[HEAD\]\] = SNAKE # 新的蛇头  
248 board\[snake\[snake\_size\]\] = UNDEFINED # 蛇尾变为空格  
249 win.addch(snake\[snake\_size\] // WIDTH, snake\[snake\_size\] % WIDTH, ' ')  
250  
251  
252 #虚拟蛇最短移动  
253 def virtual\_shortest\_move():  
254 global snake, board, snake\_size, tmpsnake, tmpboard, tmpsnake\_size, food  
255 tmpsnake\_size = snake\_size  
256 tmpsnake = snake\[:\] # 如果直接tmpsnake=snake,则两者指向同一处  
257 tmpboard = board\[:\] # board中已经是各位置到达食物的路径长度了,不用再计算  
258 board\_reset(tmpsnake, tmpsnake\_size, tmpboard)  
259  
260 food\_eated = False  
261 while not food\_eated:  
262 board\_refresh(food, tmpsnake, tmpboard)  
263 move = choose\_shortest\_safe\_move(tmpsnake, tmpboard)  
264 shift\_array(tmpsnake, tmpsnake\_size)  
265 tmpsnake\[HEAD\] += move # 在蛇头前加入一个新的位置  
266 # 如果新加入的蛇头的位置正好是食物的位置  
267 # 则长度加1,重置board,食物那个位置变为蛇的一部分(SNAKE)  
268 if tmpsnake\[HEAD\] == food:  
269 tmpsnake\_size += 1  
270 board\_reset(tmpsnake, tmpsnake\_size, tmpboard) # 虚拟运行后,蛇在board的位置  
271 tmpboard\[food\] = SNAKE  
272 food\_eated = True  
273 else: # 如果蛇头不是食物的位置,则新加入的位置为蛇头,最后一个变为空格  
274 tmpboard\[tmpsnake\[HEAD\]\] = SNAKE  
275 tmpboard\[tmpsnake\[tmpsnake\_size\]\] = UNDEFINED  
276  
277  
278 # 如果蛇与食物间有路径,则调用本函数  
279 def find\_safe\_way():  
280 global snake, board  
281 safe\_move = ERR  
282 # 虚拟地运行一次,因为已经确保蛇与食物间有路径,所以执行有效  
283 # 运行后得到虚拟下蛇在board中的位置,即tmpboard,见label101010  
284 virtual\_shortest\_move() # 该函数唯一调用处  
285 if is\_tail\_inside(): # 如果虚拟运行后,蛇头蛇尾间有通路,则选最短路运行(1步)  
286 return choose\_shortest\_safe\_move(snake, board)  
287 safe\_move = follow\_tail() # 否则虚拟地follow\_tail 1步,如果可以做到,返回true  
288 return safe\_move  
289  
290 if \_\_name\_\_ == '\_\_main\_\_':  
291  
292 while key != 27:  
293 win.border(0)  
294 win.addstr(0, 2, '分数:' + str(score) + ' ')  
295 win.timeout(10)  
296 # 接收键盘输入,同时也使显示流畅  
297 event = win.getch()  
298 key = key if event == -1 else event  
299 # 重置矩阵  
300 board\_reset(snake, snake\_size, board)  
301  
302 # 如果蛇可以吃到食物,board\_refresh返回true  
303 # 并且board中除了蛇身(=SNAKE),其它的元素值表示从该点运动到食物的最短路径长  
304 if board\_refresh(food, snake, board):  
305 best\_move = find\_safe\_way() # find\_safe\_way的唯一调用处  
306 else:  
307 best\_move = follow\_tail()  
308  
309 if best\_move == ERR:  
310 best\_move = any\_possible\_move()  
311 # 上面一次思考,只得出一个方向,运行一步  
312 if best\_move != ERR:  
313 make\_move(best\_move)  
314 else:  
315 break  
316  
317 curses.endwin()  
318 print("  
 得分:" + str(score))  
贪吃蛇-02  

在以上基础上,还需要引入第一步制造的基本贪吃蛇

细节:1.键盘蛇加入后如何与蛇抢分(只需要return即可,但是 new_food()里面是需要更改的)

	 1 # 产生新食物  
 2 def new\_food():  
 3 global food, snake\_size, myfood  
 4 cell\_free = False  
 5 while not cell\_free:  
 6 food1 = \[random.randint(1, HEIGHT - 2), random.randint(1, WIDTH - 2)\]  
 7 w = randint(1, WIDTH - 2)  
 8 h = randint(1, HEIGHT - 2)  
 9 myfood = \[h, w\]  
10 food = h \* WIDTH + w  
11 if (is\_cell\_free(food, snake\_size, snake) and \[w, h\] not in snake1):  
12 cell\_free = True  
13 win.addch(food // WIDTH, food % WIDTH, '@')  

2.一直没说,由于蛇加入后很多变量都需要global,导致变量看起来非常麻烦(读者要有心理准备)

3.curses里面的win.timeout()是控制蛇的速度

好像就没什么了,想起来了在更。我没加入2条蛇不能彼此碰撞(读者也可以弄成2个地图,然后看AI蛇和你自己的蛇如何操作跑,我是放在了一个地图里面)

当然还有很多很多细节,不过主要思路写下来了。其余就靠分析代码自行研究了。Python制作AI贪吃蛇

往期精彩文章推荐:

点击下方安全链接前往获取

CSDN大礼包:《Python入门&进阶学习资源包》免费分享

👉Python实战案例👈

光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。

图片

图片

👉Python书籍和视频合集👈

观看零基础学习视频,看视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。

图片

👉Python副业创收路线👈

图片

这些资料都是非常不错的,朋友们如果有需要《Python学习路线&学习资料》,点击下方安全链接前往获取

CSDN大礼包:《Python入门&进阶学习资源包》免费分享

本文转自 网络,如有侵权,请联系删除。

  • 29
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值