Qt井字棋人机互博之Max-Min算法

        之前做了最基础的井字棋游戏,就是人人模式,双方互相下,判断输赢,现在把功能稍微的提升了一下,使用Max-Min算法得到电脑下棋的最优点。

        这里我就简单的介绍一下Max-Min算法和在我写的这个井字棋游戏之中他是如何使用的。

        井字棋游戏和五子棋等等都是博弈游戏,而博弈游戏的算法都秉持着一个目的:最大化自己的利益,最小画别人的利益。

        自己对Max-Min算法的理解

        这个算法又叫做极大极小值算法,根据我粗略的研究就是将所有可能的方案按照树形结构画出开,这种博弈类游戏有先后手,对应的就是Max和Min,你将所有的可能列举出来,然后从最好的结果一路往上推,就会得到对你最有利的一条路径,也可以说是走棋的方法。

       怎么判断如何选择对你有利,就需要设计一个估算的函数,类似于五子棋和井字棋,就可以是计算出当前所有的空格放上玩家的棋子,得到的练成五或者三的数目。

        每次比较所有可能算法的复杂度太高,所以呢会用到剪枝算法,就是将不影响结果的那些可能全部砍掉,这样就会减少计算。

        游戏代码:

        估算函数:

        

int Widget::CalEvalute(){

    //判断此时是否以及结束
    int win_people = GetWinPeople();
    if(win_people == -1) return N;//玩家2或者电脑赢 返回最大
    if(win_people == 1) return -N;//玩家1胜利 返回最小

    //胜负未分
    int value = 0;
    int new_chess[3][3];//临时棋盘

    //计算机估值

    //遍历棋盘所有的格子
    for(int i=0;i<3;i++){
        for(int j=0;j<3;j++){
            if(chess[i][j] == 0){
                new_chess[i][j] == -1;//没有下棋的地方赋值为-1
            }
            else {
                new_chess[i][j] = chess[i][j];//下了的地方保持
            }
        }
    }//这一步 电脑所有能走的地方变成了-1  玩家下了的地方变成了1

    //value  加上 练成三线的个数  和不等于三或者-3 /3一定为0
    for(int i = 0;i<3;i++){
        value = value - (new_chess[i][0] + new_chess[i][1] + new_chess[i][2])/3;
    }
    for(int i = 0; i < 3; ++ i) //对于垂直方向
        value = value - (new_chess[0][i] + new_chess[1][i] + new_chess[2][i])/3;
    value = value - (new_chess[0][0] + new_chess[1][1] + new_chess[2][2])/3;//主对角线
    value = value - (new_chess[2][0] + new_chess[1][1] + new_chess[0][2])/3;//副对角线

    //人类
    for(int i = 0; i < 3; ++ i){
        for(int j = 0; j < 3; ++ j){
            if(chess[i][j] == 0) new_chess[i][j] = 1;
            else new_chess[i][j] = chess[i][j];
        }
    }

    for(int i = 0; i < 3; ++ i) //对于水平方向
        value = value - (new_chess[i][0] + new_chess[i][1] + new_chess[i][2])/3;
    for(int i = 0; i < 3; ++ i) //对于垂直方向
        value = value - (new_chess[0][i] + new_chess[1][i] + new_chess[2][i])/3;
    value = value - (new_chess[0][0] + new_chess[1][1] + new_chess[2][2])/3;//主对角线
    value = value - (new_chess[2][0] + new_chess[1][1] + new_chess[0][2])/3;//副对角线

    return value;
}

        Min-Max

int Widget::MinMaxSolution(int depth, int alpha, int beta)
{

    int cur_value = 0, best_value = 0, cnt = 0;
    pair<int, int> location[10];
    int win_people = GetWinPeople();

    if(win_people == -1 || win_people == 1 ||depth == 0) {
       // qDebug() << CalEvalute()<<endl;
        return CalEvalute();
    }

    //深度未耗尽,给定初始值
    if(cur_player == -1) best_value = -N;
    else if(cur_player == 1) best_value = N;

    //获取棋盘上剩余的位置
    for(int i = 0; i < 3;  ++ i){
        for(int j = 0; j < 3; ++ j){
            if(chess[i][j] == 0){
                //qDebug()<<i<<","<<j<<endl;
                location[cnt].first = i;
                location[cnt++].second = j;
            }
        }
    }


    if(cnt < 1) {
        best_point = location[0];
        return best_value;
    }

    for(int i = 0; i < cnt; ++ i){
        pair<int, int> cur_pos = location[i];
        int x = cur_pos.first, y = cur_pos.second;
        chess[x][y] = cur_player;   //当前点下一个棋
        cur_player = (cur_player == 1) ? -1 : 1;//换下一个棋手

        cur_value = MinMaxSolution(depth - 1, alpha, beta);  //向下递归

        chess[x][y] = 0;  //取消下棋
        cur_player = (cur_player == 1) ? -1 : 1;

        if(cur_player == -1){   // 当前玩家是Max节点
            if(cur_value > best_value){
                best_value = cur_value;
                if(depth == cur_depth) best_point = cur_pos;
                alpha = best_value;
            }
            if(beta <= alpha) return beta;  // Max中上界小于下界 返回较小值
        }
        else if(cur_player == 1){   // 当前是Min节点
            if(cur_value < best_value){
                best_value = cur_value;
                if(depth == cur_depth) best_point = cur_pos;
                beta = best_value;
            }
            if(beta <= alpha) return alpha; // Min中上界小于下界 返回较大值
        }
    }

    return best_value;
}

        这里推荐一下关于这个算法讲解的地址和博客,希望对大家有帮助

   https://www.bilibili.com/video/BV1bT4y1C7P5/?spm_id_from=333.337.search-card.all.click&vd_source=4796b18a2e4c1ec8a310391a5644b6da

井字游戏/一字棋——Max-Min智能算法_maxmin算法-CSDN博客 

  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值