大家好,我是深魚~
目錄
一、游戲介紹
二、文件分裝
?三、代碼實現(xiàn)步驟
1.制作簡易游戲菜單
?2. 初始化棋盤(11*11)
?3.打印棋盤(9*9)
4.布置雷?
?5.計算(x,y)周圍8個坐標(biāo)的和?
6.排查雷?
?<1>清屏后打印棋盤
<2>遞歸展開
<3>標(biāo)記雷
四、完整代碼
game.h:相關(guān)函數(shù)的聲明,整個代碼要引用的頭文件以及宏定義
?game.c:實現(xiàn)游戲相關(guān)的函數(shù)
test.c:整個游戲相關(guān)的測試
?五、游戲展示
一、游戲介紹
?
《掃雷》是一款大眾類的益智小游戲,于1992年發(fā)行。游戲目標(biāo)是在最短的時間內(nèi)根據(jù)點擊格子出現(xiàn)的數(shù)字找出所有非雷格子,同時避免踩雷,踩到一個雷即全盤皆輸
排查雷的規(guī)則:
1.如果這個位置不是雷,就計算這個位置周圍8個坐標(biāo)有幾個雷,并顯示雷的個數(shù)
2.如果這個位置是雷,就炸死了,表示游戲結(jié)束
3.如果把不是雷的位置都找出來了,那就通過了?
二、文件分裝
?實現(xiàn)這個掃雷游戲,我創(chuàng)建了三個文件
源文件:
test.c:整個游戲相關(guān)的測試
game.c:實現(xiàn)游戲相關(guān)的函數(shù)
頭文件:
game.h:相關(guān)函數(shù)的聲明,整個代碼要引用的頭文件以及宏定義
?三、代碼實現(xiàn)步驟
1.制作簡易游戲菜單
這個簡易菜單和上一篇文章三字棋一樣,就不做過多的解釋了
test.c
void menu()//打印簡易菜單
{
printf("************************************\n");
printf("************ 1.進(jìn)入游戲 **********\n");
printf("************ 0.退出游戲 **********\n");
printf("************************************\n");
}
int main()
{
int input = 0;
srand((unsigned int)time(NULL));//空指針NULL
do
{
menu();
printf("請選擇:>");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戲\n");
break;
default:
printf("輸入錯誤,請重新輸入\n");
break;
}
} while (input);//注意這里要加上;
return 0;
}
?2. 初始化棋盤(11*11)
(1)定義兩個數(shù)組為11*11:
定義一個數(shù)組(mine數(shù)組)表示雷的信息(1表示這個坐標(biāo)是雷,0表示不是雷),另一個數(shù)組(show數(shù)組)表示排查雷的信息
假設(shè)我們要實現(xiàn)一個9*9的棋盤,如果我們只定義一個9*9的二維數(shù)組,計算周圍8個坐標(biāo)會越界,那么我們就需要將數(shù)組擴(kuò)大成11*11的二維數(shù)組(上下左右分別多一排)
(2)為了簡潔,傳一個參數(shù)char set表示初始化的字符
初始化棋盤(9*9的外部也要初始化),因為mine和show數(shù)組不同,再傳一個參數(shù)set即要初始化的字符內(nèi)容
(3)宏定義ROWS,COLS,ROW,COL,EASY_COUNT?
為了方便修改游戲難度(改變棋盤的行和列及雷的個數(shù)),我們采用宏定義直接進(jìn)行修改即可
game.h
#define ROW 9//可以進(jìn)行掃雷的行列
#define COL 9
#define ROWS ROW+2//進(jìn)行判斷的行列
#define COLS COL+2
#define EASY_COUNT 10 //雷的個數(shù)
//初始化棋盤(9*9的外部也要初始化)
void InitBoard(char board[ROWS][COLS],char ch);
?game.c
//初始化棋盤(9*9的外部也要初始化),為了mine和show數(shù)組不同,再傳一個參數(shù)set即要初始化的內(nèi)容
void InitBoard(char board[ROWS][COLS],char ch)
{
for (int i = 0; i < ROWS; i++)
{
for (int j = 0; j < COLS; j++)
{
board[i][j] = ch;//自己的棋盤初始化為0,展示的數(shù)組初始化為*
}
}
}
?3.打印棋盤(9*9)
(1)打印出來的棋盤(show)得是9*9的,但是由于定義的數(shù)組就是11*11的,所以函數(shù)傳參還得傳11*11定義的數(shù)組
(2)因為我們這個游戲是自己輸入需要排雷的位置,所以最好在棋盤的旁邊打印出對應(yīng)的數(shù)字,方便輸入坐標(biāo)
game.h
//打印棋盤(打印9*9的部分就可以了)
void DisplayBoard(char board[ROWS][COLS]);
??game.c
//打印棋盤(打印9*9的部分就可以了)
void DisplayBoard(char board[ROWS][COLS])//定義的數(shù)組是不變的,一直都是11*11
{
printf("------掃雷------\n");//用來隔開數(shù)組
//打印列號
for (int i = 0; i <= COL; i++)
{
printf("%d ", i);
}
printf("\n");
for (int i = 1; i <= ROW; i++)//傳的是11*11,打印是9*9,也就是從數(shù)組下標(biāo)1開始打印到下標(biāo)為9
{
printf("%d ", i);//打印行號
for (int j = 1; j <= COL; j++)
{
printf("%c ", board[i][j]);//打印字符用%c
}
printf("\n");
}
printf("------掃雷------\n");
}
4.布置雷?
(1)布置雷是在mine數(shù)組上布置,定義mine數(shù)組上1代表有雷,0代表沒雷(這樣方便后面計算周圍8個坐標(biāo)的和)
(2)布置雷需要隨機(jī)布置,那就得隨機(jī)生成橫縱坐標(biāo),跟上篇三字棋生成隨機(jī)數(shù)一樣rand函數(shù)
,但是注意取模結(jié)束后要+1,因為取模的結(jié)果是0-8,我們需要生成的坐標(biāo)是1-9
(3)這里要注意一點:如果一個位置已經(jīng)布置了雷,那么這個位置就不需要再布置了,加一條判斷語句就可以解決這個問題
game.h
//布置雷
void SetMine(char mine[ROWS][COLS]);
???game.c
//布置雷
void SetMine(char mine[ROWS][COLS])
{
int count = EASY_COUNT;
while (count)//注意這個循環(huán)進(jìn)行的次數(shù)可能大于10次,可能有的位置已經(jīng)是1,或者是多次生成的坐標(biāo)相同
{
int x = rand() % ROW + 1;//%ROW得到的范圍是0-8,結(jié)果+1的范圍就算1-9
int y = rand() % COL + 1;
if (mine[x][y] != '1')
{
mine[x][y] = '1';
count--;
}
}
}
?5.計算(x,y)周圍8個坐標(biāo)的和?
注意求和的時候需要將字符和數(shù)字進(jìn)行轉(zhuǎn)換,加和的時候數(shù)組中的是字符0,而加和是數(shù)字0,字符=數(shù)字-'0' eg:'1'=1-'0'
???game.c
//計算(x,y)周圍8個坐標(biāo)的和
int GetMineCount(char mine[ROWS][COLS], int x, int y)
{
return mine[x - 1][y - 1] + mine[x - 1][y] + mine[x - 1][y + 1] +
mine[x][y - 1] +mine[x][y + 1] +
mine[x + 1][y - 1] + mine[x + 1][y] + mine[x + 1][y + 1]-8*'0';//記住要減去8個'0'變成數(shù)字
}
6.排查雷?
?排查雷的規(guī)則:
1.如果這個位置不是雷,就計算這個位置周圍8個坐標(biāo)有幾個雷,并顯示雷的個數(shù)
2.如果這個位置是雷,就炸死了,表示游戲結(jié)束
3.如果把不是雷的位置都找出來了,那就通過了?
(1)傳參需要傳兩個數(shù)組,mine數(shù)組用來判斷是否踩中了雷,show數(shù)組打印出來看
(2)排雷需要多次進(jìn)行,while語句控制結(jié)束,當(dāng)棋盤剩下的格子只剩下10個雷的時間就結(jié)束,
或者踩到了雷,直接break跳出結(jié)束
?game.h
//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS]);
???game.c
//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS])
{
int x = 0;
int y = 0;
int win = 0;
char ch = 0;
while (win<ROW*COL-EASY_COUNT)//當(dāng)非雷的坐標(biāo)已經(jīng)全部排出來了,即只剩下雷了就跳出循環(huán)
{
printf("請輸入要排查雷的坐標(biāo):>");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= ROW && y >= 1 && y <= COL)
{
if (mine[x][y] == '1')//踩中雷了
{
system("cls");//清空屏幕
printf("很遺憾,你被炸死了\n");
DisplayBoard(mine);
break;
}
else//不是雷,就統(tǒng)計(x,y)周圍有幾個雷:這時候雷定義為1的好處就出來了,我們直接把周圍坐標(biāo)的和加起來放入show坐標(biāo)的對應(yīng)位置上即可
{
if (show[x][y] == ' ')//為了避免再次輸入已經(jīng)變成空格的坐標(biāo)
{
printf("該坐標(biāo)已排查\n");
continue;
}
else
{
//展開一片,去除和為0,,并打印出和非0的位置(遞歸實現(xiàn))
//條件:1.這個坐標(biāo)不是雷
//2.這個坐標(biāo)周圍沒有雷,雷的個數(shù)是0
//3.這個坐標(biāo)沒有被排查過
RemoveZero(mine, show, x, y, &win);
system("cls");
DisplayBoard(show);
do
{
printf("如果需要'$'對雷進(jìn)行標(biāo)記,請輸入Y;無需標(biāo)記,請按Enter鍵繼續(xù)\n");
while ((ch = getchar()) != '\n')//清空緩沖區(qū)
{
;
}
scanf("%c", &ch);
if (ch == 'Y')
{
//標(biāo)記雷并打印
Remark(show);
}
else
{
continue;
}
} while (ch != '\n');//進(jìn)行多次標(biāo)記
}
}
}
else
{
printf("坐標(biāo)非法,請重新輸入\n");
}
}
if (win == ROW * COL - EASY_COUNT)
{
system("cls");
printf("恭喜你,排雷成功\n");
}
}
優(yōu)化:?
?<1>清屏后打印棋盤
system("cls");
頭文件:#include<windows.h>
清屏后再打印show數(shù)組棋盤,可以讓屏幕更干凈簡潔?
system("cls");
DisplayBoard(show);
<2>遞歸展開
展開一片,去除和為0,,并打印出和非0的位置(遞歸實現(xiàn))
條件:1.這個坐標(biāo)不是雷
?? ??? ??? 2.這個坐標(biāo)周圍沒有雷,雷的個數(shù)是0
?? ??? ??? 3.這個坐標(biāo)沒有被排查過
(1)遞歸展開:當(dāng)mine數(shù)組計算周圍8個坐標(biāo)的和返回的是0,那就把show數(shù)組的這個位置變?yōu)榭崭?,并且再看自己周圍的八個坐標(biāo)是否也為0,如果mine數(shù)組為0且show數(shù)組的對應(yīng)位置為*,那么再對這個坐標(biāo)的周圍8個坐標(biāo)進(jìn)行爆炸式展開(show數(shù)組對應(yīng)位置為*是為了防止多次把同一個位置變?yōu)榭崭?/strong>)
(2)傳參記得傳一個指針來使win++(即統(tǒng)計GetMineCount()的位置,每變一個符號,剩下的棋格數(shù)就少一個,對應(yīng)又成功一步)
???game.c
//展開一片,去除和為0,并打印出和非0的位置(遞歸實現(xiàn))
void RemoveZero(char mine[ROWS][COLS], char show[ROWS][COLS],int x,int y,int *num)
{
if (x >= 1 && x <= ROW && y >= 1 && y <= COL)//小數(shù)組(9*9)內(nèi)部才需要計算
{
//注意加和的時候數(shù)組中的是字符0,而加和是數(shù)字0,字符=數(shù)字-'0' eg:'1'=1-'0'
int ret = GetMineCount(mine, x, y);
if (ret == 0)
{
show[x][y] = ' ';//如果這個周圍坐標(biāo)和是0,那就變?yōu)榭崭? (*num)++;//變一個空格win也+1
//看看周圍8個坐標(biāo)是否為0
for (int i = x - 1; i <= x + 1; i++)
{
for (int j = y - 1; j <= y + 1; j++)
{
if (mine[i][j]=='0'&&show[i][j] == '*')//show[i][j] == '*'是為了避免重復(fù)
RemoveZero(mine, show, i, j,num);
}
}
}
else
{
show[x][y] = ret + '0';//數(shù)字+'0'變成字符
(*num)++;
}
}
}
<3>標(biāo)記雷
如果show數(shù)組上想要標(biāo)記的位置為*,則可以標(biāo)記;如果不是*,則不可標(biāo)記
????game.c
//標(biāo)記雷
void Remark(char show[ROWS][COLS])
{
int x = 0;
int y = 0;
while (1)
{
printf("請輸入要標(biāo)記的坐標(biāo)>:\n");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= ROW && y >= 1 && y <= COL)
{
if (show[x][y] == '*')
{
show[x][y] = '$';
system("cls");
DisplayBoard(show);
break;
}
else
{
printf("該位置不能被標(biāo)記,請重新輸入\n");
}
}
else
{
printf("坐標(biāo)非法,請重新輸入\n");
}
}
}
四、完整代碼
game.h:相關(guān)函數(shù)的聲明,整個代碼要引用的頭文件以及宏定義
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#include<windows.h>
#define ROW 9//可以進(jìn)行掃雷的行列
#define COL 9
#define ROWS ROW+2//進(jìn)行判斷的行列
#define COLS COL+2
#define EASY_COUNT 10 //雷的個數(shù)
//初始化棋盤(9*9的外部也要初始化)
void InitBoard(char board[ROWS][COLS],char ch);
//打印棋盤(打印9*9的部分就可以了)
void DisplayBoard(char board[ROWS][COLS]);
//布置雷
void SetMine(char mine[ROWS][COLS]);
//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS]);
?game.c:實現(xiàn)游戲相關(guān)的函數(shù)
#include"game.h"
//實現(xiàn)游戲相關(guān)的代碼
//9*9的棋盤,上面布置10個雷
//排查雷
//1.如果這個位置不是雷,就計算這個位置周圍8個坐標(biāo)有幾個雷,并顯示雷的個數(shù)
//2.如果這個位置是雷,就炸死了,表示游戲結(jié)束
//3.如果把不是雷的位置都找出來了,那就通過了
//一個數(shù)組表示雷的信息(1表示這個坐標(biāo)是雷,0表示不是雷),另一個數(shù)組表示排查雷的信息
//當(dāng)要排查數(shù)組最外層的雷時,計算周圍8個坐標(biāo)會越界,這就需要把數(shù)組擴(kuò)充為11*11,當(dāng)然為了兩個數(shù)組統(tǒng)一起來,兩個數(shù)組都定義11*11
//初始化棋盤(9*9的外部也要初始化),為了mine和show數(shù)組不同,再傳一個參數(shù)set即要初始化的內(nèi)容
void InitBoard(char board[ROWS][COLS],char ch)
{
for (int i = 0; i < ROWS; i++)
{
for (int j = 0; j < COLS; j++)
{
board[i][j] = ch;//自己的棋盤初始化為0,展示的數(shù)組初始化為*
}
}
}
//打印棋盤(打印9*9的部分就可以了)
void DisplayBoard(char board[ROWS][COLS])//定義的數(shù)組是不變的,一直都是11*11
{
printf("------掃雷------\n");//用來隔開數(shù)組
//打印列號
for (int i = 0; i <= COL; i++)
{
printf("%d ", i);
}
printf("\n");
for (int i = 1; i <= ROW; i++)//傳的是11*11,打印是9*9,也就是從數(shù)組下標(biāo)1開始打印到下標(biāo)為9
{
printf("%d ", i);//打印行號
for (int j = 1; j <= COL; j++)
{
printf("%c ", board[i][j]);//打印字符用%c
}
printf("\n");
}
printf("------掃雷------\n");
}
//布置雷
void SetMine(char mine[ROWS][COLS])
{
int count = EASY_COUNT;
while (count)//注意這個循環(huán)進(jìn)行的次數(shù)可能大于10次,可能有的位置已經(jīng)是1,或者是多次生成的坐標(biāo)相同
{
int x = rand() % ROW + 1;//%ROW得到的范圍是0-8,結(jié)果+1的范圍就算1-9
int y = rand() % COL + 1;
if (mine[x][y] != '1')
{
mine[x][y] = '1';
count--;
}
}
}
//計算(x,y)周圍8個坐標(biāo)的和
int GetMineCount(char mine[ROWS][COLS], int x, int y)
{
return mine[x - 1][y - 1] + mine[x - 1][y] + mine[x - 1][y + 1] +
mine[x][y - 1] +mine[x][y + 1] +
mine[x + 1][y - 1] + mine[x + 1][y] + mine[x + 1][y + 1]-8*'0';//記住要減去8個'0'變成數(shù)字
}
//展開一片,去除和為0,并打印出和非0的位置(遞歸實現(xiàn))
void RemoveZero(char mine[ROWS][COLS], char show[ROWS][COLS],int x,int y,int *num)
{
if (x >= 1 && x <= ROW && y >= 1 && y <= COL)//小數(shù)組(9*9)內(nèi)部才需要計算
{
//注意加和的時候數(shù)組中的是字符0,而加和是數(shù)字0,字符=數(shù)字-'0' eg:'1'=1-'0'
int ret = GetMineCount(mine, x, y);
if (ret == 0)
{
show[x][y] = ' ';//如果這個周圍坐標(biāo)和是0,那就變?yōu)榭崭? (*num)++;//變一個空格win也+1
//看看周圍8個坐標(biāo)是否為0
for (int i = x - 1; i <= x + 1; i++)
{
for (int j = y - 1; j <= y + 1; j++)
{
if (mine[i][j]=='0'&&show[i][j] == '*')//show[i][j] == '*'是為了避免重復(fù)
RemoveZero(mine, show, i, j,num);
}
}
}
else
{
show[x][y] = ret + '0';//數(shù)字+'0'變成字符
(*num)++;
}
}
}
//標(biāo)記雷
void Remark(char show[ROWS][COLS])
{
int x = 0;
int y = 0;
while (1)
{
printf("請輸入要標(biāo)記的坐標(biāo)>:\n");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= ROW && y >= 1 && y <= COL)
{
if (show[x][y] == '*')
{
show[x][y] = '$';
system("cls");
DisplayBoard(show);
break;
}
else
{
printf("該位置不能被標(biāo)記,請重新輸入\n");
}
}
else
{
printf("坐標(biāo)非法,請重新輸入\n");
}
}
}
//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS])
{
int x = 0;
int y = 0;
int win = 0;
char ch = 0;
while (win<ROW*COL-EASY_COUNT)//當(dāng)非雷的坐標(biāo)已經(jīng)全部排出來了,即只剩下雷了就跳出循環(huán)
{
printf("請輸入要排查雷的坐標(biāo):>");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= ROW && y >= 1 && y <= COL)
{
if (mine[x][y] == '1')//踩中雷了
{
system("cls");//清空屏幕
printf("很遺憾,你被炸死了\n");
DisplayBoard(mine);
break;
}
else//不是雷,就統(tǒng)計(x,y)周圍有幾個雷:這時候雷定義為1的好處就出來了,我們直接把周圍坐標(biāo)的和加起來放入show坐標(biāo)的對應(yīng)位置上即可
{
if (show[x][y] == ' ')//為了避免再次輸入已經(jīng)變成空格的坐標(biāo)
{
printf("該坐標(biāo)已排查\n");
continue;
}
else
{
//展開一片,去除和為0,,并打印出和非0的位置(遞歸實現(xiàn))
//條件:1.這個坐標(biāo)不是雷
//2.這個坐標(biāo)周圍沒有雷,雷的個數(shù)是0
//3.這個坐標(biāo)沒有被排查過
RemoveZero(mine, show, x, y, &win);
system("cls");
DisplayBoard(show);
do
{
printf("如果需要'$'對雷進(jìn)行標(biāo)記,請輸入Y;無需標(biāo)記,請按Enter鍵繼續(xù)\n");
while ((ch = getchar()) != '\n')//清空緩沖區(qū)
{
;
}
scanf("%c", &ch);
if (ch == 'Y')
{
//標(biāo)記雷并打印
Remark(show);
}
else
{
continue;
}
} while (ch != '\n');//進(jìn)行多次標(biāo)記
}
}
}
else
{
printf("坐標(biāo)非法,請重新輸入\n");
}
}
if (win == ROW * COL - EASY_COUNT)
{
system("cls");
printf("恭喜你,排雷成功\n");
}
}
test.c:整個游戲相關(guān)的測試
//測試代碼
#include"game.h"
void menu()//打印簡易菜單
{
printf("************************************\n");
printf("************ 1.進(jìn)入游戲 **********\n");
printf("************ 0.退出游戲 **********\n");
printf("************************************\n");
}
void game()
{
char mine[ROWS][COLS];
char show[ROWS][COLS];
//初始化棋盤(9*9的外部也要初始化)
InitBoard(mine, '0');
InitBoard(show, '*');
//打印棋盤(打印9*9的部分就可以了)
DisplayBoard(show);
//布置雷(放在mine數(shù)組9*9中即可)
SetMine(mine);
//排查雷
FindMine(mine, show);
}
int main()
{
int input = 0;
srand((unsigned int)time(NULL));//空指針NULL
do
{
menu();
printf("請選擇:>");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戲\n");
break;
default:
printf("輸入錯誤,請重新輸入\n");
break;
}
} while (input);//注意這里要加上;
return 0;
}
?五、游戲展示
掃雷小游戲演示
本次C語言小游戲掃雷的內(nèi)容就到此啦,有什么問題歡迎評論區(qū)或者私信交流,覺得筆者寫的還可以,或者自己有些許收獲的,麻煩鐵汁們動動小手,給俺來個一鍵三連,萬分感謝 !?文章來源:http://www.zghlxwxcb.cn/news/detail-650080.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-650080.html
到了這里,關(guān)于【C語言】小游戲-掃雷(清屏+遞歸展開+標(biāo)記)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!