python實(shí)現(xiàn)翻轉(zhuǎn)棋游戲(othello)
利用上一篇的框架,再寫了個(gè)翻轉(zhuǎn)棋的程序,為了調(diào)試minimax算法,花了兩天的時(shí)間。
幾點(diǎn)改進(jìn)說(shuō)明:
- 拆分成四個(gè)文件:board.py,player.py,ai.py,othello.py。使得整個(gè)結(jié)構(gòu)更清晰,更通用,更易于維護(hù)。
- AI 的水平跟 minimax 的遞歸深度,以及評(píng)價(jià)函數(shù)有關(guān)?;诖耍野?minimax 和評(píng)價(jià)函數(shù)都放到 AI 類里面
- AIPlayer 使用了多重繼承。繼承了 Player 與 AI 兩個(gè)類
- Game 類中把原run函數(shù)里的生成兩個(gè)玩家的部分提出來(lái),寫成一個(gè)函數(shù)make_two_players,使得 run函數(shù)結(jié)構(gòu)更清晰
- AI 玩家等級(jí)不要選擇 0:beginer。會(huì)報(bào)錯(cuò),還沒(méi)調(diào)試好
board.py
''' 作者:hhh5460 時(shí)間:2017年7月1日 ''' class Board(object): def __init__(self): self.empty = '.' self._board = [[self.empty for _ in range(8)] for _ in range(8)] # 規(guī)格:8*8 self._board[3][4], self._board[4][3] = 'X', 'X' self._board[3][3], self._board[4][4] = 'O', 'O' # 增加 Board[][] 索引語(yǔ)法 def __getitem__(self, index): return self._board[index] # 打印棋盤 def print_b(self): board = self._board print(' ', ' '.join(list('ABCDEFGH'))) for i in range(8): print(str(i+1),' '.join(board[i])) # 棋局終止 def teminate(self): list1 = list(self.get_legal_actions('X')) list2 = list(self.get_legal_actions('O')) return [False, True][len(list1) == 0 and len(list2) == 0] # 判斷贏家 def get_winner(self): s1, s2 = 0, 0 for i in range(8): for j in range(8): if self._board[i][j] == 'X': s1 += 1 if self._board[i][j] == 'O': s2 += 1 if s1 > s2: return 0 # 黑勝 elif s1 < s2: return 1 # 白勝 elif s1 == s2: return 2 # 平局 # 落子 def _move(self, action, color): x,y = action self._board[x][y] = color return self._flip(action, color) # 翻子(返回list) def _flip(self, action, color): flipped_pos = [] for line in self._get_lines(action): for i,p in enumerate(line): if self._board[p[0]][p[1]] == self.empty: break elif self._board[p[0]][p[1]] == color: flipped_pos.extend(line[:i]) break for p in flipped_pos: self._board[p[0]][p[1]] = color return flipped_pos # 撤銷 def _unmove(self, action, flipped_pos, color): self._board[action[0]][action[1]] = self.empty uncolor = ['X', 'O'][color=='X'] for p in flipped_pos: self._board[p[0]][p[1]] = uncolor # 生成8個(gè)方向的下標(biāo)數(shù)組,方便后續(xù)操作 def _get_lines(self, action): '''說(shuō)明:剛開(kāi)始我是用一維棋盤來(lái)考慮的,后來(lái)改為二維棋盤。偷懶,不想推倒重來(lái),簡(jiǎn)單地修改了一下''' board_coord = [(i,j) for i in range(8) for j in range(8)] # 棋盤坐標(biāo) r,c = action ix = r*8 + c r, c = ix//8, ix%8 left = board_coord[r*8:ix] # 要反轉(zhuǎn) right = board_coord[ix+1:(r+1)*8] top = board_coord[c:ix:8] # 要反轉(zhuǎn) bottom = board_coord[ix+8:8*8:8] if r <= c: lefttop = board_coord[c-r:ix:9] # 要反轉(zhuǎn) rightbottom = board_coord[ix+9:(7-(c-r))*8+7+1:9] else: lefttop = board_coord[(r-c)*8:ix:9] # 要反轉(zhuǎn) rightbottom = board_coord[ix+9:7*8+(7-(c-r))+1:9] if r+c<=7: leftbottom = board_coord[ix+7:(r+c)*8:7] righttop = board_coord[r+c:ix:7] # 要反轉(zhuǎn) else: leftbottom = board_coord[ix+7:7*8+(r+c)-7+1:7] righttop = board_coord[((r+c)-7)*8+7:ix:7] # 要反轉(zhuǎn) # 有四個(gè)要反轉(zhuǎn),方便判斷 left.reverse() top.reverse() lefttop.reverse() righttop.reverse() lines = [left, top, lefttop, righttop, right, bottom, leftbottom, rightbottom] return lines # 檢測(cè),位置是否有子可翻 def _can_fliped(self, action, color): flipped_pos = [] for line in self._get_lines(action): for i,p in enumerate(line): if self._board[p[0]][p[1]] == self.empty: break elif self._board[p[0]][p[1]] == color: flipped_pos.extend(line[:i]) break return [False, True][len(flipped_pos) > 0] # 合法走法 def get_legal_actions(self, color): uncolor = ['X', 'O'][color=='X'] uncolor_near_points = [] # 反色鄰近的空位 board = self._board for i in range(8): for j in range(8): if board[i][j] == uncolor: for dx,dy in [(-1,0),(-1,1),(0,1),(1,1),(1,0),(1,-1),(0,-1)]: x, y = i+dx, j+dy if 0 <= x <=7 and 0 <= y <=7 and board[x][y] == self.empty and (x, y) not in uncolor_near_points: uncolor_near_points.append((x, y)) for p in uncolor_near_points: if self._can_fliped(p, color): yield p # 測(cè)試 if __name__ == '__main__': board = Board() board.print_b() print(list(board.get_legal_actions('X')))
player.py
from ai import AI ''' 作者:hhh5460 時(shí)間:2017年7月1日 ''' # 玩家 class Player(object): def __init__(self, color): self.color = color # 思考 def think(self, board): pass # 落子 def move(self, board, action): flipped_pos = board._move(action, self.color) return flipped_pos # 悔子 def unmove(self, board, action, flipped_pos): board._unmove(action, flipped_pos, self.color) # 人類玩家 class HumanPlayer(Player): def __init__(self, color): super().__init__(color) def think(self, board): while True: action = input("Turn to '{}'. \nPlease input a point.(such as 'A1'): ".format(self.color)) # A1~H8 r, c = action[1], action[0].upper() if r in '12345678' and c in 'ABCDEFGH': # 合法性檢查1 x, y = '12345678'.index(r), 'ABCDEFGH'.index(c) if (x,y) in board.get_legal_actions(self.color): # 合法性檢查2 return x, y # 電腦玩家(多重繼承) class AIPlayer(Player, AI): def __init__(self, color, level_ix=0): super().__init__(color) # init Player super(Player, self).__init__(level_ix) # init AI def think(self, board): print("Turn to '{}'. \nPlease wait a moment. AI is thinking...".format(self.color)) uncolor = ['X','O'][self.color=='X'] opfor = AIPlayer(uncolor) # 假想敵,陪練 action = self.brain(board, opfor, 4) return action
ai.py
import random ''' 作者:hhh5460 時(shí)間:2017年7月1日 ''' class AI(object): ''' 三個(gè)水平等級(jí):初級(jí)(beginner)、中級(jí)(intermediate)、高級(jí)(advanced) ''' def __init__(self, level_ix =0): # 玩家等級(jí) self.level = ['beginner','intermediate','advanced'][level_ix] # 棋盤位置權(quán)重,參考:https://github.com/k-time/ai-minimax-agent/blob/master/ksx2101.py self.board_weights = [ [120, -20, 20, 5, 5, 20, -20, 120], [-20, -40, -5, -5, -5, -5, -40, -20], [ 20, -5, 15, 3, 3, 15, -5, 20], [ 5, -5, 3, 3, 3, 3, -5, 5], [ 5, -5, 3, 3, 3, 3, -5, 5], [ 20, -5, 15, 3, 3, 15, -5, 20], [-20, -40, -5, -5, -5, -5, -40, -20], [120, -20, 20, 5, 5, 20, -20, 120] ] # 評(píng)估函數(shù)(僅根據(jù)棋盤位置權(quán)重) def evaluate(self, board, color): uncolor = ['X','O'][color=='X'] score = 0 for i in range(8): for j in range(8): if board[i][j] == color: score += self.board_weights[i][j] elif board[i][j] == uncolor: score -= self.board_weights[i][j] return score # AI的大腦 def brain(self, board, opponent, depth): if self.level == 'beginer': # 初級(jí)水平 _, action = self.randomchoice(board) elif self.level == 'intermediate': # 中級(jí)水平 _, action = self.minimax(board, opponent, depth) elif self.level == 'advanced': # 高級(jí)水平 _, action = self.minimax_alpha_beta(board, opponent, depth) assert action is not None, 'action is None' return action # 隨機(jī)選(從合法走法列表中隨機(jī)選) def randomchoice(self, board): color = self.color action_list = list(board.get_legal_actions(color)) return None, random.choice(action_list) # 極大極小算法,限制深度 def minimax(self, board, opfor, depth=4): # 其中 opfor 是假想敵、陪練 '''參考:https://github.com/k-time/ai-minimax-agent/blob/master/ksx2101.py''' color = self.color if depth == 0: return self.evaluate(board, color), None action_list = list(board.get_legal_actions(color)) if not action_list: return self.evaluate(board, color), None best_score = -100000 best_action = None for action in action_list: flipped_pos = self.move(board, action) # 落子 score, _ = opfor.minimax(board, self, depth-1) # 深度優(yōu)先,輪到陪練 self.unmove(board, action, flipped_pos) # 回溯 score = -score if score > best_score: best_score = score best_action = action return best_score, best_action # 極大極小算法,帶alpha-beta剪枝 def minimax_alpha_beta(self, board, opfor, depth=8, my_best=-float('inf'), opp_best=float('inf')): '''參考:https://github.com/k-time/ai-minimax-agent/blob/master/ksx2101.py''' color = self.color if depth == 0: return self.evaluate(board, color), None action_list = list(board.get_legal_actions(color)) if not action_list: return self.evaluate(board, color), None best_score = my_best best_action = None for action in action_list: flipped_pos = self.move(board, action) # 落子 score, _ = opfor.minimax_alpha_beta(board, self, depth-1, -opp_best, -best_score) # 深度優(yōu)先,輪到陪練 self.unmove(board, action, flipped_pos) # 回溯 score = -score if score > best_score: best_score = score best_action = action if best_score > opp_best: break return best_score, best_action
othello.py
from board import Board from player import HumanPlayer, AIPlayer ''' 作者:hhh5460 時(shí)間:2017年7月1日 ''' # 游戲 class Game(object): def __init__(self): self.board = Board() self.current_player = None # 生成兩個(gè)玩家 def make_two_players(self): ps = input("Please select two player's type:\n\t0.Human\n\t1.AI\nSuch as:0 0\n:") p1, p2 = [int(p) for p in ps.split(' ')] if p1 == 1 or p2 == 1: # 至少有一個(gè)AI玩家 level_ix = int(input("Please select the level of AI player.\n\t0: beginner\n\t1: intermediate\n\t2: advanced\n:")) if p1 == 0: player1 = HumanPlayer('X') player2 = AIPlayer('O', level_ix) elif p2 == 0: player1 = AIPlayer('X', level_ix) player2 = HumanPlayer('O') else: player1 = AIPlayer('X', level_ix) player2 = AIPlayer('O', level_ix) else: player1, player2 = HumanPlayer('X'), HumanPlayer('O') # 先手執(zhí)X,后手執(zhí)O return player1, player2 # 切換玩家(游戲過(guò)程中) def switch_player(self, player1, player2): if self.current_player is None: return player1 else: return [player1, player2][self.current_player == player1] # 打印贏家 def print_winner(self, winner): # winner in [0,1,2] print(['Winner is player1','Winner is player2','Draw'][winner]) # 運(yùn)行游戲 def run(self): # 生成兩個(gè)玩家 player1, player2 = self.make_two_players() # 游戲開(kāi)始 print('\nGame start!\n') self.board.print_b() # 顯示棋盤 while True: self.current_player = self.switch_player(player1, player2) # 切換當(dāng)前玩家 action = self.current_player.think(self.board) # 當(dāng)前玩家對(duì)棋盤進(jìn)行思考后,得到招法 if action is not None: self.current_player.move(self.board, action) # 當(dāng)前玩家執(zhí)行招法,改變棋盤 self.board.print_b() # 顯示當(dāng)前棋盤 if self.board.teminate(): # 根據(jù)當(dāng)前棋盤,判斷棋局是否終止 winner = self.board.get_winner() # 得到贏家 0,1,2 break self.print_winner(winner) print('Game over!') self.board.print_history() if __name__ == '__main__': Game().run()
效果圖
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- python pygame實(shí)現(xiàn)五子棋小游戲
- python制作簡(jiǎn)單五子棋游戲
- python實(shí)現(xiàn)五子棋人機(jī)對(duì)戰(zhàn)游戲
- 使用python實(shí)現(xiàn)簡(jiǎn)單五子棋游戲
- python五子棋游戲的設(shè)計(jì)與實(shí)現(xiàn)
- python實(shí)現(xiàn)簡(jiǎn)單五子棋游戲
- python使用tkinter庫(kù)實(shí)現(xiàn)五子棋游戲
- python實(shí)現(xiàn)五子棋游戲
- python實(shí)現(xiàn)五子棋小游戲
- Python實(shí)現(xiàn)的井字棋(Tic Tac Toe)游戲示例
- python實(shí)現(xiàn)井字棋游戲
相關(guān)文章
Python爬蟲實(shí)例——scrapy框架爬取拉勾網(wǎng)招聘信息
這篇文章主要介紹了Python爬蟲實(shí)例——scrapy框架爬取拉勾網(wǎng)招聘信息的相關(guān)資料,文中講解非常細(xì)致,代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下2020-07-07python 利用已有Ner模型進(jìn)行數(shù)據(jù)清洗合并代碼
今天小編就為大家分享一篇python 利用已有Ner模型進(jìn)行數(shù)據(jù)清洗合并代碼,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-12-12Python實(shí)現(xiàn)的HTTP并發(fā)測(cè)試完整示例
這篇文章主要介紹了Python實(shí)現(xiàn)的HTTP并發(fā)測(cè)試,涉及Python多線程并發(fā)操作相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2015-05-05Python中常見(jiàn)的導(dǎo)入方式總結(jié)
這篇文章主要介紹了Python中常見(jiàn)的導(dǎo)入方式總結(jié),文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)python的小伙伴們有非常好的幫助,需要的朋友可以參考下2021-05-05Python中g(shù)etattr函數(shù)和hasattr函數(shù)作用詳解
這篇文章主要介紹了Python中g(shù)etattr函數(shù)和hasattr函數(shù)作用的相關(guān)知識(shí),非常不錯(cuò)具有參考借鑒價(jià)值,需要的朋友可以參考下2016-06-06