Python实现基于极大极小值算法的井字棋对弈

运行效果

当前棋盘:
|   |   |   |
|   |   |   |
|   |   |   |

AI为 'o' 棋,玩家为 'x' 棋,玩家先
放置棋子输入格式:行号,列号(数值为0/1/2)
请输入要放置棋的坐标:0,1
当前棋盘:
|   | o |   |
|   |   |   |
|   |   |   |

AI进行下一步...
当前棋盘:
|   | o |   |
|   | x |   |
|   |   |   |

请输入要放置棋的坐标:0,0
当前棋盘:
| o | o |   |
|   | x |   |
|   |   |   |

AI进行下一步...
当前棋盘:
| o | o | x |
|   | x |   |
|   |   |   |

请输入要放置棋的坐标:2,0
当前棋盘:
| o | o | x |
|   | x |   |
| o |   |   |

AI进行下一步...
当前棋盘:
| o | o | x |
| x | x |   |
| o |   |   |

请输入要放置棋的坐标:1,2
当前棋盘:
| o | o | x |
| x | x | o |
| o |   |   |

AI进行下一步...
游戏结束!平局

核心代码

def cal_win_value(chessboard: Chessboard):
    """
    计算当前棋盘AI的得分(AI能赢解个数减去玩家能赢的解个数)
    :param chess_type 要判断的棋子种类
    """
    # 如果用户直接可以赢,则得分无穷小,采取防守策略
    win, winner_chess = chessboard.can_win()
    if not win and winner_chess is 'both':
        print("游戏结束!平局")
        exit()
    elif win and winner_chess is chess_player:
        return MIN

    num_map = {
        chess_ai: 0,
        chess_player: 0
    }

    # 分别计算当前棋局AI以及玩家能赢的解有多少种
    for chess_type in [chess_ai, chess_player]:
        temp_board = chessboard.copy_new()

        # 将空位全部填充为某一类型的棋子
        for row in range(3):
            for col in range(3):
                if temp_board.data[row][col] is not the_other(chess_type):
                    temp_board.data[row][col] = chess_type
        # 计算横向可以赢的个数
        for row in range(3):
            row_status = True
            for col in range(3):
                if temp_board.data[row][col] is not chess_type:
                    row_status = False
            if row_status is True:
                num_map[chess_type] += 1
        # 计算纵向可以赢的个数
        for col in range(3):
            col_status = True
            for row in range(3):
                if temp_board.data[row][col] is not chess_type:
                    col_status = False
            if col_status is True:
                num_map[chess_type] += 1
        # 检查主对角线可以赢的个数
        main_diag_status = True
        for i in range(3):
            if temp_board.data[i][i] is not chess_type:
                main_diag_status = False
        if main_diag_status is True:
            num_map[chess_type] += 1
        # 检查副对角线可以赢的个数
        para_diag_status = True
        for i in range(3):
            if temp_board.data[2 - i][i] is not chess_type:
                para_diag_status = False
        if para_diag_status is True:
            num_map[chess_type] += 1
    return num_map[chess_ai] - num_map[chess_player]


def cal_total_value(chessboard: Chessboard, x_ai, y_ai):
    """
    计算将要进行的一步棋的总得分
    """
    total_value = 0
    # win, winner_chess = chessboard.can_win()
    # if win and winner_chess is chess_ai:
    #     return MAX
    # elif win and winner_chess is chess_player:
    #     return -MIN

    # 新建一个临时的棋盘,模拟之后的两步
    temp_board = chessboard.copy_new()

    if temp_board.can_put(x_ai, y_ai):
        # AI走一步
        temp_board.put_chess(chess_ai, x_ai, y_ai)
        # AI可以绝杀
        win, winner_chess = temp_board.can_win()
        if win:
            return MAX
        # 若不能绝杀,则需要预测玩家,计算最大得分的解
        empty_psts = chessboard.get_empty_psts()
        # 遍历所有空位置,模拟玩家走一步
        for x_player, y_player in empty_psts:
            inner_temp_board = temp_board.copy_new()

            if inner_temp_board.can_put(x_player, y_player):
                # 玩家走一步
                inner_temp_board.put_chess(chess_player, x_player, y_player)
                # 计算当前棋盘的得分
                value = cal_win_value(inner_temp_board)
                total_value += value
    return total_value


def ai_put(chessboard: Chessboard):
    """
    AI放置一枚棋子
    :param chessboard:
    :return:
    """
    empty_psts = chessboard.get_empty_psts()
    max_value = MIN
    for row, col in empty_psts:
        value = cal_total_value(chessboard, row, col)
        if value > max_value:
            max_value = value
            determined_x = row
            determined_y = col
    chessboard.put_chess(chess_ai, determined_x, determined_y)

完整代码

我将积累的一些算法发布到了Gihub仓库中,其中涉及一些常见的算法以及人工智能方面的算法,其中有该程序的完整实现代码。
仓库地址:https://github.com/yub1ng/Algorithm
个人博客地址:http://qiyubing.cn

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,682评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,277评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,083评论 0 355
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,763评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,785评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,624评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,358评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,261评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,722评论 1 315
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,900评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,030评论 1 350
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,737评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,360评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,941评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,057评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,237评论 3 371
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,976评论 2 355