一直說寫個幾百行的小專案,于是我寫了一個控制臺的掃雷,沒有想到精簡完了代碼才200行左右,不過考慮到這是我精簡過后的,濃縮才是精華嘛,我就發出來大家一起學習啦,看到程式跑起來能玩,感徑訓是蠻有成就感的~哈哈
掃雷應該屬于一款大眾游戲,從我初中使用計算機開始,它就被集成到了windows系統中,雖然他是這么經典,我還是要介紹一下他的玩法,然后再考慮在控制臺中怎么實作它,
1、游戲的主界面,是一個一個小方格,在小方格上單擊左鍵,可以翻開小方格看看后面有什么,
2、在這些小方格的背后隱藏著雷,如果不幸點中了雷,那么就GameOver了,
如果點中的不是一個雷,那么就是一塊空地,這個時候會出現兩種情況:
1)用滑鼠點中的空地周圍八個點內有雷,那么就顯示雷的個數
2)用滑鼠點中的空地周圍沒有雷,這個時候就將周圍的空地全部顯示出來,遇到該顯示數字的空地,就將數字顯示出來,(仔細觀察你會發現,數字會將空地圍起來,這是一句廢話,但是也值得想一想這是為什么)
3、在小方格上,點擊滑鼠的右鍵,可以將一個空地標記為雷,當然這個功能只是為了方便你記憶你之前確定是雷的地方,(還有左右鍵都點,和點擊右鍵出現?標記,這里就不談啦)
4、當空地上剩余的格子數和雷的個數一樣多,那么這個時候就應該算是勝利啦,
OK~游戲流程說完了,這個時候該談談如何實作了,

