Ⅰ 前言
掃雷游戲,想必大家都有玩過吧。沒完過的話也可以試著玩一玩,這樣對寫掃雷游戲這個小游戲的化是會有一個很好的思路的。那么接下來介紹如何實現掃雷游戲的具體步驟。
Ⅱ 模塊化編程
再說實現三子棋邏輯思路前,我們來說說什么是 模塊化編程 吧
傳統方式編程:所有的函數均放在main.c里,若使用的模塊比較多,則一個文件內會有很多的代碼,不利于代碼的組織和管理,而且很影響編程者的思路。
模塊化編程:把各個模塊的代碼放在不同的.c文件里,在.h文件里提供外部可調用函數的聲明,其它.c文件想使用其中的代碼時,只需要# "XXX.h"文件即可。使用模塊化編程可極大的提高代碼的可閱讀性、可維護性、可移植性等。
傳統方式編程:所有的函數均放在main.c里,若使用的模塊比較多,則一個文件內會有很多的代碼,不利于代碼的組織和管理,而且很影響編程者的思路。
模塊化編程:把各個模塊的代碼放在不同的.c文件里,在.h文件里提供外部可調用函數的聲明,其它.c文件想使用其中的代碼時,只需要# "XXX.h"文件即可。使用模塊化編程可極大的提高代碼的可閱讀性、可維護性、可移植性等!
總的來說就是:當你代碼比較多的時候,就可以采用模塊化編程來完成這個程序
Ⅲ 游戲思路與邏輯
Ⅳ 實現游戲步驟/過程① 創建顏色函數創建顏色函數color()
前景色顏色的對應值↓
0=黑色 8=灰色
1=藍色 9=淡藍色 十六進制
2=綠色 10=淡綠色 A
3=湖藍色 11=淡淺綠色 B
4=紅色 12=淡紅色 C
5=紫色 13=淡紫色 D
6=黃色 14=淡黃色 E
7=白色 15=亮白色 F
color()創建顏色函數如下↓
void color(short x)
{
if (x >= 0 && x <= 15)
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), x);
else
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
}
使用顏色函數的好處實際上無非就是讓程序運行看上去更加美觀、鮮明,實際上沒什么實際作用,這點是我們要知道的。
這里的需要引頭文件#,才可以進行使用。
② 菜單界面(menu)
菜單界面函數實際上就像是我們的一個界面,就好比是游戲的界面目錄,餐館當中的菜單。一樣的道理。這個是庫函數就有的我們只需要直接引用下即可。示例代碼如下↓
void menu()
{
color(0); //Black 黑色
system("cls"); //清屏.
color(10);
printf("|-----------|掃雷游戲|-----------|\n");
printf("|********************************|\n");
printf("|★★★★★★★★★★★★★★★★|\n");
printf("|★★ 1.開始 0.退出 ★★|\n");
printf("|★★★★★★★★★★★★★★★★|\n");
printf("|0 = 不是雷 ---------- 1 = 它是雷|\n");
printf("|--------------------------------|\n");
}
注→在這里用到了一個("cls");達到了一個清屏的效果,只有加了這個,你才可以讓cmd中的界面全部為黑色。因為我們還在這個清屏指令上+color(0);這個代表的是,黑色。
③ 實現多行多列掃雷
使用 # 宏定義在這里的好處:
方便程序的修改,不用對整個程序進行修改,只需對宏定義上進行修改。
提高程序的運行效率,更加方便模塊化。
在三子棋基礎上,只需改變宏定義的值,就可以實現多子棋的效果。
在程序當中,是9行9列的,如果想修改成10行10列的只需要把#改成10即可!
10行10列的掃雷棋盤如下
但是十行十列就是會出現這個的情況,當然這個問題也是非常的好解決的。大家可以看下怎么去解決這個問題。
④ 實現多個雷
這里 # 在上面提到過,就不提了。
修改雷的個數也只需要把這上面的數字(10)修改變的數字修改,當然修改請理性修改,你不可能 9*9 的棋盤,給很多雷吧,那還怎么玩哈哈哈。
比如修改成 40個雷,看看效果如下所示
⑤ 棋盤初始化
打印棋盤,本質上是打印數組的內容。如下所示
void Initialization(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;
}
}
}
char set是實參傳遞到形參的字符。
實參數組名行可以進行省略,但是列不能進行省略。
⑥ 棋盤的打印
打印棋盤,本質上是打印數組的內容,這里數組的內容是字符'0'。如下所示
void Print_board(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
color(7);
printf("════════════════════\n");
for (i = 0; i <= row; i++)
{
if (i == 0)
{
printf("%d|", i);
}
else
{
printf("%d|", i);
}
}
printf("\n/|══════════════════");
printf("\n");
for (i = 1; i <= row; i++)
{
printf("%d|", i);
for (j = 1; j <= col; j++)
{
printf("%c|", board[i][j]);
}
printf("\n");
}
color(6);
printf("\n-----掃雷游戲------\n");
}
打印棋盤的效果圖,如下所示
⑦ 布置雷的信息
打印完棋盤之后,就開始布置雷。
void Lay_thunder(char Findout[ROWS][COLS], int row, int col)
{
//布置雷
int count = Thunder;
while (count)
{
int x = rand() % row + 1;
int y = rand() % col + 1;
if (Findout[x][y] = '0')
{
Findout[x][y] = '1';
count--;
}
}
}
這里還用到了一個知識點【隨機數】
在實際開發中,我們往往需要一定范圍內的隨機數,過大或者過小都不符合要求c語言小游戲程序,那么,如何產生一定范圍的隨機數呢?我們可以利用取模的方法:
int a = rand() % 10; //產生0~9的隨機數,注意10會被整除
如果要規定上下限:
int a = rand() % 51 + 13; //產生13~63的隨機數
分析:取模即取余,rand()%51+13 我們可以看成兩部分:rand()%51 是產生 0~50 的隨機數,后面+13保證 a 最小只能是 13c語言小游戲程序,最大就是 50+13=63
使用 頭文件中的 time() 函數即可得到當前的時間(精確到秒),就像下面這樣:
srand(()time(NULL));
注意:這個在程序當中是只執行一次即可!
⑧ 玩家輸入雷實現步驟
這里的玩家輸入坐標,在玩家輸入下棋的時候,定義了個靜態局部變量,在執行代碼的時候。玩游戲的時候會提醒一次, 輸入第一個坐標記得空一格!每次進入游戲只有一次,這里主要就是用到了 靜態局部變量 就可以保證上一次的值不會被銷毀。
檢查坐標處是不是雷,布置存放的是字符'1',沒有放置雷存放的是字符'0'。
判斷坐標輸入合法性幾種情況:
void Check(char Layouts[ROWS][COLS], char Findout[ROWS][COLS], int row, int col)
{
//1.輸入排查雷的坐標
//2.檢查坐標處是不是雷,布置雷存放的是字符'1',沒有放置雷存放的是字符'0'。
int x, y;
int win = 0;
while (win
{
static int j = 1;//延長生明周期,
while (j)
{
color(8);
printf("--------------------------\n");
printf("[輸入第一個坐標記得空一格!]\n");
printf("--------------------------\n");
j--;
break;
}
color(11);
printf("---------------\n");
printf("請輸入坐標>:");
//x與y坐標范圍 1~9
scanf("%d %d", &x, &y);
printf("---------------\n");
//判斷坐標的合法性
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (Layouts[x][y] == '1')
{
printf("|══════════════════|\n");
printf("|很遺憾,你被炸死了!|\n");
printf("|══════════════════|\n");
Print_board(Layouts, ROW, COL);
Sleep(5000);
break;
}
if (Findout[x][y] == '0')
{
color(6);
printf("|═══════════════════════════════════|\n");
printf("|寧已經在這里輸入過坐標了,請重新輸入!|\n");
printf("|═══════════════════════════════════|\n");
}
if (Findout[x][y] == '1')
{
color(6);
printf("|════════════════════════════════════|\n");
printf("|寧已經在這里輸入過坐標了,請重新輸入!|\n");
printf("|════════════════════════════════════|\n");
}
else
{
//不是雷情況下,統計x,y周圍坐標有幾個雷
int Count = Statistics(Layouts, x, y);
Findout[x][y] = Count + '0';
Print_board(Findout, row, col);
win++;
}
}
else
{
printf("|═════════════════════════════|\n");
printf("|寧輸入的坐標范圍錯誤!重新輸入|\n");
printf("|═════════════════════════════|\n");
}
}
if (win == row*col - Thunder)
{
printf("|═══════════════════════|\n");
printf("|恭喜你,排雷成功!太優秀了!|\n");
printf("|═══════════════════════|\n");
Print_board(Findout, ROW, COL);
}
}
⑨ 排查 x,y 周圍有多少雷
static int Statistics(char Layouts[ROWS][COLS], int x, int y)
{
return Layouts[x-1][y-1]+
Layouts[x][y-1] +
Layouts[x+1][y-1]+
Layouts[x-1][y]+
Layouts[x+1][y]+
Layouts[x-1][y+1]+
Layouts[x][y+1]+
Layouts[x+1][y+1] - 8*'0';
}
注意:靜態局部變量去修飾函數的時候,讓這個函數只能在自己所在的源文件內看到,其它的內部當中是看不到的。
Ⅴ 結果演示
Ⅵ 模塊化代碼實現1、test.c
測試游戲的邏輯。
//掃雷游戲的測試
void menu()
{
color(0); //Black 黑色
system("cls"); //清屏.
color(10);
printf("|-----------|掃雷游戲|-----------|\n");
printf("|********************************|\n");
printf("|★★★★★★★★★★★★★★★★|\n");
printf("|★★ 1.開始 0.退出 ★★|\n");
printf("|★★★★★★★★★★★★★★★★|\n");
printf("|0 = 不是雷 ---------- 1 = 它是雷|\n");
printf("|--------------------------------|\n");
}
void game()
{
printf(" ---------\n");
printf("|PLAY GAME|\n");
printf(" ---------\n");
char Layouts[ROWS][COLS] = { 0 };//存放布置好雷的信息
char Findout[ROWS][COLS] = { 0 };//存放排查出雷的信息
//初始化棋盤
Initialization(Layouts, ROWS, COLS, '0');//mine
Initialization(Findout, ROWS, COLS, 'x');//show
//打印棋盤
/*Print_board(Layouts, ROW, COL);*/
Print_board(Findout, ROW, COL);
//布置雷
Lay_thunder(Layouts, ROW, COL);
/*Print_board(Findout, ROW, COL);*/
//排查雷
Check(Layouts,Findout,ROW,COL);
}
void test()
{
int input = 0;
srand((unsigned)time(NULL));
do
{
menu();
color(5);
printf("\n");
printf("|═════════════════════════════════|\n");
printf("|Please enter the interface number|:");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("|════════|\n");
printf("|退出游戲|\n");
printf("|════════|\n");
break;
default:
printf("\n");
printf("|═════════════════════════════════|\n");
printf("|由于你輸入錯誤罰你5s不能玩(→_→)|\n");
printf("|═════════════════════════════════|\n");
Sleep(5000);
}
} while (input);
}
int main(void)
{
test();
return 0;
}
2、game.h
關于游戲包含的函數聲明,符號聲明頭文件的包含以及宏定義。
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
//顏色函數
void color(short x);
//初始化函數,初始化11*11,因為 行 & 列 都需要加1
void Initialization(char board[ROWS][COLS], int rows, int cols, char set);
//打印棋盤,最終打印 9*9 棋盤即可
void Print_board(char board[ROWS][COLS], int row, int col);
//布置雷
void Lay_thunder(char Findout[ROWS][COLS], int row, int col);
//排查雷
void Check(char Layouts[ROWS][COLS], char Findout[ROWS][COLS], int row, int col);
3、game.c
游戲和相關函數實現。
//游戲的函數的實現
void color(short x)
{
if (x >= 0 && x <= 15)
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), x);
else
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
}
void Initialization(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;
}
}
}
void Print_board(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
color(7);
printf("════════════════════\n");
for (i = 0; i <= row; i++)
{
if (i == 0)
{
printf("%d|", i);
}
else
{
printf("%d|", i);
}
}
printf("\n/|══════════════════");
printf("\n");
for (i = 1; i <= row; i++)
{
printf("%d|", i);
for (j = 1; j <= col; j++)
{
printf("%c|", board[i][j]);
}
printf("\n");
}
color(6);
printf("\n-----掃雷游戲------\n");
}
void Lay_thunder(char Findout[ROWS][COLS], int row, int col)
{
//布置雷
int count = Thunder;
while (count)
{
int x = rand() % row + 1;
int y = rand() % col + 1;
if (Findout[x][y] = '0')
{
Findout[x][y] = '1';
count--;
}
}
}
//靜態局部變量去修飾函數的時候,讓這個函數只能在自己所在的源文件內看到,其它的內部當中是看不到的。
static int Statistics(char Layouts[ROWS][COLS], int x, int y)
{
return Layouts[x-1][y-1]+
Layouts[x][y-1] +
Layouts[x+1][y-1]+
Layouts[x-1][y]+
Layouts[x+1][y]+
Layouts[x-1][y+1]+
Layouts[x][y+1]+
Layouts[x+1][y+1] - 8*'0';
}
void Check(char Layouts[ROWS][COLS], char Findout[ROWS][COLS], int row, int col)
{
//1.輸入排查雷的坐標
//2.檢查坐標處是不是雷,布置雷存放的是字符'1',沒有放置雷存放的是字符'0'。
int x, y;
int win = 0;
while (win
{
static int j = 1;//延長生明周期,
while (j)
{
color(8);
printf("--------------------------\n");
printf("[輸入第一個坐標記得空一格!]\n");
printf("--------------------------\n");
j--;
break;
}
color(11);
printf("---------------\n");
printf("請輸入坐標>:");
//x與y坐標范圍 1~9
scanf("%d %d", &x, &y);
printf("---------------\n");
//判斷坐標的合法性
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (Layouts[x][y] == '1')
{
printf("|══════════════════|\n");
printf("|很遺憾,你被炸死了!|\n");
printf("|══════════════════|\n");
Print_board(Layouts, ROW, COL);
Sleep(5000);
break;
}
if (Findout[x][y] == '0')
{
color(6);
printf("|═══════════════════════════════════|\n");
printf("|寧已經在這里輸入過坐標了,請重新輸入!|\n");
printf("|═══════════════════════════════════|\n");
}
if (Findout[x][y] == '1')
{
color(6);
printf("|════════════════════════════════════|\n");
printf("|寧已經在這里輸入過坐標了,請重新輸入!|\n");
printf("|════════════════════════════════════|\n");
}
else
{
//不是雷情況下,統計x,y周圍坐標有幾個雷
int Count = Statistics(Layouts, x, y);
Findout[x][y] = Count + '0';
Print_board(Findout, row, col);
win++;
}
}
else
{
printf("|═════════════════════════════|\n");
printf("|寧輸入的坐標范圍錯誤!重新輸入|\n");
printf("|═════════════════════════════|\n");
}
}
if (win == row*col - Thunder)
{
printf("|═══════════════════════|\n");
printf("|恭喜你,排雷成功!太優秀了!|\n");
printf("|═══════════════════════|\n");
Print_board(Findout, ROW, COL);
}
}
對于初學者這是可以嘗試下,對編程的思維和邏輯,以及代碼的理解能力幫助都是非常大的( ?? .? ?? )?
簡單分享快樂學習,如有錯誤請多包涵!
PS:如果沒有你的關注,那我所做的將毫無意義!歡迎分享,點贊,在看。