python_pygame_alpha-beta剪枝算法_玩中国象棋
发布日期:2021-06-29 19:49:34
浏览次数:3
分类:技术文章
本文共 24356 字,大约阅读时间需要 81 分钟。
本文主要内容:python Pygame alpha-beta剪枝算法 玩中国象棋 相当于入门水平,我还是能下赢它
完整简洁并有详细注释的代码: 运行入口为:chinachess.py 算法和代码解释请查看参考文献里的文章1、界面演示
2、关键代码
可视化中国象棋运行入口
import timeimport pygameimport ChinaChess.constantsfrom ChinaChess import constants, pieces, computerimport ChinaChess.computerimport ChinaChess.my_game as mg'''此文件为可视化中国象棋运行入口'''class MainGame(): window = None Start_X = ChinaChess.constants.Start_X Start_Y = ChinaChess.constants.Start_Y Line_Span = ChinaChess.constants.Line_Span Max_X = Start_X + 8 * Line_Span Max_Y = Start_Y + 9 * Line_Span from_x = 0 from_y = 0 to_x = 0 to_y = 0 clickx = -1 clicky = -1 mgInit = mg.my_game() player1Color = constants.player1Color player2Color = constants.player2Color Putdownflag = player1Color piecesSelected = None piecesList = [] def start_game(self): MainGame.window = pygame.display.set_mode([constants.SCREEN_WIDTH, constants.SCREEN_HEIGHT]) pygame.display.set_caption("中国象棋") # 把所有棋子摆好 self.piecesInit() while True: time.sleep(0.1) # 获取事件 MainGame.window.fill(constants.BG_COLOR) self.drawChessboard() # 遍历所有棋子,显示所有棋子 self.piecesDisplay() # 判断游戏胜利 self.VictoryOrDefeat() # 轮到电脑了 self.Computerplay() # 获取所有的事件 self.getEvent() pygame.display.update() pygame.display.flip() def drawChessboard(self): mid_end_y = MainGame.Start_Y + 4 * MainGame.Line_Span min_start_y = MainGame.Start_Y + 5 * MainGame.Line_Span for i in range(0, 9): x = MainGame.Start_X + i * MainGame.Line_Span if i == 0 or i == 8: pygame.draw.line(MainGame.window, constants.BLACK, [x, MainGame.Start_Y], [x, MainGame.Max_Y], 1) else: pygame.draw.line(MainGame.window, constants.BLACK, [x, MainGame.Start_Y], [x, mid_end_y], 1) pygame.draw.line(MainGame.window, constants.BLACK, [x, min_start_y], [x, MainGame.Max_Y], 1) for i in range(0, 10): y = MainGame.Start_Y + i * MainGame.Line_Span pygame.draw.line(MainGame.window, constants.BLACK, [MainGame.Start_X, y], [MainGame.Max_X, y], 1) speed_dial_start_x = MainGame.Start_X + 3 * MainGame.Line_Span speed_dial_end_x = MainGame.Start_X + 5 * MainGame.Line_Span speed_dial_y1 = MainGame.Start_Y + 0 * MainGame.Line_Span speed_dial_y2 = MainGame.Start_Y + 2 * MainGame.Line_Span speed_dial_y3 = MainGame.Start_Y + 7 * MainGame.Line_Span speed_dial_y4 = MainGame.Start_Y + 9 * MainGame.Line_Span pygame.draw.line(MainGame.window, constants.BLACK, [speed_dial_start_x, speed_dial_y1], [speed_dial_end_x, speed_dial_y2], 1) pygame.draw.line(MainGame.window, constants.BLACK, [speed_dial_start_x, speed_dial_y2], [speed_dial_end_x, speed_dial_y1], 1) pygame.draw.line(MainGame.window, constants.BLACK, [speed_dial_start_x, speed_dial_y3], [speed_dial_end_x, speed_dial_y4], 1) pygame.draw.line(MainGame.window, constants.BLACK, [speed_dial_start_x, speed_dial_y4], [speed_dial_end_x, speed_dial_y3], 1) def piecesInit(self): MainGame.piecesList.append(pieces.Rooks(MainGame.player2Color, 0, 0)) MainGame.piecesList.append(pieces.Rooks(MainGame.player2Color, 8, 0)) MainGame.piecesList.append(pieces.Elephants(MainGame.player2Color, 2, 0)) MainGame.piecesList.append(pieces.Elephants(MainGame.player2Color, 6, 0)) MainGame.piecesList.append(pieces.King(MainGame.player2Color, 4, 0)) MainGame.piecesList.append(pieces.Knighs(MainGame.player2Color, 1, 0)) MainGame.piecesList.append(pieces.Knighs(MainGame.player2Color, 7, 0)) MainGame.piecesList.append(pieces.Cannons(MainGame.player2Color, 1, 2)) MainGame.piecesList.append(pieces.Cannons(MainGame.player2Color, 7, 2)) MainGame.piecesList.append(pieces.Mandarins(MainGame.player2Color, 3, 0)) MainGame.piecesList.append(pieces.Mandarins(MainGame.player2Color, 5, 0)) MainGame.piecesList.append(pieces.Pawns(MainGame.player2Color, 0, 3)) MainGame.piecesList.append(pieces.Pawns(MainGame.player2Color, 2, 3)) MainGame.piecesList.append(pieces.Pawns(MainGame.player2Color, 4, 3)) MainGame.piecesList.append(pieces.Pawns(MainGame.player2Color, 6, 3)) MainGame.piecesList.append(pieces.Pawns(MainGame.player2Color, 8, 3)) MainGame.piecesList.append(pieces.Rooks(MainGame.player1Color, 0, 9)) MainGame.piecesList.append(pieces.Rooks(MainGame.player1Color, 8, 9)) MainGame.piecesList.append(pieces.Elephants(MainGame.player1Color, 2, 9)) MainGame.piecesList.append(pieces.Elephants(MainGame.player1Color, 6, 9)) MainGame.piecesList.append(pieces.King(MainGame.player1Color, 4, 9)) MainGame.piecesList.append(pieces.Knighs(MainGame.player1Color, 1, 9)) MainGame.piecesList.append(pieces.Knighs(MainGame.player1Color, 7, 9)) MainGame.piecesList.append(pieces.Cannons(MainGame.player1Color, 1, 7)) MainGame.piecesList.append(pieces.Cannons(MainGame.player1Color, 7, 7)) MainGame.piecesList.append(pieces.Mandarins(MainGame.player1Color, 3, 9)) MainGame.piecesList.append(pieces.Mandarins(MainGame.player1Color, 5, 9)) MainGame.piecesList.append(pieces.Pawns(MainGame.player1Color, 0, 6)) MainGame.piecesList.append(pieces.Pawns(MainGame.player1Color, 2, 6)) MainGame.piecesList.append(pieces.Pawns(MainGame.player1Color, 4, 6)) MainGame.piecesList.append(pieces.Pawns(MainGame.player1Color, 6, 6)) MainGame.piecesList.append(pieces.Pawns(MainGame.player1Color, 8, 6)) def piecesDisplay(self): # 遍历所有棋子,显示所有棋子 for item in MainGame.piecesList: item.displaypieces(MainGame.window) # MainGame.window.blit(item.image, item.rect) def getEvent(self): # 获取所有的事件 eventList = pygame.event.get() for event in eventList: if event.type == pygame.QUIT: self.endGame() elif event.type == pygame.MOUSEBUTTONDOWN: pos = pygame.mouse.get_pos() mouse_x = pos[0] mouse_y = pos[1] if (mouse_x > MainGame.Start_X - MainGame.Line_Span / 2 and mouse_x < MainGame.Max_X + MainGame.Line_Span / 2) and ( mouse_y > MainGame.Start_Y - MainGame.Line_Span / 2 and mouse_y < MainGame.Max_Y + MainGame.Line_Span / 2): print(str(mouse_x) + "" + str(mouse_y)) print(str(MainGame.Putdownflag)) if MainGame.Putdownflag != MainGame.player1Color: return click_x = round((mouse_x - MainGame.Start_X) / MainGame.Line_Span) click_y = round((mouse_y - MainGame.Start_Y) / MainGame.Line_Span) click_mod_x = (mouse_x - MainGame.Start_X) % MainGame.Line_Span click_mod_y = (mouse_y - MainGame.Start_Y) % MainGame.Line_Span if abs(click_mod_x - MainGame.Line_Span / 2) >= 5 and abs( click_mod_y - MainGame.Line_Span / 2) >= 5: print("有效点:x=" + str(click_x) + " y=" + str(click_y)) # 有效点击点 self.from_x = MainGame.clickx self.from_y = MainGame.clicky self.to_x = click_x self.to_y = click_y print(self.from_x) print(self.from_y) MainGame.clickx = click_x MainGame.clicky = click_y self.PutdownPieces(MainGame.player1Color, click_x, click_y) else: print("out") def PutdownPieces(self, t, x, y): selectfilter = list( filter(lambda cm: cm.x == x and cm.y == y and cm.player == MainGame.player1Color, MainGame.piecesList)) if len(selectfilter): MainGame.piecesSelected = selectfilter[0] return if MainGame.piecesSelected: print("MainGame.piecesSelected") arr = pieces.listPiecestoArr(MainGame.piecesList) if MainGame.piecesSelected.canmove(arr, x, y): self.PiecesMove(MainGame.piecesSelected, x, y) MainGame.Putdownflag = MainGame.player2Color else: fi = filter(lambda p: p.x == x and p.y == y, MainGame.piecesList) listfi = list(fi) if len(listfi) != 0: MainGame.piecesSelected = listfi[0] def PiecesMove(self, pieces, x, y): for item in MainGame.piecesList: if item.x == x and item.y == y: MainGame.piecesList.remove(item) pieces.x = x pieces.y = y print("move to " + str(x) + " " + str(y)) return True def Computerplay(self): if MainGame.Putdownflag == MainGame.player2Color: print("轮到电脑了") computermove = computer.getPlayInfo(MainGame.piecesList, self.from_x, self.from_y, self.to_x, self.to_y, self.mgInit) if computer == None: return piecemove = None for item in MainGame.piecesList: if item.x == computermove[0] and item.y == computermove[1]: piecemove = item self.PiecesMove(piecemove, computermove[2], computermove[3]) MainGame.Putdownflag = MainGame.player1Color # 判断游戏胜利 def VictoryOrDefeat(self): result = [MainGame.player1Color, MainGame.player2Color] for item in MainGame.piecesList: if type(item) == pieces.King: if item.player == MainGame.player1Color: result.remove(MainGame.player1Color) if item.player == MainGame.player2Color: result.remove(MainGame.player2Color) if len(result) == 0: return if result[0] == MainGame.player1Color: txt = "你失败了哦!" else: txt = "你胜利了哦!" MainGame.window.blit(self.getTextSuface("%s" % txt), (constants.SCREEN_WIDTH - 100, 200)) MainGame.Putdownflag = constants.overColor def getTextSuface(self, text): pygame.font.init() print(pygame.font.get_fonts()) font = pygame.font.SysFont('kaiti', 18) txt = font.render(text, True, constants.TEXT_COLOR) return txt def endGame(self): print("退出") exit()if __name__ == '__main__': MainGame().start_game()
非可视化中国象棋运行入口
import ChinaChess.my_chess as mcimport ChinaChess.chess_constants as ccimport numpy as np'''此文件为非可视化中国象棋运行入口'''class HistoryTable: # 历史启发算法 def __init__(self): self.table = np.zeros((2, 90, 90)) def get_history_score(self, who, step): return self.table[who, step.from_x * 9 + step.from_y, step.to_x * 9 + step.to_y] def add_history_score(self, who, step, depth): self.table[who, step.from_x * 9 + step.from_y, step.to_x * 9 + step.to_y] += 2 << depthclass Relation: def __init__(self): self.chess_type = 0 self.num_attack = 0 self.num_guard = 0 self.num_attacked = 0 self.num_guarded = 0 self.attack = [0, 0, 0, 0, 0, 0] self.attacked = [0, 0, 0, 0, 0, 0] self.guard = [0, 0, 0, 0, 0, 0] self.guarded = [0, 0, 0, 0, 0, 0]class my_game: def __init__(self): self.board = mc.chess_board() self.max_depth = cc.max_depth self.history_table = HistoryTable() self.best_move = mc.step() self.cnt = 0 def alpha_beta(self, depth, alpha, beta): # alpha-beta剪枝,alpha是大可能下界,beta是最小可能上界 who = (self.max_depth - depth) % 2 # 那个玩家 if self.is_game_over(who): # 判断是否游戏结束,如果结束了就不用搜了 return cc.min_val if depth == 1: # 搜到指定深度了,也不用搜了 # print(self.evaluate(who)) return self.evaluate(who) move_list = self.board.generate_move(who) # 返回所有能走的方法 # 利用历史表0 for i in range(len(move_list)): move_list[i].score = self.history_table.get_history_score(who, move_list[i]) move_list.sort() # 为了让更容易剪枝利用历史表得分进行排序 # for item in move_list: # print(item.score) best_step = move_list[0] score_list = [] for step in move_list: temp = self.move_to(step) score = -self.alpha_beta(depth - 1, -beta, -alpha) # 因为是一层选最大一层选最小,所以利用取负号来实现 score_list.append(score) self.undo_move(step, temp) if score > alpha: alpha = score if depth == self.max_depth: self.best_move = step best_step = step if alpha >= beta: best_step = step break # print(score_list) # 更新历史表 if best_step.from_x != -1: self.history_table.add_history_score(who, best_step, depth) return alpha def evaluate(self, who): # who表示该谁走,返回评分值 self.cnt += 1 # print('====================================================================================') relation_list = self.init_relation_list() base_val = [0, 0] pos_val = [0, 0] mobile_val = [0, 0] relation_val = [0, 0] for x in range(9): for y in range(10): now_chess = self.board.board[x][y] type = now_chess.chess_type if type == 0: continue # now = 0 if who else 1 now = now_chess.belong pos = x * 9 + y temp_move_list = self.board.get_chess_move(x, y, now, True) # 计算基础价值 base_val[now] += cc.base_val[type] # 计算位置价值 if now == 0: # 如果是要求最大值的玩家 pos_val[now] += cc.pos_val[type][pos] else: pos_val[now] += cc.pos_val[type][89 - pos] # 计算机动性价值,记录关系信息 for item in temp_move_list: # print('----------------') # print(item) temp_chess = self.board.board[item.to_x][item.to_y] # 目的位置的棋子 if temp_chess.chess_type == cc.kong: # 如果是空,那么加上机动性值 # print('ok') mobile_val[now] += cc.mobile_val[type] # print(mobile_val[now]) continue elif temp_chess.belong != now: # 如果不是自己一方的棋子 # print('ok1') if temp_chess.chess_type == cc.jiang: # 如果能吃了对方的将,那么就赢了 if temp_chess.belong != who: # print(self.board.board[item.from_x][item.from_y]) # print(temp_chess) # print(item) # print('bug here') return cc.max_val else: relation_val[1 - now] -= 20 # 如果不能,那么就相当于被将军,对方要减分 continue # 记录攻击了谁 relation_list[x][y].attack[relation_list[x][y].num_attack] = temp_chess.chess_type relation_list[x][y].num_attack += 1 relation_list[item.to_x][item.to_y].chess_type = temp_chess.chess_type # print(item) # 记录被谁攻击 # if item.to_x == 4 and item.to_y == 1: # print('--------------') # print(now_chess.chess_type) # print(item.from_x, item.from_y) # print('*************') # print(temp_chess.chess_type) # print(item.to_x, item.to_y) # print(relation_list[item.to_x][item.to_y].num_attacked) # print([relation_list[item.to_x][item.to_y].attacked[j] for j in range(relation_list[item.to_x][item.to_y].num_attacked)]) # if relation_list[item.to_x][item.to_y].num_attacked == 5: # print('###################') # self.board.print_board() # print('###################') relation_list[item.to_x][item.to_y].attacked[relation_list[item.to_x][item.to_y].num_attacked] = type relation_list[item.to_x][item.to_y].num_attacked += 1 elif temp_chess.belong == now: # print('ok2') if temp_chess.chess_type == cc.jiang: # 保护自己的将没有意义,直接跳过 continue # 记录关系信息-guard # print(item) # if item.to_x == 4 and item.to_y == 1: # print('--------------') # print(now_chess.chess_type) # print(item) # print('*************') # print(temp_chess.chess_type) # print(relation_list[item.to_x][item.to_y].num_guarded) # print([relation_list[item.to_x][item.to_y].guarded[j] for j in range(relation_list[item.to_x][item.to_y].num_guarded)]) # if relation_list[item.to_x][item.to_y].num_guarded == 5: # print('###################') # print(x, y, who) # self.board.print_board(True) # print('###################') relation_list[x][y].guard[relation_list[x][y].num_guard] = temp_chess relation_list[x][y].num_guard += 1 relation_list[item.to_x][item.to_y].chess_type = temp_chess.chess_type relation_list[item.to_x][item.to_y].guarded[ relation_list[item.to_x][item.to_y].num_guarded] = type relation_list[item.to_x][item.to_y].num_guarded += 1 # relation_list[x][y].chess_type = type for x in range(9): for y in range(10): num_attacked = relation_list[x][y].num_attacked num_guarded = relation_list[x][y].num_guarded now_chess = self.board.board[x][y] type = now_chess.chess_type now = now_chess.belong unit_val = cc.base_val[now_chess.chess_type] >> 3 sum_attack = 0 # 被攻击总子力 sum_guard = 0 min_attack = 999 # 最小的攻击者 max_attack = 0 # 最大的攻击者 max_guard = 0 flag = 999 # 有没有比这个子的子力小的 if type == cc.kong: continue # 统计攻击方的子力 for i in range(num_attacked): temp = cc.base_val[relation_list[x][y].attacked[i]] flag = min(flag, min(temp, cc.base_val[type])) min_attack = min(min_attack, temp) max_attack = max(max_attack, temp) sum_attack += temp # 统计防守方的子力 for i in range(num_guarded): temp = cc.base_val[relation_list[x][y].guarded[i]] max_guard = max(max_guard, temp) sum_guard += temp if num_attacked == 0: relation_val[now] += 5 * relation_list[x][y].num_guarded else: muti_val = 5 if who != now else 1 if num_guarded == 0: # 如果没有保护 relation_val[now] -= muti_val * unit_val else: # 如果有保护 if flag != 999: # 存在攻击者子力小于被攻击者子力,对方将愿意换子 relation_val[now] -= muti_val * unit_val relation_val[1 - now] -= muti_val * (flag >> 3) # 如果是二换一, 并且最小子力小于被攻击者子力与保护者子力之和, 则对方可能以一子换两子 elif num_guarded == 1 and num_attacked > 1 and min_attack < cc.base_val[type] + sum_guard: relation_val[now] -= muti_val * unit_val relation_val[now] -= muti_val * (sum_guard >> 3) relation_val[1 - now] -= muti_val * (flag >> 3) # 如果是三换二并且攻击者子力较小的二者之和小于被攻击者子力与保护者子力之和,则对方可能以两子换三子 elif num_guarded == 2 and num_attacked == 3 and sum_attack - max_attack < cc.base_val[ type] + sum_guard: relation_val[now] -= muti_val * unit_val relation_val[now] -= muti_val * (sum_guard >> 3) relation_val[1 - now] -= muti_val * ((sum_attack - max_attack) >> 3) # 如果是n换n,攻击方与保护方数量相同并且攻击者子力小于被攻击者子力与保护者子力之和再减去保护者中最大子力,则对方可能以n子换n子 elif num_guarded == num_attacked and sum_attack < cc.base_val[ now_chess.chess_type] + sum_guard - max_guard: relation_val[now] -= muti_val * unit_val relation_val[now] -= muti_val * ((sum_guard - max_guard) >> 3) relation_val[1 - now] -= sum_attack >> 3 # print('-------------------------') # print(base_val[0], pos_val[0], mobile_val[0], relation_val[0]) # print(base_val[1], pos_val[1], mobile_val[1], relation_val[1]) my_max_val = base_val[0] + pos_val[0] + mobile_val[0] + relation_val[0] my_min_val = base_val[1] + pos_val[1] + mobile_val[1] + relation_val[1] if who == 0: return my_max_val - my_min_val else: return my_min_val - my_max_val def init_relation_list(self): res_list = [] for i in range(9): res_list.append([]) for j in range(10): res_list[i].append(Relation()) return res_list def is_game_over(self, who): # 判断游戏是否结束 for i in range(9): for j in range(10): if self.board.board[i][j].chess_type == cc.jiang: if self.board.board[i][j].belong == who: return False return True def move_to(self, step, flag=False): # 移动棋子 belong = self.board.board[step.to_x][step.to_y].belong chess_type = self.board.board[step.to_x][step.to_y].chess_type temp = mc.chess(belong, chess_type) # if flag: # self.board.print_board() # print(self.board.board[step.to_x][step.to_y].chess_type) self.board.board[step.to_x][step.to_y].chess_type = self.board.board[step.from_x][step.from_y].chess_type # if flag: # print(self.board.board[step.from_x][step.from_y].chess_type) # print(self.board.board[step.to_x][step.to_y].chess_type) # print(step.to_x, step.to_y) self.board.board[step.to_x][step.to_y].belong = self.board.board[step.from_x][step.from_y].belong self.board.board[step.from_x][step.from_y].chess_type = cc.kong self.board.board[step.from_x][step.from_y].belong = -1 return temp def undo_move(self, step, chess): # 恢复棋子 self.board.board[step.from_x][step.from_y].belong = self.board.board[step.to_x][step.to_y].belong self.board.board[step.from_x][step.from_y].chess_type = self.board.board[step.to_x][step.to_y].chess_type self.board.board[step.to_x][step.to_y].belong = chess.belong self.board.board[step.to_x][step.to_y].chess_type = chess.chess_typeif __name__ == "__main__": game = my_game() game.board.print_board() while (True): from_x = int(input()) from_y = int(input()) to_x = int(input()) to_y = int(input()) s = mc.step(from_x, from_y, to_x, to_y) game.board.print_board() game.alpha_beta(game.max_depth, cc.min_val, cc.max_val) print(game.best_move) game.move_to(game.best_move) game.move_to(s) game.board.print_board()
3、参考文献
以下的代码冗长且复杂,文件多,我对他们的代码进行了注释并简化了不少,所以下载我的就行
转载地址:https://data-mining.blog.csdn.net/article/details/114787872 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!
发表评论
最新留言
不错!
[***.144.177.141]2024年04月22日 03时43分20秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
Linux 2.6内核Makefile浅析
2019-04-30
编译和链接的过程
2019-04-30
Git学习(二):git-rev-parse命令初识
2019-04-30
vim字符串替换
2019-04-30
C语言:堆和栈的区别是什么?
2019-04-30
C语言:二级指针(指向指针的指针)详解
2019-04-30
C语言:断言assert函数完全攻略
2019-04-30
C语言:命令行选项解析函数---getopt()和getopt_long()
2019-04-30
C语言:inline,static inline
2019-04-30
Git学习(三):Git 撤销commit文件 和 回退push的文件
2019-04-30
WAV系列之一:G711编解码原理及代码实现
2019-04-30
WAV系列之二:ADPCM编解码原理及代码实现
2019-04-30
详解shell中source、sh、bash、./执行脚本的区别
2019-04-30
Git学习(四):git clean的用法
2019-04-30
Linux命令(一): ln - 创建和删除软、硬链接
2019-04-30
C语言:static关键字的作用
2019-04-30
C语言:volatile关键字的作用
2019-04-30
/usr/bin/ld: skipping incompatible解决方案
2019-04-30
Gstreamer学习笔记(8):Gobject类对象
2019-04-30