程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

Python制作AI貪吃蛇,很多很多細節、思路都寫下來了!

編輯:Python

前提:本文實現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.算法思路:

AI算法:https://www.cnblogs.com/21207-iHome/p/6048969.html (本人之前接觸過,當時講課老師說是自動尋路算法,我感覺和BFS+DFS一樣,結果沒想到居然是AI算法)

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('*****************
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved