中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

C++語言設計實現五子棋

發布時間:2020-08-20 03:45:25 來源:腳本之家 閱讀:182 作者:black_kyatu 欄目:編程語言

本文為大家分享了C++五子棋的設計思路和設計實現,供大家參考,具體內容如下

算法思路:

在結束了對C++的學習之后,準備自己編制一些簡單的練習程序。目前初步設想是編制一個人機對戰的簡易五子棋軟件。 以下為個人設計思考的過程。

首先,進行問題分析與設計。計劃實現的功能為,開局選擇人機或雙人對戰,確定之后比賽開始。比賽結束后初始化棋盤,詢問是否繼續比賽或退出。后續可加入復盤、悔棋等功能。整個過程中,涉及到了棋子和棋盤兩種對象,同時要加上人機對弈時的AI對象,即涉及到三個對象。

棋盤類的設計。

數據存儲:五子棋棋盤為15*15的網格結構,即一共有225個節點,每個節點有橫豎坐標各一,同時每個節點狀態有3種,黑,白,或者為空。可考慮采用二維數組來存儲。每個節點三種狀態,適合采用枚舉(enum)類型。
-* 實現功能*:1. 棋盤對象應負責實時更新棋盤狀態并對外顯示,因此需要接收棋子對象的輸入,同時需要對外輸出。而棋盤對象不需要對棋子對象發送信息,所以可以設計棋盤類中更新棋盤狀態的函數接收棋子對象作為形參。2. 同時,在每次走棋之后,棋盤對象都要及時更新棋盤信息,即輸出棋盤狀態。3. 而且,每次走棋之后更新輸出之前,應該對棋子走棋是否符合規則以及輸贏進行判定。若將規則判定單獨封裝為一個對象,則不方便調用棋盤信息,故將規則判定設計為棋盤類的成員函數,接收兩個形參,一個是棋盤當前的狀態,一個是即將走的下一步棋,即一個棋子對象。

設計棋子對象。棋子對象應包含兩種信息。一是棋子顏色,二是當前要走的棋子的位置坐標,并保留對外輸出的接口。

接下來細化規則判定函數。

  • 首先進行走棋規則判定。接收當前棋子位置信息后,判定該位置是否越界或為空,若非空或者越界,則判定違規,拋擲異常,交付上級調用處理。
  • 然后進行輸贏判定。按照一定順序對當前落子位置的相鄰元素進行同色判定并計數。當發現某條直線上同色棋子超過四枚,則判定當前走棋方獲勝 。判定過程中同樣需要注意是否越界。若均未構成五星連珠,則進入平局判定。
  • 平局判定,遍歷棋盤,統計空位,若空位為0,即棋盤已滿,判定為平局。

接下來設計下棋AI。設計為一個棋子類型的函數,即接收當前棋盤狀態和對方最后一次落棋,返回棋子對象類型。

對弈算法設計。

  • 首先進行先后手判定:若棋盤為空則直接落子(8,8),正中開局。
  • 然后進行防守判定:針對對方上次落棋進行活棋檢測,在橫、豎、左斜、右斜四條直線上依次進行檢測。在任意方向檢測到四或活三,即可進行 封堵操作,給出所有可行的封堵位置。若未檢測到四或活三,則統計活二并給出所有可能的封堵位置。然后針對所有可能的封堵位置進行評分,選取分數最高的位置進行落子。若上述檢測均未找到防守點,則轉入進攻算法。
  • 進攻算法:采用枚舉,即暴力破解的方法。遍歷整個棋盤的所有空位,并給出每個空位的評分,選取最高分進行落子。
  • 活棋檢測算法:給定參照棋子,在四個方向上分別檢測。以橫向檢測為例,設參照棋子坐標為(x,y),設定同色計數器count=1(計算同色棋子數目),設定封鎖端統計量lock=0,設定已判斷的方向統計judge=0。對x-1,判斷節點狀態,若同色計數器加1,繼續判斷x-2;若異色,則lock+1,judge+1,若judge=2,終止判斷,若judge<2,反向判斷x+1;若空白,judge+1,若judge=2,終止判斷,若judge<2,反向判斷。最后得到被封堵的端口數lock和同色數count。若lock=0,count=3或2,判定為活3或活2。若lock=1,count=4,判定為4,若lock=1,count=3,判定為半3。但是在這種算法中,關于空白的判定存在著一些問題。用0代表空白,用+代表同色,-代表異色,則當出現下列情況時:-0++0-,-+++0-,事實上是死棋,而+0++0,+0+++-,實際上相當于活3或半4。為此,需要對活2和半3的情況進行進一步篩選,即空白端應保證連續兩個空白。在活棋檢測過程中,如果遇到活3或者半4,則立即終止檢測,返回落子的可能位置。若沒有則記錄活2半3的防守位置,換方向檢測。最后返回一個棋子類的數組,包含所有建議的落子位置。若均無,則遍歷棋盤,統計所有空白位置,返回。
  • 落子位置評分算法:對活棋檢測返回數組中的每個位置進行評分,即以該點為己方參照點,進行活棋檢測,若有count=5,直接返回該落子位置。有活三或者半4,分數加20,有活2,分數加5,對角線有相鄰同色,分數+2,有異色,分數-2,橫豎有同色,分數+1,有異色,分數-1。最后排序,取最高分對應的落子,返回該落子。

