python实现AI井字棋极大极小算法和Alpha-beta算法

本文介绍了使用Python实现井字棋AI的极大极小搜索和Alpha-beta剪枝算法。详细阐述了算法思路,包括棋盘状态、先手判断、胜者检测、玩家和电脑下棋的逻辑,并给出了两种算法的流程图和部分运行结果展示。
部署运行你感兴趣的模型镜像

python实现AI井字棋极大极小算法和Alpha-beta算法

程序设计思路

大致思路:
井字棋最后的结果无非就是玩家赢、电脑赢和平局三种结果,而最后的结果正对应这整棵棋盘生成树的叶子节点,那么可以把玩家赢、电脑赢和平局三种结果赋值,然后根据当前深度是Max层还是Min层来,往上推出该子节点的父子节点的值,一直往上走到根节点,这也正是极大极小搜索的一个过程,而alpha-beta算法只要在极大极小上加以修改即可。

主要步骤和代码

1、 棋盘:用一个长度为9的数组存储每一位的字符,其中空位为‘-’,玩家棋子默认为‘O’,电脑玩家默认为‘#’,该数组为全局变量;定义print_board()函数来输出当前棋盘状况;定义reset_board()函数来重置棋盘;
2、 先手问题:定义一个变量first,根据输入来定义先手,输入1为玩家先手,输入-1为电脑先手;

first=0#先手变量,玩家先手为1,电脑先手为-1
board_list=['-' for i in range(9)]#棋盘位置以数组存储

#重置棋盘
def reset_board():
    global board_list#将其定义成全局变量
    board_list=['-' for i in range(9)]

#输出棋盘
def print_board():
    print("棋盘:")
    for i in range(1,10):
        if i%3==0:
            print(board_list[i-1])
        else:
            print(board_list[i-1],end="")
    return board_list

3、 胜者判断:定义check_win( )函数来判断当前是否有练成一线的情况,胜利的情况有8种,水平线3种,竖直线3种,斜线2种,根据位置的下标加以判断;定义winner( )函数判断赢家,如果是玩家先手,则玩家赢赋值为1,电脑赢为-1,平局为0;如果是电脑赢,则电脑赢赋值为1,玩家赢为-1,平局为0,这样可以方便Max和Min的区别;

#判断胜负
def check_win(tag):
    return ((board_list[0] == tag and board_list[1] == tag and board_list[2] == tag) or # 顶水平连线
    (board_list[3] == tag and board_list[4] == tag and board_list[5] == tag) or # 中间水平连线
    (board_list[6] == tag and board_list[7] == tag and board_list[8] == tag) or # 底部水平连线
    (board_list[0] == tag and board_list[3] == tag and board_list[6] == tag) or # 左侧垂直连线
    (board_list[1] == tag and board_list[4] == tag and board_list[7] == tag) or # 中间垂直连线
    (board_list[2] == tag and board_list[5] == tag and board_list[8] == tag) or # 右侧垂直连线
    (board_list[0] == tag and board_list[4] == tag and board_list[8] == tag) or # 左斜线
    (board_list[2] == tag and board_list[4] == tag and board_list[6] == tag)) # 右斜线

#判断赢家
def winner():
    '''
    当玩家先手时,max为玩家,所以返回1表示玩家赢,返回-1表示电脑赢,返回0表示平局或者还没结束;
    当电脑先手时,max为电脑,所以返回1表示电脑赢,返回-1表示玩家赢,返回0表示平局或者还没结束。
    '''
    if check_win('O')==True and first==1 or check_win('X') and first==-1:
        return 1
    elif check_win('X')==True and first==1 or check_win('O') and first==-1: 
        return -1
    else:
        return 0

4、 玩家下棋:定义player( )函数来实现玩家下棋,通过输入位置0-8来下自己想要下的位置,同时也需要判断下得位置是否能下;

#玩家下棋
def player():
    while(1):
        print("输入想要走的位置,0-8:")
        number=int(input())
        if board_list[number]=='-':
            board_list[number]='O'
            break
        else:
            print("该位置有棋子!请输入数字0-8!")
            continue   

5、 极大极小算法:定义max_min_search( )函数实现极大极小算法。把玩家赢、电脑赢和平局三种结局的赋值当作当前叶子节点的评估值,然后根据当前深度是Max层还是Min层来,往上推出该子节点的父子节点的值,一直往上走,这一过程可以通过递归函数生成。比如玩家先手下了一个棋子,那么轮到电脑时,电脑调用极大极小算法,把剩下每个空位的值给算出来,然后比较选出这些位置中算出值最小的一个位置,而这计算空位的值时,电脑会自行模拟玩家选择当前最优的一步,这样自己交替下棋,完成一个棋盘的整个下棋动作。

#极大极小值算法
def max_min_search(player,nextplayer):
    '''
    通过递归,从叶子节点,推出父子节点(即往上推出)的值,该树的取值只有三种要么1,要么-1,要么0。
    player:当前玩家;
    nextplayer:下一个玩家;
    '''
    global first
    max_val=-2
    min_val=2
    win=winner()
    #如果是叶子节点,即最后棋局结果,就返回胜利者的值
    if win!=0:
        return win
    #如果下满没有赢家,为平局
    elif '-' not in board_list:
        return 0
    #如果不是叶子节点,则通过叶子节点来推出当下节点的值。遍历当前所有能下的位置,找到这层节点中最大或者最小的值。
    for left_index in range(len(board_list)):
        if board_list[left_index]=='-':
            board_list[left_index]=player
            val=max_min_search(nextplayer,player)
            board_list[left_index]='-'#还原
            if player=='O' and first==1 or player=='X' and first==-1:
                if max_val<val:
                    max_val=val
            elif player=='X' and first==1 or player=='O' and first==-1:
                if min_val>val:
                    min_val=val
    #需要对先手情况进行判断,先手返回的是max,后手返回的是min,然后将最大或者最小的值传给父子节点
    if player=='O' and first==1 or player=='X' and first==-1:
        reval=max_val
    elif player=='X' and first==1 or player=='O' and first==-1:
        reval=min_val
    return reval

