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 location[10];
    int win_people = GetWinPeople();

    if(win_people == -1 || win_people == 1 ||depth == 0) {
       // qDebug() << CalEvalute()< 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博客 

你可能感兴趣的:(qt学习,数据结构,算法)