接下來則是數據結構和對象設計及主函數調用實現:

類及類的實現

#define RENJU_H
#include <iostream>
#include <windows.h>
#include <string>
#define hor 7
#define ver 4
using namespace std;


//用于記錄坐標
struct position
{
 int x;
 int y;
 position()
 {
 x = 0;
 y = 0;
 }
 position(int a,int b)
 {
 x = a;
 y = b;
 }
};


//用于記錄棋子顏色和節點狀態
enum state
{
 blank=0,black=1,white=2


};


//用于存儲棋局分析信息:未完賽,犯規,平局,黑方勝,白方勝
enum result
{
 go_on,error,draw,black_win,white_win
};


// 設置光標
void setpos(COORD a) 
{
 HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
 SetConsoleCursorPosition(out, a);
}


// 設置光標
void setpos(int i, int j)
{
 COORD pos = { i, j };
 setpos(pos);
}


//繪圖函數,用于在指定坐標輸出指定字符
inline void gps(int x,int y,char c)
{
 setpos(y,x);
 cout<<c;
}


//繪圖函數,用于在指定坐標輸出整數
inline void gps(int x,int y,int i)
{
 setpos(y,x);
 if(i>=10)
 cout<<i;
 else
 cout<<0<<i;
}


//繪圖函數,用于在指定坐標輸出字符串
inline void gps(int x,int y,string s)
{
 setpos(y,x);
 cout<<s;
}


//繪圖函數,用于在給定坐標打印棋盤中的一格
void tab(int x,int y,state str)
{
 string s;
 switch (str)
 {
 case blank:
 s=" "; 
 break;
 case black:
 s="黑";
 break;
 case white:
 s="白";
 break;
 default:
 break;
 }
 setpos(y,x);
 cout<<" ------ ";
 setpos(y,x+1);
 cout<<"|  |";
 setpos(y,x+2);
 cout<<"| "<<s<<" |";
 setpos(y,x+3);
 cout<<"|  |";
 setpos(y,x+4);
 cout<<" ------ ";
}


//查找最大值
int MAX(const int *a,int n)
{
 int max = a[0];
 for(int i =1; i < n ;i++)
 {
 if(a[i] > max)
 max = a[i];
 }
 return max;
}


//檢測是否符合勝利條件


//棋子類
class chess
{
public:
 inline chess(int x=0,int y=0,state c=blank)
 { point.x=x,point.y=y;
 color=c;
 };
 inline chess(chess &ch) 
 { point=ch.drop_point();
 color=ch.get_color();
 }
 ~chess(){};
 struct position drop_point()const;//用于向外部提供棋子位置
 inline state get_color() const { return color;}//提供棋子顏色信息
 void set_point();//用于從外部獲取棋子位置
 void set_point(int x,int y){ point.x=x,point.y=y;}
 void set_point(position p){ point.x=p.x,point.y=p.y;}
 void set_color(state c){ color=c;}//設置棋子顏色
private:
 position point;
 enum state color;
 };


position chess::drop_point()const
{
 return point; 
}
 
void chess::set_point()
{
 if(color==black)
 {
 setpos(110,1);
 cout<<"請黑方輸入落子列數和行數,空格隔開:";
 cin>>point.x>>point.y;
 while(point.x<1||point.x>15)
 {
 setpos(110,1);
 cout<<"列數輸入超出范圍,請重新輸入1~15之間數字  ";
 cin>>point.x;
 }
 while(point.y<1||point.y>15)
 {
 setpos(110,2);
 cout<<"行數輸入超出范圍,請重新輸入1~15之間數字 ";
 cin>>point.y;
 }
 }
 else if(color==white)
 {
 setpos(110,1);
 cout<<"請白方輸入落子列數和行數,空格隔開:";
 cin>>point.x>>point.y;
 while(point.x<1||point.x>15)
 {
 setpos(110,1);
 cout<<"列數輸入超出范圍,請重新輸入1~15之間數字  ";
 cin>>point.x;
 }
 while(point.y<1||point.y>15)
 {
 setpos(110,2);
 cout<<"行數輸入超出范圍,請重新輸入1~15之間數字 ";
 cin>>point.y;
 }
 }
 point.x--;
 point.y--;
}


