上次我們寫了三子棋,回顧一下吧,用到了很簡單的二維陣列,全域變數,頭檔案的創建,函式的封裝呼叫,回圈分支,想必大家下來肯定都自己上手練了練的,看會了可不算會,要做就做話少本事大的人,不做屁多話稠的盧瑟,說可以,一做就歇菜,所以編程這條路上沒有用眼睛成功的,所有的程式員都是勤于動手動腦的人,想100%成功就要200%的努力,好了回歸正題,今天我們來完成三子棋的進階版,掃雷,想必大家更不陌生,在大家買的第一部電腦上都有這部游戲,藍灰色的界面,一個小黃臉,很多小格子藏著地雷等你去踩,規則我就不多說了,大家可以自行打開這款游戲回味一下, 我們直接來用C語言實作
希望大家腦海里存著上次我們寫三子棋的思路,這就算是一個程式的簡化簡化簡化版,我們就按這個思路來完成我們今天的作業,
首先呢還是我們的游戲封面,當然上次我就說了如果你這個人不怎么在乎審美只想一心一意把代碼寫好當然可以忽略這個環節,但是我不能,因為我有審美,我還要水博客長度,所以還是照例我們先搞好封面,依舊是1.玩,0.退出
void Gameface()
{
printf("*************************");
printf("****1.play*****0.exit****");
printf("*************************");
printf("請選擇:");
}
然后就是我們的test函式,和上次的三子棋結構大體一致,do while回圈的結構,1玩游戲0退出其他報錯.......
void test()
{
int input = 0;
//srand((unsigned int)time(NULL));
do
{
Gameface();
scanf("%d\n", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戲");
break;
default:
printf("輸入錯誤,請重新輸入");
break;
}
} while (input);
}
不要問我為什么把srand那一行注釋,有人會問我們已經知道那是什么了你遮住有啥用,但是畢竟我們還沒到那一步,現在我們只是介紹進入游戲的流程,歐克,我們當然都是網癮少年了,我要玩游戲!我選1,那一個game函式肯定是必不可少的吧
void game()
{
//雷的資訊存盤
//布置好雷的資訊
char mine[ROWS][COLS] = { 0 };
//排查雷的資訊
char show[ROWS][COLS];
//初始化陣列
InitBoard(mine, ROWS, COLS,'0');
InitBoard(show, ROWS, COLS,'*');
//列印棋盤
//DisplayBoard(mine, ROW, COL);
DisplayBoard(show, ROW, COL);
//布置雷
Settingmine(mine,ROW,COL);
//DisplayBoard(mine, ROW, COL);
//掃雷
Fidemine(mine,show,ROW,COL);
}
game函式作為最重要的函式,整個雷區要在這里初始化,展示,玩家掃雷后的雷區要展示,所以在game函式里又嵌套了很多函式,好了,重頭戲才開始,
按照順序,首先是創建雷區,大家肯定都能想到用二維陣列啊,是的你沒錯,還是用二維陣列,但是不要太天真認為一個二維陣列就足夠了,我首先先來講一下我們掃雷的玩法
好,這次明顯上次的三子棋有不同,上次是需要兩個玩家在空白的棋盤上下棋,這次需要玩家在滿是地雷的雷區上排雷,一個是空的,沒有任何東西,一個確實“干貨”滿滿,想必大家腦海里已經開始亂了,放心,肯定是和上次不一樣的,不然我就不講了,那這樣的雷區改怎么實作呢?當遇到難題時冷靜一步步畫圖思考總是能解決問題的,那我們就先從簡單想起吧,肯定是需要二維陣列的,那我們先建立一個二維陣列,大小就10*10好了,但是不要忘記一個問題,掃雷游戲的規則是格子上的數字會顯示周圍有幾顆雷,我們就不搞那么復雜的了,當遇到雷的時候就顯示1,沒有雷就顯示0,好了我們就一直玩一直玩,哎呀,當遇到邊界時會發生什么呢?大家想想雷區只會顯示它周圍8個方格的雷,但是如果我排到邊界的時候地圖外的地方是不是也被我納入排雷范圍了,但是我可沒有初始化它們,所以它們都是隨機值,肯定會對我的排雷產生很大的影響,好,為解決這個問題,我擴大雷區,這個擴大版的雷區只比我列印出來的雷區各邊大1,也就是擴大版雷區也會被我全初始化為無雷區,真正的雷區上才會放雷,這樣當我點到邊界方格它給我回傳的也是真正雷區里雷的個數
這樣我們就可以創建雷區了,也像昨天一樣定義一個二維陣列show,然后全域變數ROW,COL,然后再創建一個二維陣列mine,然后再創建兩個全域變數ROW+1,COL+1,因為我們需要擴大版的雷區,不要忘記頭檔案的創建和宣告哦,像昨天一樣,如果忘記就去翻翻昨天的博客吧,然后我們就可以初始化雷區了,InitBoard(mine,ROWS,COLS,'0');InitBoard(show,ROWS,COLS,'*');然后就是InitBoard的寫法,用一個很簡單的for回圈將'0'和'*'放進去
void InitBoard(char board[ROWS][COLS], int rows, int cols,char set)
{
int i = 0;
int j = 0;
for (i = 0; i < rows;i++)
{
for (j = 0; j < cols;j++)
{
board[i][j] = set;
}
}
}
然后就是展示雷區,記住我們的雷區有兩個,但是展示給玩家的時候切記不要展示擴大版的,只是我們自己知道有兩個就好了,所以你可以看到我的test函式第一個穿mine陣列的DisplayBoard函式被注釋掉了,DisplayBoard的封裝也很簡單,由于是二維陣列,所以我們需要兩個for回圈,然后在列印的時候不要自己以為寫了兩個for回圈二維陣列就會以網格的形式列印出來,二維陣列在我們的邏輯思維里確實是網格狀的,但是在記憶體存盤中它其實是連續存放的,說白了和一維陣列是一樣的連續存放的,所以我們需要在列印完一行后列印一個'\n',然后再列印下一行的內容
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0; i <= col;i++)
{
printf("%d ", i);
}
printf("\n");
for (i = 1; i <=row;i++)
{
for (j = 1; j <=col;j++)
{
printf("%c",board[i][j]);
}
printf("\n");
}
}
然后就要在雷區里放雷了,我們當然不能自己知道我們創建的是一個10*10的二維陣列就只在這100個方格中放,如果我們哪天心大了想玩一個1000*1000的掃雷,難道還需要提前在這1000000個方格里找地方放進去雷?不不不我們依舊用我們的隨機生成數,每次玩每次生成雷的個數和地點都是不同的,這才是一款合格的游戲,bug少,這時候srand的注釋就可以被拿掉了,我們創建一個全域變數ESAY_BOOMS,然后創建一個int變數booms來接收它,用它來當回圈的控制變數,當booms為真時,x和y分別用rand函式%row+1和col+1,得到符合雷區的合法坐標,然后if這個地方沒雷,就放上一顆雷,然后boom--,當然ESAT_BOOMS是根據ROW和COL來變化的,它要比ROW和COL大1
void Settingmine(char board[ROWS][COLS], int row, int col)
{
int booms = EASY_BOOMS;
while (booms)
{
int x = rand() % row + 1;
int y = rand() % col + 1;
if (board[x][y] == '0')
{
board[x][y] = '1';
booms--;
}
}
}
然后就是找雷了,Fidemine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);這里我們要傳兩個陣列的原因就是為了防止點到邊界時產生錯誤,首先進去提示玩家輸入兩個坐標,如果坐標xy合法的話,也就是x >= 1 && x <= row&&y >= 1 && y <= col,就進入,如果這個地方有雷,提示玩家找雷失敗,再需要展示一下雷區然后跳出,如果沒有踩雷,需要計算出周圍雷的個數,可以創建一個count變數,然后再封裝一個get_mine_booms函式,它的作用就是用來回傳整個雷區還剩下多少雷,這里用到了遞回,無限的套娃,大家一定要自己下來多畫圖理解一下, 不然很容易繞進去
int get_mine_booms(char mine[ROW][COL],int x, int y)
{
return mine[x - 1][y] +
mine[x - 1][y - 1] +
mine[x][y - 1] +
mine[x + 1][y - 1] +
mine[x + 1][y] +
mine[x + 1][y + 1] +
mine[x][y + 1] +
mine[x - 1][y - 1] - 8 * '0';
}
計算好后再展示一下雷區,再來讓玩家排雷,直到踩雷或者完全排雷成功,如果有非法坐標要及時提醒,如果完全排完,提示其成功并且再展示一次雷區,就可以回傳了
void Fidemine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int win = 0;
while (win<row*col-EASY_BOOMS)
{
printf("請輸入排查雷的坐標:");
scanf("%d%d", &x, &y);
if (x >= 1 && x <= row&&y >= 1 && y <= col)
{
//坐標合法
//踩雷
if (mine[x][y] == '1')
{
printf("很遺憾,你被炸死了");
DisplayBoard(mine, ROW, COL);
break;
}
//不是雷,但是要計算周圍雷的個數
else
{
int count=get_mine_booms(mine, x, y);
show[x][y] = count + '0';
DisplayBoard(mine, ROW, COL);
}
}
else
{
printf("坐標非法,請重新輸入");
}
}
if (win == ROW*COL - EASY_BOOMS)
{
printf("恭喜,你贏了");
DisplayBoard(mine, ROW, COL);
}
}
大家要注意寫代碼的程序中要自己把main函式寫好,然后再呼叫test函式,也要注意設定游戲的時候也要單獨創建一個.c檔案,不要全都寫道test.c檔案里,這里只放main函式就足夠,我們現在就要培養起分塊作業的思維,
好了,這次的掃雷小游戲就到這里,我們下次再見,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/302038.html
標籤:其他
下一篇:js打地鼠
