五子棋ai:极大极小搜索和α-β剪枝算法的思想和实现(qt和c++)(四)算杀模块的简单实现

一、什么是算杀?为什么要算杀?

算杀就是只算杀棋

我用五子棋ai跟别人下了一阵子之后发现,用博弈树看6层深度(模拟ai走4步,模拟人走3步)其实根本不够,因为真正的高手看到的远比6层要多。高手进行谋划以后,一开始走看似“不那么重要”的位置,然后就可以形成双活3或者活4的必杀棋型打败ai。我实现的ai其实还非常短视,也就是只能看到6层以内的利益,而看不到更大的、全局的利益。

这里我参考了这位大佬的文章,写的非常好,无奈我不是很能看懂,也只能凭自己的理解写算杀了:五子棋AI算法第五篇-算杀。

怎么样让电脑也能这样进行“谋划”?一个简单的思路就是算杀。算杀是只算杀棋,很容易想到,算杀也是一个极大极小搜索,只不过不用考虑10个节点(之前实现的),只需要考虑白棋(ai)的杀棋节点(形成新的连5、活4、冲4、活3),黑棋只考虑最好的那个节点,那么分支数b极大减少,搜索深度可以达到16层以上(很多搜不到16层,因为没有那么多的杀棋节点),达到搜索深度之前,只要有一个节点白棋获胜了,算杀就成功了。这就是我简单实现的算杀模块。

我实现的算杀功能比较简单,但也进一步提升了棋力。

二、具体实现

首先进行算杀,如果算杀成功就用算杀的点,如果不成功就用原来6层极大极小搜索找到的点

首先是找白棋的杀棋点。

QList<QPoint> chessAi::seek_kill_points(int (*board)[15]){//找白棋的连5,活4,冲4,活3的杀棋位置
    QList<QPoint> pointList;

    POINTS P=seekPoints(board);//一般来说,能冲4或者活3的必在评分前20的点内

    int sameBoard[15][15];
    copyBoard(board,sameBoard);

    for(int i=0;i<20;++i){
        sameBoard[P.pos[i].x()][P.pos[i].y()]=C_WHITE;//模拟落子
        if(evaluate(sameBoard).STAT[WIN]>0){//产生连5
            pointList.append(P.pos[i]);
        }else if(evaluate(sameBoard).STAT[FLEX4]>evaluate(board).STAT[FLEX4]){//产生新活4
            pointList.append(P.pos[i]);
        }else if(evaluate(sameBoard).STAT[BLOCK4]>evaluate(board).STAT[BLOCK4]){//产生新冲4
            pointList.append(P.pos[i]);
        }else if(evaluate(sameBoard).STAT[FLEX3]>evaluate(board).STAT[FLEX3]){//产生新活3
            pointList.append(P.pos[i]);
        }
        sameBoard[P.pos[i].x()][P.pos[i].y()]=C_NONE;//还原落子
    }
    return pointList;
}

简单算杀模块

struct EVALUATION{
    int score;
    gameResult result;
    int STAT[8];//储存部分棋形的个数,下标WIN=1为白连5,LOSE=2为黑连5,FLEX4=3为白活4,BLOCK4=5为白冲4,FLEX3=7为白活3
};
struct POINTS{//最佳落子位置,[0]分数最高,[19]分数最低
    QPoint pos[20];
    int score[20];//此处落子的局势分数
};
struct DECISION{
    QPoint pos;//位置
    int eval;//对分数的评估
};

DECISION decision;

bool chessAi::analyse_kill(int (*board)[15], int depth){
    EVALUATION EVAL=evaluate(board);
    if(depth==0||EVAL.result!=R_DRAW){
        if(depth==0){//若抵达最深层,走一步对白棋的最好位置,若白棋还没赢则返回false
            POINTS P;
            P=seekPoints(board);            
            board[P.pos[0].x()][P.pos[0].y()]=C_WHITE;

            gameResult result=evaluate(board).result;
            if(result==R_WHITE)return true;
            else return false;
        }else if(EVAL.result==R_WHITE)return true;//找到白棋杀棋
        else return false;//白棋输
    }else if(depth%2==0){//max层,我方(白)决策
        QList<QPoint> pointList=seek_kill_points(board);//产生杀棋点

        if(pointList.length()==0)return false;//没有杀棋点
        for(auto i:pointList){ 
            int sameBoard[15][15];
            copyBoard(board,sameBoard);

            sameBoard[i.x()][i.y()]=C_WHITE;//模拟己方落子
            if(analyse_kill(sameBoard,depth-1)){
                if(depth==16){//开始层,需决定落子,结果存于decision中
                    decision.pos.setX(i.x());
                    decision.pos.setY(i.y());
                    decision.eval=INT_MAX;//杀棋评分没有作用
                }
                return true;
            }
        }
        return false;
    }else{//min层,敌方(黑)决策,只下对自己最好的棋
        int rBoard[15][15];
        reverseBoard(board,rBoard);
        POINTS P=seekPoints(rBoard);//找对于黑子的最佳位置,需要将棋盘不同颜色反转,因为seekPoint是求白色方的最佳位置

        int sameBoard[15][15];
        copyBoard(board,sameBoard);

        sameBoard[P.pos[0].x()][P.pos[0].y()]=C_BLACK;//模拟敌方落子:只走最好的一步
        //无需剪枝
        return analyse_kill(sameBoard,depth-1);
    }
}

//调用
if(!ai.analyse_kill(ai.chesses,16)){
     qDebug()<<"没找到杀棋";
     ai.analyse(ai.chesses,6,-INT_MAX,INT_MAX);
}else{
     qDebug()<<"找到了杀棋";
}

结束

简单写了一个算杀模块,还是提升了部分棋力。

棋类博弈知识还是很值得去研究的,在知网上找资料的时候我竟然发现可以用五子棋ai作为硕士毕业论文,看了以后感觉。。国内论文审查的确比较水。真正的高手都在GitHub上啊!

你可能感兴趣的:(c++,qt,ai,博弈论,算法)