//棋盤類
class chessboard
{
public:
 chessboard()
 {
 for(int i=0;i<15;i++)
 for(int j=0;j<15;j++)
 {
 square[i][j]=blank;
 }
 }
 chessboard(chessboard *cb)
 {
 for(int i=0;i<15;i++)
 for(int j=0;j<15;j++)
 {
 square[i][j]=cb->viewboard(i,j);
 }
 }
 inline state viewboard(position p_c) const;//接收坐標,返回該位置的狀態
 inline state viewboard(int x,int y) const;//接收整數坐標,返回該位置的狀態
 void update(chess ch);//接收新棋子,更新棋盤狀態
 void display()const;//向外輸出棋盤狀態
 result judge(chess ch)const;//規則函數,判斷走棋是否犯規和輸贏
 void clear()//清空棋盤
 {
 for(int i=0;i<15;i++)
 for(int j=0;j<15;j++)
 {
 square[i][j]=blank;
 }
 }
private:
 state square[15][15];
};
int check_five(chessboard bd,chess ch)
{
 position ori=ch.drop_point();
 int count=1;//計數器,統計同色個數
 int sum[4]={0};
 bool locked=0;//邏輯標記量,用來標記是否遇到了非同色節點
 //水平方向檢測
 for(int i=0,locked=0;i<5&&((ori.x-i)>=0)&&(!locked);i++)//終止循環條件:同色超過4個或觸碰到棋盤邊界或遇到非同色節點
 if(ch.get_color()==bd.viewboard(ori.x-i,ori.y))
 count++;
 else
 if(i!=0)
 locked=1;
 //sum[0]=count-1;
 for(int i=0,locked=0;i<5&&((ori.x+i)<=14)&&(!locked);i++)//終止循環條件:同色超過4個或觸碰到棋盤邊界或遇到非同色節點
 if(ch.get_color()==bd.viewboard(ori.x+i,ori.y))
 count++;
 else
 if(i!=0)
 locked=1;
 //sum[1]=count-sum[0]-2;
 sum[0]=count;
 if(count>=5)
 return count;
 //豎直方向檢測
 count=1;
 for(int i=0,locked=0;i<5&&((ori.y-i)>=0)&&(!locked);i++)//終止循環條件:同色超過4個或觸碰到棋盤邊界或遇到非同色節點
 if(ch.get_color()==bd.viewboard(ori.x,ori.y-i))
 count++;
 else
 if(i!=0)
 locked=1;
 //sum[2]=count-1;
 for(int i=0,locked=0;i<5&&((ori.y+i)<=14)&&(!locked);i++)//終止循環條件:同色超過4個或觸碰到棋盤邊界或遇到非同色節點
 if(ch.get_color()==bd.viewboard(ori.x,ori.y+i))
 count++;
 else
 if(i!=0)
 locked=1;
 //sum[3]=count-sum[2]-2;
 sum[1]=count;
 if(count>=5)
 return count;
 //左上到右下斜向檢測
 count=1;
 for(int i=0,locked=0;i<5&&((ori.y-i)>=0)&&((ori.x-i)>=0)&&(!locked);i++)//終止循環條件:同色超過4個或觸碰到棋盤邊界或遇到非同色節點
 if(ch.get_color()==bd.viewboard(ori.x-i,ori.y-i))
 count++;
 else
 if(i!=0)
 locked=1;
 //sum[4]=count-1;
 for(int i=0,locked=0;i<5&&((ori.x+i)<=14)&&((ori.y+i)<=14)&&(!locked);i++)//終止循環條件:同色超過4個或觸碰到棋盤邊界或遇到非同色節點
 if(ch.get_color()==bd.viewboard(ori.x+i,ori.y+i))
 count++;
 else
 if(i!=0)
 locked=1;
 //sum[5]=count-sum[4]-2;
 sum[2]=count;
 if(count>=5)
 return count;
 //左下到右上斜向檢測
 count=1;
 for(int i=0,locked=0;i<5&&((ori.y+i)<=14)&&((ori.x-i)>=0)&&(!locked);i++)//終止循環條件:同色超過4個或觸碰到棋盤邊界或遇到非同色節點
 if(ch.get_color()==bd.viewboard(ori.x-i,ori.y+i))
 count++;
 else
 if(i!=0)
 locked=1;
 //sum[6]=count-1;
 for(int i=0,locked=0;i<5&&((ori.x+i)<=14)&&((ori.y-i)>=0)&&(!locked);i++)//終止循環條件:同色超過4個或觸碰到棋盤邊界或遇到非同色節點
 if(ch.get_color()==bd.viewboard(ori.x+i,ori.y-i))
 count++;
 else
 if(i!=0)
 locked=1;
 //sum[7]=count-sum[6]-2;
 sum[3]=count;
 if(count>=5)
 return count;
 return MAX(sum,4);
}


