五子棋算法問題(求解)


各位大佬。。。。我在解決老師布置的作業——Qt實現五子棋游戲中,出現了一些問題,我獨自想了幾天也無法解決,便求助一下大神們。
因為我們都是新手,也才接觸Qt,於是老師讓我們一個小組完成一個任務,我們的任務也就是五子棋。
在我負責寫的AI算法的中,出現了一些問題。我先簡單介紹一下我大概的想法:
  因為是采用打分制,首先獲取每個空位周圍的棋子信息,並存入信息數組(ChessInfo)。
  通過空位周圍的信息,判斷預落子在這個空位后,能夠構成多少個同樣的子相連,記為count數。
  通過count數和周圍子的信息,判斷棋型(5連啊,活4啊,活3啊那些),並根據棋型給分。
  根據給分的高低下棋。
之后便是我沒能實現的地方,我有兩個分值數組,分別是當前棋子和敵對棋子形勢下的分數(myScore和hisScore)。我想通過這兩個存儲分值的數組判斷是進攻還是防守:(其中用到了一個myMaxScore和hisMaxScore變量,分別代表兩個數組中的最大值)
  如果myMaxScore>=hisMaxScore,則進攻,下我方形勢最大值myMaxScore對應的位置;如果有多個myMaxScore相等,則下這幾個對應位置上hisMaxScore最大的位置。
  否則,防守,下敵方形勢最大值hisMaxScore對應的位置。如果有多個hisMaxScore相等,則下這幾個對應位置上myMaxScore最大的位置。
我的AI在連成4顆子后,被堵住一方,就不再在另一方能連成5顆子的地方下,另外,我的AI也無法堵住對方的棋子,下在奇奇怪怪的地方,,,,
請哪位大神指教一下,,,或者哪里有我沒想到的錯誤,請提醒我一下,小弟在此先謝過了。。。。(因為老師給我們的綠色版的Qt,沒有調試器,我之前嘗試配置調試器的時候還把電腦弄出問題,結果重新裝了系統。而我們這個項目又是在老師給的這個綠色版的Qt上運行的,所以我下載新的Qt之后,或者時候Visual Studio 2017的時候還是沒法調試,最后我。。。只能一句一句的寫qDebug()來調試了,真的。。。心塞。)