6、 Alpha-beta算法:定义alpha_beta_search( )函数实现Alpha-beta算法。在极大极小算法的基础上,加入alpha和beta来进行剪枝,因为这里三种结果的赋值为-1、0、1,这里设置alpha初始值为-2,beta值为2;如果当前子节点的父子节点为Min层,那么根据第一个子节点得出beta值下界,如果后面子节点比beta大则进行剪枝不再往下深究,如果后面子节点有比beta小的则更新beta的值,最后把全部子节点筛选完,父子节点就为beta值;如果当前子节点的父子节点为Max层,那么根据第一个子节点得出alpha值上界,如果后面子节点有比alpha小则进行剪枝,不再往下进行深究,alpha大的值则更新alpha,最后把全部子节点筛选完,父子节点就是alpha值。

#alpha-beta算法
def alpha_beta_search(player,nextplayer,alpha,beta):
    global first
    win=winner()
    if win!=0:
        return win
    elif '-' not in board_list:
        return 0
    for left_index in range(len(board_list)):
        if board_list[left_index]=='-':
            board_list[left_index]=player
            val=alpha_beta_search(nextplayer,player,alpha,beta)
            board_list[left_index]='-'
            if player=='O' and first==1 or player=='X' and first==-1:
                if alpha<val:
                    alpha=val
                if alpha>=beta:
                    return beta #直接返回当前的最大值beta,进行剪枝
            elif player=='X' and first==1 or player=='O' and first==-1:
                if beta>val:
                    beta=val
                if beta<=alpha:
                    return alpha #直接返回当前的最小值beta,进行剪枝
    #需要对先手情况进行判断,先手返回的是max,后手返回的是min,然后将最大或者最小的值传给父子节点
    if player=='O' and first==1 or player=='X' and first==-1:
        reval=alpha
    elif player=='X' and first==1 or player=='O' and first==-1:
        reval=beta
    return reval

7、 电脑下棋:定义一个computer( )函数来实现电脑下棋,通过调用max_min_search( )或者alpha_beta_search( ),来推算出当前最优的下棋位置。这个推算过程中,电脑也来模拟人下棋,也是调用极大极小算法或者alpha-beta算法,算出当前对玩家最优位置。假设玩家先手走了第一部棋子,电脑把剩下的空位都走一遍第二步棋,电脑自行模拟玩家走第三步棋子,也是调用相应算法得出当前玩家最优的位置,这样轮流走到最后结果,然后电脑选出最后局面中对自己最优的结果,回溯得到第二步棋子应该下什么(假设玩家先手下了第一步棋)。

#电脑决定下棋位置
def computer():
    '''
    best_val:用来记录先手为玩家时,电脑取min时,能取的最小值
    best_val2:用来记录先手为电脑时,电脑取max时,能取的最大值
    my_moves:用来记录电脑能走的位置
    '''
    best_val=2
    best_val2=-2
    my_moves=[]
    for index in range(len(board_list)):
        if board_list[index]=='-':
            board_list[index]='X'
            val=max_min_search('O','X')
            #val=alpha_beta_search('O','X',-2,2)
            board_list[index]='-'
            if first==1:
                if val < best_val:
                    best_val=val
                    my_moves=[index]
                elif val==best_val:
                    my_moves.append(index)
            elif first==-1:
                if val > best_val2:
                    best_val2=val
                    my_moves=[index]
                elif val==best_val2:
                    my_moves.append(index) 
    print(my_moves)              
    return random.choice(my_moves)

8、主函数:

def main():
    while(1):
        global first
        while(1):
            first=int(input('选择是先手对象,如果选择玩家则输入1,选择电脑输入-1,退出输入0:'))
            if first==-1 or first==1 or first==0:
                next_move=first
                break
            else:
                print('输入错误!重新输入!')
                continue
        if next_move==0:
            break
        while '-' in board_list and winner()==0:
            print_board()
            if next_move==1 and '-' in board_list:
                player()
                next_move=-1
            if next_move==-1 and '-' in board_list:
                computer_move=computer()
                board_list[computer_move]='X'
                next_move=1
                print('电脑走了'+str(computer_move))
        print_board()
        if first==1:
            print(["电脑赢了", "平局", "你赢了"][winner()+1])
        else:
            print(["你赢了", "平局", "电脑赢了"][winner()+1])
        reset_board()

main()

对于两个算法流程图

根据个人理解手写的,写得不好多见谅!如果实在理解不了可以在csdn再搜索,挺多的!
在这里插入图片描述
在这里插入图片描述

运行结果

结果挺多的,在这里我就贴一张极大极小算法玩家先手的情况:
电脑胜利:
在这里插入图片描述
平局:
在这里插入图片描述

您可能感兴趣的与本文相关的镜像

Python3.8

Python3.8

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值