state chessboard::viewboard(position p_c) const
{
 return square[p_c.x][p_c.y];
}
state chessboard::viewboard(int x,int y) const
{
 return square[x][y];
}
void chessboard::update(chess ch)
{
 position pos=ch.drop_point();
 square[pos.x][pos.y]=ch.get_color();
}


void chessboard::display()const
{
 system("cls");


 for(int i=0;i<15;i++)//打印列坐標說明
 {
 gps(0,6+i*hor,i+1);
 }
 for(int i=0;i<15;i++)//打印列坐標說明
 {
 gps(16*ver,6+i*hor,i+1);
 }
 for(int i=0;i<15;i++)//打印行坐標說明
 {
 gps(3+i*ver,1,i+1);
 }
 for(int i=0;i<15;i++)//打印行坐標說明
 {
 gps(3+i*ver,1+16*hor,i+1);
 }
 for(int i=0,j=0;i<15;i++)
 {
 for(j=0;j<15;j++)
 tab(1+i*ver,3+hor*j,square[j][i]);
 }
 cout<<endl;
}
result chessboard::judge(chess set)const
{
 bool full=1;
 if(viewboard(set.drop_point())!=blank)
 {
 return error;
 }


 if(check_five(*this,set)>=5&&(set.get_color()==black))
 return black_win;


 if(check_five(*this,set)>=5&&(set.get_color()==white))
 return white_win;


 for(int i=0;i<15;i++)
 for(int j=0;j<15;j++)
 {
 if(square[i][j]==blank) 
 full=0;
 }
 if(full==1)
 return draw;
 else
 return go_on;
}
#endif

主函數,應該再定義game類進行優化,不過設計的時候沒有考慮周全,還是按照C的思想寫了。

#include "ai.h"
#include <stdlib.h>