1、首先需要一張地圖,一般情況下我們都可以用一個二維陣串列示一個地圖,每一個元素代表著掃雷中的一個小方格,相應元素存盤0,那么地圖上的這個位置就是空地,相應元素存盤1,那么就代表這個位置就一顆雷,
2、在控制臺上依照二維陣列長度和寬度,列印相應的小方塊,
3、然后就用滑鼠點擊那些小方塊,對于控制臺來講,在黑框框的區域中是有坐標的,可以使用一些函式捕獲到你點擊了螢屏的哪一個坐標,
4、對于控制臺來說,列印一個字符,有的字符橫向占一個位置比如普通的字母數字,有的字符橫向占兩個位置比如一些圖形字符: ①②③■◆等等,這點在控制臺編程的時候要注意,
5、當點擊螢屏的時候,獲取到點擊的坐標后,去二維陣列中查看相應的位置是雷還是空地,從而做相應的處理,
1)假如點擊到了雷,那么就控制游戲結束
2)假如點擊到了空地有兩種情況
1.點擊的空地周圍有雷,那么就將雷的個數顯示出來
2.假如點擊的空地周圍沒有雷,那么就使用遞回的方法去探測周圍的點,探測出與其相連的所有周圍有雷的點,
這個是我實作的效果,下面就是代碼啦:
// saolei.cpp : 定義控制臺應用程式的入口點, // #include "stdafx.h" #include #include #include #define Boom 10 int a[10][10] = {0}; COORD TempPos[100] ={0}; int nSign = 0;
/************************************
函式名 : WriteWchar
函式作用: 在控制臺相應的坐標上顯示一串字符
回傳值 : void
引數 : int x 橫坐標
引數 : int y 縱坐標
引數 : char szString[] 要顯示的字串
說明 :
************************************/
void WriteWchar(int x,int y,char szString[]) { HANDLE hOut= GetStdHandle(STD_OUTPUT_HANDLE); COORD pos = {x*2,y}; SetConsoleCursorPosition(hOut,pos); printf("%s",szString); }
/************************************
函式名 : DrawNumber
函式作用: 在相應的坐標上,根據傳入的數字,列印相應的數字字符
回傳值 : void
引數 : COORD pos 要列印的位置
引數 : int nNumber 要列印的數字
說明 :
************************************/
void DrawNumber(COORD pos,int nNumber) { switch (nNumber) { case 1: WriteWchar(pos.X,pos.Y,"①"); break; case 2: WriteWchar(pos.X,pos.Y,"②"); break; case 3: WriteWchar(pos.X,pos.Y,"③"); break; case 4: WriteWchar(pos.X,pos.Y,"④"); break; case 5: WriteWchar(pos.X,pos.Y,"⑤"); break; case 6: WriteWchar(pos.X,pos.Y,"⑥"); break; case 7: WriteWchar(pos.X,pos.Y,"⑦"); break; case 8: WriteWchar(pos.X,pos.Y,"⑧"); break; default: break; } }
/************************************
函式名 : GetNumber
函式作用: 獲取一個點的四周有幾顆雷
回傳值 : int
引數 : COORD pos 要探測的點的坐標
說明 :
************************************/
int GetNumber(COORD pos) { int nCount = 0; for(int i = pos.X-1;i<=pos.X+1;i++) for (int j = pos.Y-1;j<=pos.Y+1;j++) { if (a[j][i] == Boom) { nCount++; } } return nCount; }
/************************************
函式名 : Drawmap
函式作用: 列印一下地圖
回傳值 : void
說明 :
************************************/
void Drawmap() { for (int i =0;i<10;i++) { for (int j =0;j<10;j++) { WriteWchar(j,i,"■"); } } }
/************************************
函式名 : Init
函式作用: 隨機生成10個地雷,然后存到陣列中
回傳值 : void
說明 :
************************************/
void Init() { srand(time(NULL)); for (int i =0;i<10;i++) { int Temp_x = rand()%10; int Temp_y = rand()%10; //判斷這個地方是不是已經生成一個雷了,如果沒有,賦值為雷 if (a[Temp_x][Temp_y]!=Boom) { a[Temp_x][Temp_y] = Boom; } //如果是雷,就相當于本次生成沒有發生過,,,,, else { i--; } } Drawmap(); }
/************************************
函式名 : IsClose
函式作用: 判斷是不是已經探測過的點,由于使用的8方向遞回的探測,這樣避免重復
回傳值 : bool
引數 : COORD posTemp
說明 :
************************************/
bool IsClose(COORD posTemp) { for (int i =0;i { if(TempPos[i].X == posTemp.X&&TempPos[i].Y == posTemp.Y) return true; } return false; }
/************************************
函式名 : IsKongdi
函式作用: 判斷一個點是空地,還是雷,如果是空地,需要做其他處理
回傳值 : void
引數 : COORD pos
說明 :
************************************/
bool IsKongdi(COORD pos) { int nNumber = 0; //1 如果是雷,就直接回傳一個false說明要掛了 if (a[pos.Y][pos.X] == Boom) { return false; } //2 如果不是雷,那么就做后續處理 else { //2.1先判斷一下周圍有幾顆雷 nNumber = GetNumber(pos); if (nNumber!=0){ //有幾顆雷,就列印這個數字 DrawNumber(pos,nNumber); return true; } else { //如果沒有雷,那就先畫空地出來,然后向周圍擴散去探測其他點 WriteWchar(pos.X,pos.Y," "); } } //2.2點到了空地,但是周圍沒有雷的情況的處理,繼續去探測周圍8個點 for(int i = -1;i<=1;i++) for (int j = -1;j<=1;j++) { COORD posTemp = {pos.X+i,pos.Y+j}; //是不是越界了 if (i==0&&j==0||posTemp.X==-1||posTemp.Y==-1||posTemp.X==10||posTemp.Y==10) continue; //這個點是不是已經探測過了 if (IsClose(posTemp)) continue; //這個點沒有探測過,就將其加入到陣列中,然后使其在以后的探測中,存入 TempPos[nSign++] =posTemp; IsKongdi(posTemp); } return true; }
/************************************
函式名 : GetMousePosition
函式作用: 獲取滑鼠點擊的位置,假如沒有獲取到,就回傳(-1,-1)
回傳值 : COORD 滑鼠點擊的坐標
說明 :
************************************/
COORD GetMousePosition() { HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE); INPUT_RECORD stcInput = {0}; DWORD buffer; COORD pos = {-1,-1}; ReadConsoleInput(hIn,&stcInput,1,&buffer); if (stcInput.EventType == MOUSE_EVENT) { MOUSE_EVENT_RECORD stcMouseEnent = stcInput.Event.MouseEvent; if (stcMouseEnent.dwButtonState ==FROM_LEFT_1ST_BUTTON_PRESSED ) { pos = stcMouseEnent.dwMousePosition; pos.X/=2; } } return pos; } int _tmain(int argc, _TCHAR* argv[]) { Init(); COORD pos; //開始游戲 while(1) { //獲取滑鼠點擊位置 pos = GetMousePosition(); if (pos.X!=-1) { //如果滑鼠點擊的位置被探測過了,就開始下一次回圈 if (IsClose(pos)) { continue; } TempPos[nSign++] =pos; bool bIskongdi = IsKongdi(pos); //點到雷了,就直接退出游戲了, if (false ==bIskongdi) { system("cls"); WriteWchar(20,10,"you lose"); getchar(); break; } //檢測是不是贏了,贏的條件就是沒有被探測的點的個數和雷的個數相等 if (nSign ==90) { system("cls"); WriteWchar(20,10,"you win"); } } } return 0; }

專案不是很長,但是注釋我寫的還算明白,估計大家都可以看得懂,希望對于新手們有一定的幫助,謝謝大家的支持!!!
看到這里你是不是又學到了很多新知識呢~
如果你很想學編程,小編推薦我的C語言/C++編程學習基地【點擊進入】!
都是學編程小伙伴們,帶你入個門還是簡簡單單啦,一起學習,一起加油~
還有許多學習資料和視頻,相信你會喜歡的!
涉及:游戲開發、常用軟體開發、編程基礎知識、課程設計、黑客等等......

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/276.html
標籤:C
上一篇:學習第18天
下一篇:學習第19天
