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 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:python_长短期记忆模型LSTM_公交短时客流预测
下一篇:python_强化学习算法DQN_玩五子棋游戏

发表评论

最新留言

不错!
[***.144.177.141]2024年04月22日 03时43分20秒