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

实现效果:

很多人学习python,不知道从何学起。
很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手。
很多已经做案例的人,却不知道如何去学习更加高深的知识。
那么针对这三类人,我给大家提供一个好的学习平台,免费领取视频教程,电子书籍,以及课程的源代码!
QQ群:1097524789

具体功能:

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贪吃蛇

Python制作AI贪吃蛇,很多很多细节、思路都写下来了!的更多相关文章

  1. Python制作AI贪吃蛇

    前提:本文实现AI贪吃蛇自行对战,加上人机对战,文章末尾附上源代码以及各位大佬的链接,还有一些实现步骤,读者可再次基础上自行添加电脑VS电脑和玩家VS玩家(其实把人机对战写完,这2个都没什么了,思路都 ...

  2. AI贪吃蛇(二)

    前言 之前写过一篇关于贪吃蛇AI的博客,当时虽然取得了一些成果,但是也存在许多问题,所以最近又花了三天时间重新思考了一下.以下是之前博客存在的一些问题: 策略不对,只要存在找不到尾巴的情况就可能失败, ...

  3. AI贪吃蛇前瞻——基于Dijkstra算法的最短路径问题

    在贪吃蛇流程结构优化之后,我又不满足于亲自操刀控制这条蠢蠢的蛇,干脆就让它升级成AI,我来看程序自己玩,哈哈. 一.Dijkstra算法原理 作为一种广为人知的单源最短路径算法,Dijkstra用于求 ...

  4. 200行PYTHON代码实现贪吃蛇

    200行Python代码实现贪吃蛇 话不多说,最后会给出全部的代码,也可以从这里Fork,正文开始: 目前实现的功能列表: 贪吃蛇的控制,通过上下左右方向键: 触碰到边缘.墙壁.自身则游戏结束: 接触 ...

  5. Luat Inside | 致敬经典,使用Air724UG制作简易贪吃蛇

    作者简介: 打盹的消防车--活跃于Luat社群的新生代全能开发者,东北小伙儿爽朗幽默.好学敏思,更是实力行动派.幼年曾手握火红炽铁而后全然无恙,堪称魔幻经历:如今热衷于各类嵌入式软硬件研究,快意物联江 ...

  6. 同事上班时间无聊,用python敲出贪吃蛇游戏打发时间

    自从学会啦python,再也不用担心上班时间老板发现我打游戏啦 贪吃蛇代码: 还有不懂的(https://www.ixigua.com/i6808019824560570888/)这里有视频教程. 如 ...

  7. Python实例:贪吃蛇(简单贪吃蛇编写)🐍

    d=====( ̄▽ ̄*)b 叮~ Python -- 简易贪吃蛇实现 目录: 1.基本原理 2.需要学习的库 3.代码实现 1.基本原理 基本贪吃蛇所需要的东西其实很少,只需要有一块让蛇动的屏幕, 在 ...

  8. Python-pygame案例AI贪吃蛇

    # coding: utf-8 import pygame,sys,time,random from pygame.locals import * # 定义颜色变量 redColour = pygam ...

  9. python学习-56 贪吃蛇🐍

    import random, pygame, sys from pygame.locals import * FPS = 15 WINDOWWIDTH = 640 WINDOWHEIGHT = 480 ...

随机推荐

  1. 01-flask电商项目开发基础配置

    本项目前端采用vue-cli的脚手架,后端采用Flask的Web框架.项目通过完成用户管理.权限管理.商品管理.订单管理.统计管理等功能,综合了前后端的知识,希望使大家都能受益. 1.使用到的技术如下 ...

  2. bzoj3687简单题*

    bzoj3687简单题 题意: 给个集合,求所有子集的元素和的异或和.集合元素个数≤1000,整个集合的元素和≤2000000 题解: 用bitset维护每个子集元素和的个数是奇数还是偶数.每次读入一 ...

  3. Facebook没有测试工程师,如何进行质量控制的?

    Facebook从04年的哈佛校园的学生项目在短短的7-8年的时间中快速增长为拥有10亿用户的世界上最大的社交网络,又一次见证了互联网创业成功的奇迹.同时它的产品研发流程也成为了众多互联网产品公司的追 ...

  4. ASP.Net Core 3.1 With Autofac ConfigureServices returning an System.IServiceProvider isn't supported.

    ASP.Net Core 3.1 With Autofac ConfigureServices returning an System.IServiceProvider isn't supported ...

  5. Intelij DataGrip 的安装和使用

    链接: Intelij DataGrip 安装教程以及汉化教程 Intelij DataGrip 使用教程 以上两个教程已使用过,没有问题 如有侵权请联系删除

  6. JS闭包应用场景之函数回调(含函数的调用个人理解)

    首先我们来绑定一个函数给click事件,这个很好理解,就是创建一个匿名函数作为回调绑定给click事件,如下: 但如果我们想声明一个函数作为回调来绑定多个元素呢,例如下面(注意:绑定事件后不用加括号, ...

  7. html头文件设置常用之<meta>设置

    也许很多开发人员并没有重视meta标签,我就是其中一个,但是meta标签的功能很强大,下面就来说说meta标签! <meta http-equiv="pragma" cont ...

  8. Android复习准备

    1. 四大组件是什么? Activity(活动):用于表现功能 Service(服务):后台运行服务,不提供界面呈现 BroadcastReceiver(广播接收器):用来接收广播 ContentPr ...

  9. java 心跳机制

    心跳机制:就是每隔几分钟发送一个固定信息给服务端,服务端收到后回复一个固定信息如果服务端几分钟内没有收到客户端信息则视客户端断开. 心跳包 心跳包就是在客户端和服务器间定时通知对方自己状态的一个自己定 ...

  10. 图解 JVM 核心知识点(面试版)

    一.基本概念 1.1 OpenJDK 自 1996 年 JDK 1.0 发布以来,Sun 公司在大版本上发行了 JDK 1.1.JDK 1.2.JDK 1.3.JDK 1.4.JDK 5,JDK 6 ...