進階版三子棋(待改進)
Designed By Rossi
僅供記錄和參考,轉載需經本人同意
有段時間沒寫blog了,感覺自己快生銹了,2021年是時候該整點狠活了,我決定搬出我用c++寫了三個月的小游戲
目錄
- 進階版三子棋(待改進)
- 初衷
- 一、三子棋的介紹
- 二、代碼決議
- 1.登錄程式
- 2.列印棋盤
- 3.核心代碼1:玩家移動,電腦移動與勝負判定
- 4.核心代碼2:玩家先走和電腦先走
- 5.成就系統(計分)
- 6.全域變數,定義及部分主函式部分
- 三、小感慨
初衷
學了這么久編程,總覺得自己除了演算法還應該弄點別的東西,用c++寫個軟體吧似乎很難實作,而且c++的GUI設計還是比較難的,
既然搞不了軟體,那要不寫個小游戲吧,畢竟自己也喜歡游戲,于是我想了想,貪吃蛇和雷電我都寫不出,推箱子做過了感覺太低級,要不整個三子棋吧,
期初我看了網上很多三子棋的例子,發現很多開源例子都只是停留在簡單層面的設計,所以我決定寫點花里胡哨的
是時候進入正題了
一、三子棋的介紹
寫游戲之前當然得先了解游戲規則和背景吧
三子棋是黑白棋的一種,三子棋是一種民間傳統游戲,又叫九宮棋、圈圈叉叉、一條龍、井字棋等,將正方形對角線連起來,相對兩邊依次擺上三個雙方棋子,只要將自己的三個棋子走成一條線,對方就算輸了,但是,有很多時候會出現和棋的情況,
二、代碼決議
1.登錄程式
首先進游戲之前得整個花里胡哨的東西——登錄
第一步得先設計好登錄的界面UI,然后設計好登錄時用戶名和密碼的輸入和后臺校驗,考慮到登錄失敗的情況,需要逼真地模擬登錄失敗后的重新登錄和延時登錄,因此需要撰寫一個Time()函式套用到LogIn()函式中,
然后這個功能里我最喜歡的部分就是登錄輸入密碼時用*隱藏原始密碼,這一步足足花了我兩個星期,此前雖然想了三種實作方法都沒有成功,但是最后成功之后出來的效果讓我比較滿意,
//倒計時
void Time()
{
char content[]="9876543210";
char lable[]="Please wait #S!";
int len=strlen(content);
int start=0;
cout<<lable<<'\r';
for(start=0;start<len;start++)
{
lable[12]=content[start];//給陣列第十三個元素傳值
int t=1000 ;
Sleep(t);
cout<<lable<<'\r';
if(start==len-1)//數傳完畢
cout<<'\b'<<"Please log in again! "<<3;// \b 退格符
}
cout<<endl;
}
//登錄界面
void LogIn()
{
char username[64];
char password[64];
char code[64];
int flag=0;
cout<<"注意:你只有三次登錄機會"<<endl;
for(int times=0;times<3;times++)
{
the: cout<<"請輸入賬號:";
cin>>username;//陣列在輸入時降維成指標;所以不帶&
cout<<"請輸入密碼:";
int i=0;
if(strcmp(USERNAME,username)==0)
{
//接下來這一步就是實作模擬密碼輸入時有*隱藏的效果
do
{
password[i]=getch();
if(password[i]=='\r')
break;
if(password[i]=='\b')
{
if(i==0)
{
cout<<'\a';
continue;
}
i=i-1;
cout<<'\b';//實作刪字不影響顯示
}
else
{
i=i+1;
cout<<"*";
}
}while(password[i]!='\n' && i<20);
password[i]='\0';
cout<<endl;
if(strcmp(PASSWORD,password)==0)
{
cout<<"登錄成功!"<<endl;
flag=1;
break;
}
else
{
cout<<"登錄失敗!"<<endl;
times==2;
}
if(flag=1)
break;
}
if(times==2)
{
cout<<"請等待 "<<WaitTime<<"秒!"<<'\r';
Time();
goto the;//跳轉到登錄,登錄失敗1次就延時!
}
}
}
2.列印棋盤
登錄進去了,那得先有棋盤才能下棋吧
這里我使用了一個二維陣列來存放棋盤,所以我需要先進行初始化操作然后列印棋盤(row是列,line是行)
void init(char chessBoard[MAXROW][MAXLINE])
{
for(int row=0;row<MAXROW;row++)
for(int line=0;col<MAXLINE;line++)
chessBoard[row][line]=' ';
}
void print_chessBoard(char chessBoard[MAXROW][MAXLINE])
{
cout<<"+---+---+---+"<<endl;
for(int row=0;row<MAXROW;row++)
{
cout<<"| "<<chessBoard[row][0]<<" | "<<chessBoard[row][1]<<" | "<<chessBoard[row][2]<<" |"<<endl;
cout<<"+---+---+---+"<<endl;
}
}
3.核心代碼1:玩家移動,電腦移動與勝負判定
棋盤有了,那可以開始下棋了
因為我用c++寫這個游戲沒有UI,不像人家那些真游戲那樣可以動動滑鼠就可以下棋,所以這里只能采用坐標法落子,利用坐標法落子需要注意兩個事情:一是落子位置是否已經有棋,二是落子位置是否在棋盤之外,下完棋之后還要做一件事就是“裁判”:設定一個變數來記錄比賽結果方便最后根據判定輸出結果,還要一個細節就是勝負判定時會出現平局的結果,這時候只需要判斷棋盤是否滿棋而沒有產生勝負就行了,
void playerMove(char chessBoard[MAXROW][MAXLINE])
{
while(1)
{
int row=0;
int line=0;
cout<<"請輸入坐標(范圍0~2):";
cin>>row>>line;
if(row<0 || row>=MAXROW || line<0 || line>=MAXLINE)
{
cout<<"您的坐標不在合法范圍內 [0, 2],請重新輸入:"<<endl;
continue;
}
if(chessBoard[row][line]!=' ')
{
cout<<"您下的位置已經有子了!"<<endl;
continue;
}
chessBoard[row][line]='x';
break;
}
}
void computerMove(char chessBoard[MAXROW][MAXLINE])
{
while(1)
{
int row=rand()%MAXROW;
int line=rand()%MAXLINE;
if(chessBoard[row][line]!=' ')
continue;
chessBoard[row][line]='o';
break;
}
}
int isFull(char chessBoard[MAXROW][MAXLINE])
{
for(int row=0;row<MAXROW;row++)
for(int line=0;line<MAXLINE;line++)
if(chessBoard[row][line]==' ')
return 0;
return 1;
}
char isWin(char chessBoard[MAXROW][MAXLINE])
{
for(int row=0;row<MAXROW;row++)
if(chessBoard[row][0] != ' ' && chessBoard[row][0]==chessBoard[row][1] && chessBoard[row][0]==chessBoard[row][2])
return chessBoard[row][0];
for(int line=0;line<MAXLINE;line++)
if(chessBoard[0][line]!=' ' && chessBoard[0][line]==chessBoard[1][line] && chessBoard[0][line]==chessBoard[2][line])
return chessBoard[0][line];
if(chessBoard[0][0] != ' ' && chessBoard[0][0]==chessBoard[1][1] && chessBoard[0][0]==chessBoard[2][2])
return chessBoard[0][0];
if(chessBoard[2][0]!=' ' && chessBoard[2][0]==chessBoard[1][1] && chessBoard[2][0]==chessBoard[0][2])
return chessBoard[2][0];
if(isFull(chessBoard))
return 'q';
return ' ';
}
4.核心代碼2:玩家先走和電腦先走
有棋了,怎么走是個問題
下棋總有先手和后手對吧,所以我寫了兩個函式,game()是玩家先走的開局,fungame()是電腦先走的開局
void game()
{
char chessBoard[MAXROW][MAXLINE]={0};
init(chessBoard);
char winner=' ';
while(1)
{
print_chessBoard(chessBoard);
playerMove(chessBoard);
winner=isWin(chessBoard);
if(winner!=' ')
break;
computerMove(chessBoard);
winner=isWin(chessBoard);
if(winner!=' ')
break;
}
print_chessBoard(chessBoard);
if(winner=='x')
cout<<"恭喜您, 您贏了!"<<endl;
else if(winner=='o')
{
score-=50;
cout<<"對不起,你輸了!"<<endl;
}
else
{
score-=50;
cout<<"很遺憾,打成了平手!!"<<endl;
}
}
void fungame()
{
char chessBoard[MAXROW][MAXLINE]={0};
init(chessBoard);
char winner=' ';
while(1)
{
print_chessBoard(chessBoard);
computerMove(chessBoard);
winner=isWin(chessBoard);
if(winner!=' ')
break;
playerMove(chessBoard);
winner=isWin(chessBoard);
if(winner!=' ')
break;
}
print_chessBoard(chessBoard);
if(winner=='x')
cout<<"恭喜您, 您贏了!"<<endl;
else if(winner=='o')
{
score-=50;
cout<<"對不起,你輸了!"<<endl;
}
else
{
score-=50;
cout<<"很遺憾,打成了平手!!"<<endl;
}
}
很多人看到這里應該看到了里面的score了吧,別急,下面就是用到它的地方了
5.成就系統(計分)
玩游戲沒有分數哪有動力啊對吧
光玩游戲多沒意思啊,而且這樣寫出來也展現不出我的水平,秉持著花里胡哨的理念,我決定寫個成就系統
這里因為傳值程序會出現一些問題,最終結果會出現一些與預期效果不符的結果,所以這里結合主函式弄了一個算是比較巧的方法(+50,-50)
void honor(int score)
{
if(score>=0 && score<100)
cout<<"當前稱號:小菜雞"<<" 當前積分:"<<score<<endl;
if(score>=100 && score<250)
cout<<"當前稱號:初出茅廬"<<" 當前積分:"<<score<<endl;
if(score>=250 && score<500)
cout<<"當前稱號:牛刀小試"<<" 當前積分:"<<score<<endl;
if(score>=500 && score<800)
cout<<"當前稱號:棋藝精湛"<<" 當前積分:"<<score<<endl;
if(score>=800)
cout<<"當前稱號:三子棋大師"<<" 當前積分:"<<score<<endl;
}
6.全域變數,定義及部分主函式部分
前面用到的棋盤、分數、等待時間等等,都在函式撰寫前已經定義好了
int WaitTime=10;
int score=0;
包括宏定義
#define _CRT_SECURE_NO_WARNINGS
#define MAXROW 3
#define MAXLINE 3
有了函式自然得有呼叫它們的辦法,這些方法就塞在主函式里面
srand((unsigned int)time(0));
notice();//游戲公告
LogIn();//登錄程式
while(1)
{
int choice=menu();//呼叫選單
if(choice==1)
{
game();
score+=50;
}
else if(choice==2)
{
fungame();
score+=50;
}
else if(choice==0)
{
cout<<"退出游戲,再見!!!!!"<<endl;
break;
}
else
{
cout<<"輸入錯誤!請重新輸入!"<<endl;
continue;
}
honor(score);
}
system("pause");
三、小感慨
說實話當寫出來、除錯成功,能玩的時候,心里的成就感真的滿滿的,
不過這個游戲不完善的地方還是有的,例如電腦判斷玩家棋路這方面,這一步涉及到演算法,因為忙于學習 還沒有時間去完善這個方面,另外還有一個就是登錄方面,還沒想到怎么去實作注冊賬號(注冊之后還要實作賬號的長久保存)、找回密碼等等,時間還長,這些得等到以后才能去實作了(PS:如果有大佬有興趣搞一下這個不妨和小弟一起探討一下,或者幫小弟寫個補全,蒟蒻期待大佬們臨幸我)
部分編譯截圖


(這里可以看到電腦的棋路和判斷還是挺傻的,以后再來改善)
ps:防止被生搬硬造,這里我就不把完整代碼放出來了,想要完整源代碼的話到時我會放鏈接的
(exe檔案:點擊這里)
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/247243.html
標籤:其他