int main()
{
 system("mode con cols=150 lines=150 ");
 system("color 27");
 chessboard bd;
 chess now;
 result final;
 int mode;
 gps(5,40,"==============歡迎使用簡易五子棋!==============");
 gps(10,50,">>>>輸入1或2進行模式選擇<<<<");
 gps(11,50,"  <1> 雙人對戰 ");
 gps(12,50,"  <2> 人機對戰 ");
 do{
 cout<<endl<<"         input mode:";
 cin>>mode;
 }while(mode != 1 && mode != 2);
 
 //雙人對戰
 if (mode==1)
 {
loop1: now.set_color(black);//執黑先行
 bd.clear();
 bd.display(); //初始化棋盤
 setpos(110,0);
 cout<<"對局開始,黑旗先行";
 //循環判斷上一次落子結果,收集下一次輸入,直到棋局出結果
 do{ 
 now.set_point();//輸入
 final=bd.judge(now);
 //判斷是否違規
 while(final==error)//犯規輸入則重新輸入
 {
 system("cls");
 bd.display();
 setpos(110,10);
 cout<<"犯規(輸入坐標已有棋子)!";
 now.set_point();
 final=bd.judge(now);
 }
 //正確落子后更新棋盤
 bd.update(now);
 bd.display();
 //反轉下一步走棋的顏色
 if(now.get_color()==black)
 now.set_color(white);
 else
 now.set_color(black);
 
 }while(final==go_on);
 switch (final)
 {
 case go_on:
 break;
 case error:
 break;
 case draw:
 setpos(110,10);
 cout<<"平局:游戲結束";
 break;
 case black_win:
 setpos(110,10);
 cout<<"黑旗獲勝:游戲結束";
 break;
 case white_win:
 setpos(110,10);
 cout<<"白旗獲勝:游戲結束";
 break;
 default:
 break;
 }
 setpos(110,11);
 cout<<"是否繼續下一局?Y/N";
 char flag;
 cin>>flag;
 if(flag == 'Y')
 goto loop1;
 }
 if(mode == 2)
 {
 chess ai_ch;
 system("cls");
 gps(5,40,"==============歡迎使用簡易五子棋!==============");
 gps(10,50,">>>>輸入1或2進行模式選擇<<<<");
 gps(11,50,"  <1> 執黑先行 ");
 gps(12,50,"  <2> 執白后行 ");
 do{
 cout<<endl<<"         input mode:";
 cin>>mode;
 }while(mode != 1 && mode != 2);
 if(mode == 1)
 {
loop2: now.set_color(black);//執黑先行
 bd.clear();
 bd.display(); //初始化棋盤
 Ai afago(bd,white);
 setpos(110,0);
 cout<<"對局開始,請您落子";
 now.set_point();
 bd.update(now);
 ai_ch.set_color(white);
 ai_ch.set_point(left(now.drop_point(),false));
 bd.update(ai_ch);
 bd.display();
 //循環判斷上一次落子結果,收集下一次輸入,直到棋局出結果
 do{ 
 now.set_point();//輸入
 final=bd.judge(now);
 //判斷是否違規
 while(final==error)//犯規輸入則重新輸入
 {
  system("cls");
  bd.display();
  setpos(110,10);
  cout<<"犯規(輸入坐標已有棋子)!";
  now.set_point();
  final=bd.judge(now);
 }
 //正確落子后更新棋盤
 bd.update(now);
 if(final != black_win)
 {
  ai_ch=afago.set_chess();
  final=bd.judge(ai_ch);
  bd.update(ai_ch);
  bd.display();
 }else{bd.display();}
 }while(final==go_on);
 switch (final)
 {
 case go_on:
  break;
 case error:
  break;
 case draw:
  setpos(110,10);
  cout<<"平局:游戲結束";
  break;
 case black_win:
  setpos(110,10);
  cout<<"恭喜您棋藝高超,戰勝了AI:游戲結束";
  break;
 case white_win:
  setpos(110,10);
  cout<<"電腦獲勝,請繼續努力提高自己:游戲結束";
  break;
 default:
  break;
 }
 setpos(110,11);
 cout<<"是否繼續下一局?Y/N";
 char flag;
 cin>>flag;
 if(flag=='Y')
 goto loop2;
 }
 if(mode == 2)
 {
loop3: ai_ch.set_color(black);//AI執黑先行
 now.set_color(white);
 bd.clear(); //初始化棋盤
 Ai afago(bd,black);
 ai_ch.set_point(7,7);
 bd.update(ai_ch);
 bd.display(); 
 setpos(110,0);
 cout<<"對局開始,請您落子";
 //循環判斷上一次落子結果,收集下一次輸入,直到棋局出結果
 do{ 
 now.set_point();//輸入
 final=bd.judge(now);
 //判斷是否違規
 while(final==error)//犯規輸入則重新輸入
 {
  system("cls");
  bd.display();
  setpos(110,10);
  cout<<"犯規(輸入坐標已有棋子)!";
  now.set_point();
  final=bd.judge(now);
 }
 //正確落子后更新棋盤
 bd.update(now);
 if(final != white_win)
 {
 ai_ch=afago.set_chess();
 final=bd.judge(ai_ch);
 bd.update(ai_ch);
 bd.display();
 }else{bd.display();}
 }while(final==go_on);
 switch (final)
 {
 case go_on:
  break;
 case error:
  break;
 case draw:
  setpos(110,10);
  cout<<"平局:游戲結束";
  break;
 case white_win:
  setpos(110,10);
  cout<<"恭喜您棋藝高超,戰勝了AI:游戲結束";
  break;
 case black_win:
  setpos(110,10);
  cout<<"電腦獲勝,請繼續努力提高自己:游戲結束";
  break;
 default:
  break;
 }
 setpos(110,11);
 cout<<"是否繼續下一局?Y/N";
 char flag;
 cin>>flag;
 if(flag=='Y')
 goto loop3;
 }
 }
 return 0;
 
}

更多有趣的經典小游戲實現專題,分享給大家:

C++經典小游戲匯總

python經典小游戲匯總

python俄羅斯方塊游戲集合

JavaScript經典游戲 玩不停

java經典小游戲匯總

javascript經典小游戲匯總

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

万全县| 万州区| 包头市| 五华县| 汤阴县| 孟村| 泰来县| 天峨县| 即墨市| 松江区| 潞西市| 承德县| 浦江县| 扶风县| 荃湾区| 南汇区| 涟水县| 柏乡县| 乐山市| 泰来县| 江西省| 安平县| 崇信县| 剑河县| 军事| 新密市| 肥乡县| 桃园县| 临海市| 纳雍县| 高阳县| 汾阳市| 贵州省| 瓮安县| 固镇县| 绥阳县| 临洮县| 资溪县| 罗山县| 应城市| 中卫市|