降智警告:本人爲編程新手,遵守面向CSDN編程原則,代碼架構具有個人特色,僅供參考
前言:課程期末項目寫了個黑白棋,所以放假寫個五子棋,作爲今年的總結
(該五子棋僅涉及最基礎的規則,輪留下,連五贏)
一.最終效果
功能:規定玩家先下,結束時展示結果。restart按鈕會變色,鼠標在按鈕上時顏色變深。按下restart按鈕可以重新開局。
二.AI實現
1.思路
①棋局
使用二維列表表示棋盤,0表示空位,1表示玩家棋子(黑),2表示電腦棋子(白)
②局面評估
爲了減少計算量,我將電腦當前的可下位置限制爲,非空位置的八鄰域中的空位。然後對每一個可下位置進行評估。
我們需要爲每一個當前可下位置進行評估得到一個分數,然後取分數最高的位置作爲本次的下子位置。
在評估時,我們需要考慮該位置對於本方的重要性,同時也要考慮該位置對敵方的重要性,所以我們需要將兩個評估所得分數相加作爲該位置的最終分數。
③評估方法
首先對於每一個需要評估的位置,先將電腦棋子放到該位置,然後分別取該位置的橫,豎,左斜,右斜四個方向上的線上的所有位置作爲四條棋線,對每個位置的四條棋線進行評估。然後反轉棋盤,將電腦的棋子換爲玩家棋子,玩家棋子換爲電腦棋子,再對該位置進行評估。兩個評估分數相加即爲該位置的最終分數。
五子棋中有許多棋型,如連五,活四,衝四,活三等,爲每一個棋型設置一個分數,每個位置的四條棋線中存在的所有棋型的分數相加,得到該位置的一方評估分數。
2.代碼實現
這裏僅給出根據當前棋局給出最佳下子位置的實現,項目完整代碼在我的github
①獲取當前棋局所有可下位置(限制條件下)
def get_charge_pos(board) : #八鄰域 way = [(-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1)] ret = [] for i in range(15) : for j in range(15) : #當前位置不爲空位 if board[i][j] != 0 : #搜索八鄰域 for w in way : pos = (i + w[0], j + w[1]) if pos[0] not in range(15) or pos[1] not in range(15) : continue if (board[pos[0]][pos[1]] == 0) and (pos not in ret) : ret.append(pos) return ret
②獲取當前位置棋線
(將一條棋線上的位置整理爲一個列表,將列表轉化爲字符串並進行處理,最終只剩下包含0,1,2三個數字的字符串,返回包含四條棋線代表的字符串的列表)
def get_score(pos, board) : #獲取棋盤副本,在當前位置放入棋子 ori = copy.deepcopy(board) ori[pos[0]][pos[1]] = 2 #橫,豎 h = str(ori[pos[0]])[1:-1].replace(',', '').replace(' ', '') s = str([ori[i][pos[1]] for i in range(15)])[1:-1].replace(',', '').replace(' ', '') #左斜 lx = str([ori[i][i - pos[0] + pos[1]] for i in range(15) if (i - pos[0] + pos[1]) in range(15)])[1:-1].replace(',', '').replace(' ', '') #右斜 rx = str([ori[i][pos[0] + pos[1] - i] for i in range(15) if (pos[0] + pos[1] - i) in range(15)])[1:-1].replace(',', '').replace(' ', '') return get_line_score([h, s, lx, rx])
③棋線評分
(由於棋型過多,判斷比較繁瑣,截取部分代碼作爲示例)
注意:由於棋線上對於棋型是單向查找的,所以對於不對稱的棋型要反轉棋型再次查找
④主函數
實現對每個可下位置進行兩次評分得到最終分數後,返回分數最高的位置
def get_pos(board) : pos = get_charge_pos(board) get = (-1, -1) score = -float("inf") for p in pos : #反轉棋盤 o_board = opp_board(board) s = get_score(p, board) + get_score(p, o_board) if s > score : get = p score = s return get
三.總結
這個項目的界面實現就不放代碼了,有興趣的可以看一下(項目代碼)
使用pygame來構造界面,調用了棋盤,黑白棋子,restart按鈕共五張圖片,如果修改圖片的話需要更改顯示的具體參數
因爲界面用到好幾張圖,如果轉化爲py文件一起打包的話,最後的exe會很大,所以就放在一個文件夾裏直接調用了,順便把程序框圖標的ico也放進去了
最終的效果還是不錯的,AI的勝率挺高的,也用到了今年所學的東西,也是今年的最後一個項目了。