下面是我的代碼:
#define NO_THREAT 0
#define BLANK 0
#define WIN5 100000
#define ALIVE4 20000
#define ALIVE3 4500
#define DIE4 1000
#define ALIVE2 200
#define DIE3 45
#define DIE2 10
(分值我是隨意定的。。。只考慮了不讓四個方向上的分數加起來超過更高一級的棋型。。)
//電腦下棋---------------------------------------------------------------------------
void Chessboard::computerPlaceChess(int myChess){
    //判斷棋型(暫時考慮五連,活四,沖四,活三,死三,活二,死二,其他棋型以及禁手后續擴充)
    int dx[8]={-1,-1,0,1,1,1,0,-1};
    int dy[8]={0,1,1,1,0,-1,-1,-1};
    int myScore[15][15];//創建兩個數組存儲對應兩方的空位分數
    int hisScore[15][15];
    int countOfBlank=0;
    int hisChess=myChess==1?2:1;//黑子為1,白子為2
    //循環查找每一位
    for(int i=0;i<15;i++){
        for(int j=0;j<15;j++){
            if(chess[i+1][j+1]==0){//空位個數++
                countOfBlank++;
            }else{//非空給分,並直接跳
                hisScore[i][j]=0;
                myScore[i][j]=0;
                continue;
            }
            //在4條直線方向,獲取預置點兩端的8個點的棋盤信息
            int step1=0,r=1,c=1;//step代表直線,r,c分別代表加上偏移量之后的坐標
            int count=1,myCount=1,hisCount=1;//與中心點相連接的同色子的個數,myCount用於myScore,hisCount用於hisScore
            int chessInfo[4][8];//定義4個存儲每條直線上的,預置點附近點的信息.一維0,1,2,3分別為豎直,k=1,水平,k=-1的直線.
            //存儲方式:如水平線上,預置點左邊3個與右邊3個,如chess[2][8]={左3,左2,左1,左,右,右1,右2,右3},其他同理.
            //存儲信息並判斷分數

            for(step1;step1<4;step1++) {


                for(int changeCount=0;changeCount!=2;changeCount++){
                    int dir = step1;
                    int nowChess;
                    if(changeCount==0){//改變判斷棋子的角度
                        nowChess=myChess;
                        //qDebug()<<__LINE__<<nowChess;
                    }else{
                        nowChess=myChess==1?2:1;
                        //qDebug()<<__LINE__<<nowChess;
                    }
                    for(int k=0;k<4;k++){//每個方向取4個子的信息
                        if(k==0){
                            switch(step1){//前四個方向的初始值,通過基點位置加偏移量的方式,獲取附近的點信息
                            case 0:
                                r=i-1+1;//由於寫框架的同學使用的16*16的棋盤,而我的i,j都從0開始,並且有15*15的計分數組使用了i,j,所以在使用到期盼的地方都添加+1操作
                                c=j+1;
                            case 1:
                                r=i-1+1;
                                c=j+1+1;
                            case 2:
                                r=i+1;
                                c=j+1+1;
                            case 3:
                                r=i+1+1;
                                c=j+1+1;
                            }
                        }
                        if(r<1 || c<1 || r>15  || c>15){
                            break;
                        }
                        if(chess[r][c]==nowChess){
                            count++;
                            chessInfo[step1][3-k]=nowChess;
                            r+=dx[dir];
                            c+=dy[dir];
                        }else{
                            chessInfo[step1][3-k]=chess[r][c];
                        }
                    }
                    for(int k=0;k<4;k++){
                        dir+=4;
                        if(k==0){
                            switch(step1){//后四個方向的初始值
                            case 0:
                                r=i+1+1;
                                c=j+1;
                            case 1:
                                r=i+1+1;
                                c=j-1+1;
                            case 2:
                                r=i+1;
                                c=j-1+1;
                            case 3:
                                r=i-1+1;
                                c=j-1+1;
                            }
                        }
                        if(r<1 || c<1 || r>15  || c>15){
                            break;
                        }
                        if(chess[r][c]==nowChess){
                            count++;
                            chessInfo[step1][k+4]=nowChess;
                            r+=dx[dir];
                            c+=dy[dir];
                        }else{
                            chessInfo[step1][k+4]=chess[r][c];
                        }
                    }

                    myCount=changeCount==0?count:myCount;
                    hisCount=changeCount==1?count:hisCount;
                }
                //判斷分數
                //qDebug()<<__LINE__<<"my"<<myCount;
                //qDebug()<<__LINE__<<"his"<<hisCount;
                myScore[i][j]=evaluateBlank(valueOfBlank(chessInfo[0],myCount,myChess)+valueOfBlank(chessInfo[1],myCount,myChess)+valueOfBlank(chessInfo[2],myCount,myChess)+valueOfBlank(chessInfo[3],myCount,myChess));
                //qDebug()<<__LINE__<<"my"<<myCount;
                hisScore[i][j]=evaluateBlank(valueOfBlank(chessInfo[0],hisCount,hisChess)+valueOfBlank(chessInfo[1],hisCount,hisChess)+valueOfBlank(chessInfo[2],hisCount,hisChess)+valueOfBlank(chessInfo[3],hisCount,hisChess));
                //qDebug()<<__LINE__<<"his"<<hisCount;
            }
        }
    }
    /*for(int i=0;i<15;i++){
        for(int j=0;j<15;j++){
            qDebug()<<__LINE__<<myScore[i][j];
        }
    }*/
    //下棋
    int myMaxScore=0,hisMaxScore=0;
    QList<int> row1;//存儲myScore中最高分坐標(一個或多個)
    QList<int> col1;
    QList<int> row2;//存儲hisScore中最高分坐標(一個或多個)
    QList<int> col2;
    int countOfMax1=0;//myScore最大值個數
    int countOfMax2=0;//hisScore最大值個數
    int myTemp=0,hisTemp=0;//存儲對應一方分數最高時,另一方的最高分
    int myIndex=0,hisIndex=0;//應該落子的最大值所在的索引
    myMaxScore=max(myScore[0],row1,col1,countOfMax1);
    hisMaxScore=max(hisScore[0],row2,col2,countOfMax2);
    if(countOfBlank==225){//場上沒有棋子
        placeChess(8,8);//下在中間
    }else if(myMaxScore>hisMaxScore){//如果自己最高分數大於對方,則進攻
        qDebug()<<__LINE__<<"JinGong";
        if(countOfMax1>1){//如果自己最高分數不止一個,選擇對方分數最高的地方下
            qDebug()<<__LINE__<<"DiYi";
            for(int i=1;i!=countOfMax1;i++){
                if(hisTemp<=hisScore[row1.at(i-1)][col1.at(i-1)]){
                    hisTemp=hisScore[row1.at(i-1)][col1.at(i-1)];
                    myIndex=i-1;
                }
            }
            //qDebug()<<__LINE__<<row1.at(myIndex)+1<<col1.at(myIndex);//代碼沒有運行到這兒,條件判斷有問題?
            placeChess(row1.at(myIndex)+1,col1.at(myIndex)+1);
        }else{
            qDebug()<<__LINE__<<"DiEr";
            placeChess(row1.at(0)+1,col1.at(0)+1);
        }
    }else{//如果自己最高分數小於對方,則防守
        qDebug()<<__LINE__<<"FangShou";
        if(countOfMax2>1){//如果對方最高分數不止一個,選擇我方分數最高的地方下
            qDebug()<<__LINE__<<"DiYi";
            for(int j=1;j!=countOfMax2;j++){
                if(myTemp<=myScore[row2.at(j-1)][col2.at(j-1)]){
                    myTemp=myScore[row2.at(j-1)][col2.at(j-1)];
                    hisIndex=j-1;
                }
            }
            //qDebug()<<__LINE__<<row2.at(hisIndex)+1<<col2.at(hisIndex)+1;//代碼沒有運行到這兒,條件判斷有問題?
            placeChess(row2.at(hisIndex)+1,col2.at(hisIndex)+1);
        }else{
            qDebug()<<__LINE__<<"DiEr";
            placeChess(row2.at(0)+1,col2.at(0)+1);
        }
    }
}
int Chessboard::evaluateBlank(int value) {//給出最終分數
    //qDebug()<<"evaluateBlank";
    if(value/100000>=1){//有一個及以上的五連
        return Level_1;
    }else if(value/20000>1){//有一個以上的活四
        return Level_2;
    }else if(value/20000==1){//有一個活四
        return Level_3;
    }else if(value/4500>2){//有兩個以上的活三
        return Level_4;
    }else if(value/4500==2){//有兩個活三
        return Level_5;
    }else if(value/4500==1){//有一個活三
        return Level_6;
    }else if(value/1000>2){//有兩個以上的死四
        return Level_7;
    }else if(value/1000==2){//有兩個死四
        return Level_8;
    }else if(value/1000==1){//有一個死四
        return Level_9;
    }else if(value/200>2){//有兩個以上的活二
        return Level_10;
    }else if(value/200==2){//有兩個活二
        return Level_11;
    }else if(value/200==1){//有一個活二
        return Level_12;
    }else if(value/45>2){//有兩個以的死三
        return Level_13;
    }else if(value/45==2){//有兩個死三
        return Level_14;
    }else if(value/45==1){//有一個死三
        return Level_15;
    }else if(value/10>1){//有一個以上的死二
        return Level_16;
    }else if(value/10==1){//有一個死二
        return Level_17;
    }else {
        return Level_18;
    }
    return 0;
}

