1. 程式人生 > >五子棋算法問題(求解)

五子棋算法問題(求解)

介紹 直接 個數 斷開 com hist 偏移量 重新 pty

各位大佬。。。。我在解決老師布置的作業——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;//返回沒有威脅 } //電腦下棋-----------------------------------------------------------------------

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

技術分享圖片技術分享圖片

五子棋算法問題(求解)