int Chessboard::max(const int *score,QList<int> &row,QList<int> &col,int &countOfMax){//獲取二位數組最大值並存儲落子坐標,修改最大值個數
    //qDebug()<<"max";
    int temp=*score;
    row.append(0);
    col.append(0);
    for(int i=0;i<15;i++){
        for(int j=0;j<15;j++){
            if(temp<=*(score+(i*15+j))){
                if(temp==*(score+(i*15+j))){
                    countOfMax++;
                }else{
                    countOfMax=1;//若最大值改變,最大值個數更新為1
                    while ( !row.isEmpty() )//若最大值改變,容器清空
                        row.removeFirst();
                    while ( !col.isEmpty() )
                        col.removeFirst();
                }
                temp=*(score+(i*15+j));
                row.append(i);
                col.append(j);

            }
        }
    }
    return temp;
}

//對一條直線上的空位計算分數,變量名以左,右為例(傳入相應數組時,變量代表其他反方向)(待改)
int Chessboard::valueOfBlank(const int *chessBoard,int count,int myChess) {
    //qDebug()<<"valueOfBlank";
    //qDebug()<<__LINE__<<count;
    int hisChess=myChess==1?2:1;
    int left=3;
    int right=4;
    int leftChess=*(chessBoard+left);
    int rightChess=*(chessBoard+right);
    if (count >= 5){//中心線5連
        //qDebug()<<__LINE__<<"WIN5";
        return WIN5;//5連珠
    }

    if (count == 4){//中心線4連
        //qDebug()<<__LINE__<<"count==4";
        if (leftChess == BLANK && rightChess == BLANK)//兩邊斷開位置均空
            return ALIVE4;//活四
        else if (leftChess == hisChess && rightChess == hisChess)//兩邊斷開位置均非空
            return NO_THREAT;//沒有威脅
        else if (leftChess == BLANK || rightChess == BLANK)//兩邊斷開位置只有一個空
            return DIE4;//死四
    }

    if (count == 3) {//中心線3連
        //qDebug()<<__LINE__<<"count==3";
        int leftChess1 = *(chessBoard+left-1);
        int rightChess1 = *(chessBoard+right+1);

        if (leftChess == BLANK && rightChess == BLANK)//兩邊斷開位置均空
        {

            if (leftChess1 == hisChess && rightChess1 == hisChess)//均為對手棋子
                return DIE3;
            else if (leftChess1 == myChess || rightChess1 == myChess)//只要一個為自己的棋子
                return DIE4;
            else if (leftChess1 == BLANK || rightChess1 == BLANK)//只要有一個空
                return ALIVE3;

        }
        else if (leftChess == hisChess && rightChess == hisChess)//兩邊斷開位置均非空
        {
            return NO_THREAT;//沒有威脅
        }
        else if (leftChess == BLANK || rightChess == BLANK)//兩邊斷開位置只有一個空
        {

            if (leftChess == hisChess) {//左邊被對方堵住
                if (rightChess1 == hisChess)//右邊也被對方堵住
                    return NO_THREAT;
                if (rightChess1 == BLANK)//右邊均空
                    return DIE3;
                if (rightChess1 == myChess)
                    return DIE4;

            }
            if (rightChess == hisChess) {//右邊被對方堵住
                if (leftChess1 == hisChess)//左邊也被對方堵住
                    return NO_THREAT;
                if (leftChess1 == BLANK)//左邊均空
                    return DIE3;
                if (leftChess1 == myChess)//左邊還有自己的棋子
                    return DIE4;
            }
        }
    }

    if (count == 2) {//中心線2連
        //qDebug()<<__LINE__<<"count==2";
        int leftChess1 = *(chessBoard+left-1);
        int rightChess1 = *(chessBoard+right+1);
        int leftChess2 = *(chessBoard+left-2);
        int rightChess2 = *(chessBoard+right+2);

        if (leftChess == BLANK && rightChess == BLANK)//兩邊斷開位置均空
        {
            if ((rightChess1 == BLANK && rightChess2 == myChess) ||
                    (leftChess1 == BLANK && leftChess2 == myChess))
                return DIE3;//死3
            else if (leftChess1 == BLANK && rightChess1 == BLANK)
                return ALIVE2;//活2

            if ((rightChess1 == myChess && rightChess2 == hisChess) ||
                    (leftChess1 == myChess && leftChess2 == hisChess))
                return DIE3;//死3

            if ((rightChess1 == myChess && rightChess2 == myChess) ||
                    (leftChess1 == myChess && leftChess2 == myChess))
                return DIE4;//死4

            if ((rightChess1 == myChess && rightChess2 == BLANK) ||
                    (leftChess1 == myChess && leftChess2 == BLANK))
                return ALIVE3;//活3
            //其他情況在下邊返回NO_THREAT
        }
        else if (leftChess == hisChess && rightChess == hisChess)//兩邊斷開位置均非空
        {
            return NO_THREAT;
        }
        else if (leftChess == BLANK || rightChess == BLANK)//兩邊斷開位置只有一個空
        {
            if (leftChess == hisChess) {//左邊被對方堵住
                if (rightChess1 == hisChess || rightChess2 == hisChess) {//只要有對方的一個棋子
                    return NO_THREAT;//沒有威脅
                }
                else if (rightChess1 == BLANK && rightChess2 == BLANK) {//均空
                    return DIE2;//死2
                }
                else if (rightChess1 == myChess && rightChess2 == myChess) {//均為自己的棋子
                    return DIE4;//死4
                }
                else if (rightChess1 == myChess || rightChess2 == myChess) {//只有一個自己的棋子
                    return DIE3;//死3
                }
            }
            if (rightChess == hisChess) {//右邊被對方堵住
                if (leftChess1 == hisChess || leftChess2 == hisChess) {//只要有對方的一個棋子
                    return NO_THREAT;//沒有威脅
                }
                else if (leftChess1 == BLANK && leftChess2 == BLANK) {//均空
                    return DIE2;//死2
                }
                else if (leftChess1 == myChess && leftChess2 == myChess) {//均為自己的棋子
                    return DIE4;//死4
                }
                else if (leftChess1 == myChess || leftChess2 == myChess) {//只有一個自己的棋子
                    return DIE3;//死3
                }
            }
        }
    }

    if (count == 1) {//中心線1連
        //qDebug()<<__LINE__<<"count==1";
        int leftChess1 = *(chessBoard+left-1);
        int rightChess1 = *(chessBoard+right+1);
        int leftChess2 = *(chessBoard+left-2);
        int rightChess2 = *(chessBoard+right+2);
        int leftChess3 = *(chessBoard+left-3);
        int rightChess3 = *(chessBoard+right+3);

        if (leftChess == BLANK && leftChess1 == myChess &&
                leftChess2 == myChess && leftChess3 == myChess)
            return DIE4;
        if (rightChess == BLANK && rightChess1 == myChess &&
                rightChess2 == myChess && rightChess3 == myChess)
            return DIE4;

        if (leftChess == BLANK && leftChess1 == myChess &&
                leftChess2 == myChess && leftChess3 == BLANK && rightChess == BLANK)
            return ALIVE3;
        if (rightChess == BLANK && rightChess1 == myChess &&
                rightChess2 == myChess && rightChess3 == BLANK && leftChess == BLANK)
            return ALIVE3;

        if (leftChess == BLANK && leftChess1 == myChess &&
                leftChess2 == myChess && leftChess3 == hisChess && rightChess == BLANK)
            return DIE3;
        if (rightChess == BLANK && rightChess1 == myChess &&
                rightChess2 == myChess && rightChess3 == hisChess && leftChess == BLANK)
            return DIE3;

        if (leftChess == BLANK && leftChess1 == BLANK &&
                leftChess2 == myChess && leftChess3 == myChess)
            return DIE3;
        if (rightChess == BLANK && rightChess1 == BLANK &&
                rightChess2 == myChess && rightChess3 == myChess)
            return DIE3;

        if (leftChess == BLANK && leftChess1 == myChess &&
                leftChess2 == BLANK && leftChess3 == myChess)
            return DIE3;
        if (rightChess == BLANK && rightChess1 == myChess &&
                rightChess2 == BLANK && rightChess3 == myChess)
            return DIE3;

        if (leftChess == BLANK && leftChess1 == myChess &&
                leftChess2 == BLANK && leftChess3 == BLANK && rightChess == BLANK)
            return ALIVE2;
        if (rightChess == BLANK && rightChess1 == myChess &&
                rightChess2 == BLANK && rightChess3 == BLANK && leftChess == BLANK)
            return ALIVE2;

        if (leftChess == BLANK && leftChess1 == BLANK &&
                leftChess2 == myChess && leftChess3 == BLANK && rightChess == BLANK)
            return ALIVE2;
        if (rightChess == BLANK && rightChess1 == BLANK &&
                rightChess2 == myChess && rightChess3 == BLANK && leftChess == BLANK)
            return ALIVE2;

        //其余在下邊返回沒有威脅

    }
    //qDebug()<<__LINE__<<"NoThreat";
    return NO_THREAT;//返回沒有威脅

}
//電腦下棋-----------------------------------------------------------------------

 

下面是我運行時的一些截圖:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM