【C語言】掃雷
整體來說比較簡單
適合初學C語言的小白
需要你掌握以下知識:
掌握——分支switch、回圈for、while陳述句
掌握——函式(傳參,宣告,創建)
掌握——陣列(創建,傳參)
閱讀文章須知
此代碼在VS2019軟體中撰寫 (Visual Studio 2019)
文章順序
1.先說整體思路
2.寫出部分代碼
3.決議上述代碼
布局
1.列印選單
2.接收變數
3.列印雷區
4.接收坐標
5.判斷雷區周圍包括坐標本身在內的 9個坐標內有幾個雷
6. *為顯示可排查區域
7. 1為雷
8.踩到雷結束游戲
9.全部排查則游戲勝利
************************
******* 1.play *******
******* 0.exly *******
************************
請選擇輸入開始游戲:> 1
共有30個雷
0 1 2 3 4 5 6 7 8 9
1 * * * * * * * * *
2 * * * * * * * * *
3 * * * * * * * * *
4 * * * * * * * * *
5 * * * * * * * * *
6 * * * * * * * * *
7 * * * * * * * * *
8 * * * * * * * * *
9 * * * * * * * * *
//作弊 看到雷的布局
0 1 2 3 4 5 6 7 8 9
1 0 0 1 1 1 0 0 1 0
2 1 0 0 1 1 0 0 0 1
3 0 0 0 1 1 0 0 1 0
4 1 1 0 1 1 0 0 0 0
5 0 0 1 1 0 1 1 1 1
6 0 0 0 1 0 0 0 0 0
7 1 1 0 1 0 0 1 0 0
8 0 0 0 0 0 0 0 0 0
9 0 0 1 1 1 0 0 0 1
請輸入坐標:5 5
0 1 2 3 4 5 6 7 8 9
1 * * * * * * * * *
2 * * * * * * * * *
3 * * * * * * * * *
4 * * * * * * * * *
5 * * * * 5 * * * * 顯示周圍雷的數量
6 * * * * * * * * *
7 * * * * * * * * *
8 * * * * * * * * *
9 * * * * * * * * *
游戲分為——兩部分
- 開始游戲
- 結束游戲
開始游戲分為——四部分
- 創建雷區
- 初始化并列印
- 生成雷
- 排查雷
簡單看一下整體布局 不至于從一開始就勸退初學者
全文共217行代碼 整體代碼在文章最后
下面跟隨我的思路一起完成掃雷游戲吧!
首先創建三個檔案
.c 檔案是C語言檔案
.h 檔案是頭檔案
- test.c :寫主程式的.c檔案
- game.c : 寫游戲主要代碼的.c檔案
- game.h :參考 頭檔案 和 宣告的.h頭檔案
在test.c檔案中
創建main函式主體
主要思路是:
-
先列印選單: 1開始 / 0結束
-
選擇并開始游戲
如在手機中觀看 可左右滑動查看查處部分代碼
void emnu()
{
printf("************************\n");
printf("******* 1.play *******\n");
printf("******* 0.exly *******\n");
printf("************************\n");
}
int main()
{
int input = 0;
srand((unsigned int)time(NULL)); //后面創建亂數的函式
do {
//列印選單
emnu();
printf("請選擇輸入開始游戲:> ");
scanf("%d", &input);
switch (input)
{
case 1:
game();
//printf("游戲開始\n");
break;
case 0:
printf("游戲結束\n");
break;
default:
printf("輸入錯誤,請重新選擇!\n");
break;
}
} while (input);
return 0;
}
srand((unsigned int)time(NULL)); 對于這句話后面會講到
-
上述代碼分為 ——— 三部分
1.列印選單
2.接收字符
3.判斷狀態為了一打開程式就進入游戲狀態
所以用了 do{}while{} 回圈
1.列印選單呼叫 emnu()函式
void emnu()
{
printf("************************\n");
printf("******* 1.play *******\n");
printf("******* 0.exly *******\n");
printf("************************\n");
}
2.接收字符
我們在回圈外部定義
int input = 0; 接收指令的變數
scanf("%d",&input); 接收鍵盤輸入的函式
注意:
%d后面不要加空格
& 符號不要忘記寫
3.判斷接收字符的狀態
switch(整形運算式)
{
case 整形常量運算式:
break; //跳出switch 去下面的while中判斷是否繼續回圈
case 0:
break;
default://相當于if陳述句中的else的作用
//當上面的陳述句都不滿足時 執行此陳述句
break;
}while(input); //input為0時結束游戲
輸入1 繼續游戲
輸入0 結束游戲
輸入錯誤 給出提示并從新輸入
-
當你想驗證一下現在寫的代碼時
- 可以在game.h中引入頭檔案
- 并且在test.c中引入game.h頭檔案
- 這樣所有頭檔案都放在game.h中就可以了
game.h
#pragma once #include <stdio.h>在頭檔案中 第一行 寫入#pragma once 在其他檔案中不管包含幾次<stdio.h>都只拷貝一次 是為了防止頭檔案重復 做無用功test.c
#include "game.h"
經過上面的代碼 可以在case 1: 中呼叫函式game()
ganme()分為——五部分
- 1.創建雷區
- 2.初始化
- 3.列印初始化
- 4.生成雷
- 5.排查雷
1.創建雷區
test.c
void game()
{
char LQu[ROWS][COLS]; 存放雷的資訊
char PCha[ROWS][COLS]; 排查雷的資訊
}
so easy 有沒有 雷區創建好了
2.初始化雷區
void game()
{
//創建雷區
char LQu[ROWS][COLS]; //存放雷的資訊
char PCha[ROWS][COLS];//排查雷的資訊
//初始化
CShi(LQu, ROWS, COLS,'0');//雷區
CShi(PCha,ROWS, COLS,'*');//排查區
//列印初始化
//DY(LQu, ROW, COL);//雷區
printf("共有%d個雷\n",LEI);
DY(PCha, ROW, COL);//排查區
//生成雷
S_L(LQu, ROW, COL,LEI);
printf("\n");
//DY(LQu, ROW, COL);//雷區
//排查雷
P_C(LQu,PCha, ROW, COL);
DY(PCha, ROW, COL);//排查區
}
可以看到創建雷區 用到了兩個陣列 LQu PCha
先看下game.h中的代碼
game.h
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#define ROW 9
#define COL 9
#define ROWS ROW+2 //ROW+2
#define COLS COL+2 //COL+2
#define LEI 10
//初始化
void CShi(char CShi[ROWS][COLS], int rows, int cols,char ret);//雷區
上述陣列用到了兩個 常量ROWS、COLS 怎么來的?
這里用到5個變數,用#define定義
#define 定義全域變數
ROW 為用戶可見區域 橫坐標
COL 為用戶可見區域 縱坐標
ROWS 為底層排雷區域 橫坐標
COLS 為底層排雷區域 縱坐標
LEI 為雷的個數
為什么分為 ROW 和 ROWS 呢
我們開頭說到 比如是9*9 的格子
在掃描雷的時候要掃描坐標在內的周圍的9個格子
如下:
* * *
* n *
* * *
整體的布局:(ROW,COL)
0 1 2 3 4 5 6 7 8 9
1 * * * * * * * * *
2 * * * * * * * * *
3 * * * * * * * * *
4 * * * * * * * * *
5 * * * * * * * * *
6 * * * * * * * * *
7 * * * * * * * * *
8 * * * * * * * * *
9 * * * * * * * * *
但是:
左上(1,1),左下(1,9),右上(9,1),右下(9,9).....
這幾個坐標訪問時就越界了
所以:
我們在底層代碼掃描時 把上下左右都加上一行
這時訪問陣列時就不會出現越界了
也就有了ROWS、COLS 這兩個變數
#define ROW 9
#define COL 9
#define ROWS ROW+2 //ROW+2
#define COLS COL+2 //COL+2
game.h 中下方還有一行代碼——初始化 (下)
左右滑動查看代碼
test.c
char LQu[ROWS][COLS]; //存放雷的資訊 定義陣列
char PCha[ROWS][COLS];//排查雷的資訊 定義陣列
//需要初始化的代碼:
CShi(LQu, ROWS, COLS,'0');//雷區
CShi(PCha,ROWS, COLS,'*');//排查區
這樣設計用一個函式傳參 就能給不同陣列 初始化成不同的 字符
game.h
//初始化
void CShi(char CShi[ROWS][COLS], int rows, int cols,char ret);//雷區
函式回傳型別 不需要回傳值 所以為 void
陣列傳參 接收一個陣列 用char CShi[][]陣列接收
ROWS COLS 是整形 用int 型別變數接收
后面的 '0' '*' 用char 字符型別接收
因為排查雷需要更大的陣列 所以用到了 ROWS COLS
test.c 中定義函式
game.h 宣告函式
game.c 實作代碼
game.c
#include "game.h"
//初始化雷區
void CShi (char CShi[ROWS][COLS], int rows, int cols,char ret)
{
int i = 0;
for (i = 0; i < rows; i++)
{
int j = 0;
for (j = 0; j < cols; j++)
{
CShi[i][j] = ret;
}
}
}
用for回圈將兩個陣列初始化成全0 全*
CShi(LQu, ROWS, COLS,'0');
0 1 2 3 4 5 6 7 8 9 a b
1 0 0 0 0 0 0 0 0 0 0 0
2 0 0 0 0 0 0 0 0 0 0 0
3 0 0 0 0 0 0 0 0 0 0 0
4 0 0 0 0 0 0 0 0 0 0 0
5 0 0 0 0 0 0 0 0 0 0 0
6 0 0 0 0 0 0 0 0 0 0 0
7 0 0 0 0 0 0 0 0 0 0 0
8 0 0 0 0 0 0 0 0 0 0 0
9 0 0 0 0 0 0 0 0 0 0 0
a 0 0 0 0 0 0 0 0 0 0 0
b 0 0 0 0 0 0 0 0 0 0 0
這一層布置雷 掃雷
CShi(PCha,ROWS, COLS,'*');
0 1 2 3 4 5 6 7 8 9 a b
1 * * * * * * * * * * *
2 * * * * * * * * * * *
3 * * * * * * * * * * *
4 * * * * * * * * * * *
5 * * * * * * * * * * *
6 * * * * * * * * * * *
7 * * * * * * * * * * *
8 * * * * * * * * * * *
9 * * * * * * * * * * *
a * * * * * * * * * * *
b * * * * * * * * * * *
這一層列印出來給用戶看 當然不是列印11*11 是列印9*9 后面會說到
(16進制 a=10 b=11 c=12 d=13 e=14 f=15)
3.列印初始化
test.c
//列印初始化
DY(PCha, ROW, COL);//排查區
printf("共有%d個雷\n",LEI); //告訴用戶有幾個雷
game.h
//列印初始化
void DY(char LQu[ROWS][COLS],int rows,int cols);//雷區
傳參上面講了 同理
這里要強調的是傳參的時候用的是ROW COL
因為列印出來的是要給用戶觀察的
ROW COL 定義的為9
所以要列印9*9 的個格子
聰明的你要問了:怎么才能在11*11 的陣列中列印9*9 的格子呢?
你: 我才沒問呢 我都知道!
你: 只要在陣列下標為1 的地方列印到下標10就可以啦
你真是個機靈鬼!!!
game.c
//列印
void DY(char LQu[ROWS][COLS], int row, int col)
{
int i = 0;
for (i = 0; i <= row; i++)
{
printf("%d ", i);
}
printf("\n");
for (i = 1; i <= row; i++)
{
int j = 0;
printf("%d ", i);
for (j = 1; j <= col; j++)
{
printf("%c ", LQu[i][j]);
}
printf("\n");
}
printf("\n");
}
上述代碼 第一個回圈 是列印出了每行的編號 為了方便觀察
下面的代碼 也在每一行的首元素列印了編號
最后for回圈列印的陣列初始化的內容
列印結果如下:DY(PCha, ROW, COL);
共有10個雷
0 1 2 3 4 5 6 7 8 9
1 * * * * * * * * *
2 * * * * * * * * *
3 * * * * * * * * *
4 * * * * * * * * *
5 * * * * * * * * *
6 * * * * * * * * *
7 * * * * * * * * *
8 * * * * * * * * *
9 * * * * * * * * *
4.生成雷
test.c
//生成雷
S_L(LQu, ROW, COL,LEI);
printf("\n");
game.h
//生成雷
void S_L(char LQu[ROWS][COLS], int row, int col,int lei);
game.c
//生成雷
void S_L(char LQu[ROWS][COLS], int row, int col,int lei)
{
int i = lei;
while(i)
{
int x = rand() % row+1;
int y = rand() % col+1;
if (LQu[x][y] != '1')
{
LQu[x][y] = '1';
i--;
}
}
}
思路:
1.x y在規定坐標內 生成亂數
一個亂數%10 則得到的結果不會大于10 也就是最大得到9
2.在隨機產生的坐標中放入字符'1'
產生亂數rand()
在主函式中呼叫srand()
srand((unsigned int)time(NULL));
接收time系統時間 強制準換成無符號整型(unsigned int)
srand() 的頭檔案 <stdlib.h>
time() 的頭檔案 <time.h>
此時就可以在已經宣告的范圍內 使用rand()
還差一步就完成啦 ?(?>?<?)? 加油!
5.排查雷
敗北:坐標 = ‘1’
勝利:輸入坐標 = 坐標 - 雷
test.c
//排查雷
P_C(LQu,PCha, ROW, COL);
DY(PCha, ROW, COL);//列印排查區
game.h
//排查雷
char P_C(char LQu[ROWS][COLS], char PCha[ROWS][COLS], int row, int col);
game.c
//判斷周圍的雷數
int LS(char LQu[ROWS][COLS], int x,int y)
{
return (LQu[x-1][y]
+ LQu[x - 1][y - 1]
+ LQu[x][y - 1]
+ LQu[x + 1][y - 1]
+ LQu[x + 1][y]
+ LQu[x + 1][y + 1]
+ LQu[x][y + 1]
+ LQu[x - 1][y + 1]
- 8 * '0');
}
//排查
char P_C(char LQu[ROWS][COLS], char PCha[ROWS][COLS], int row, int col)
{
int x = 0;//橫坐標
int y = 0;//縱坐標
int win = 0; //輸入坐標次數
//判斷坐標合法
while (win<row*col-LEI)
{
printf("請輸入坐標:");
scanf("%d %d", &x, &y);
//排查雷
if ((x > 0 && x <=row) && (y > 0 && y <=col))
{
if (LQu[x][y] != '1')
{
//判斷周圍有幾個雷
int L = LS(LQu, x, y);
PCha[x][y] = (L+'0');
DY(PCha, ROW, COL);//列印排查區
win++;
}
else
{
printf("很遺憾,你輸了\n\n");
DY(LQu, ROW, COL);//列印雷區
break;
}
}
else
{
printf("坐標非法,請重新輸入!\n\n");
}
}
if (win == ROW * COL - LEI)
{
printf("恭喜你勝利了\n\n");
}
}
解釋說明:
x 橫坐標
y 縱坐標
win 輸入坐標數
當輸入坐標次數 < 雷區-雷
接收坐標;
如果: x y 符合要求
如果:底層坐標xy != '1'
則判斷周雷數
函式() - 下面單獨講
假如回傳數字 3
列印時需要列印字符'3' - 下面單獨講
列印雷區;
win++;
否則:
游戲敗北
列印雷區
跳出
否則:
重新輸入
當輸入坐標次數 = 雷區-雷
恭喜勝利!
首先是函式
int LS(char LQu[ROWS][COLS], int x,int y)
{
return (LQu[x-1][y]
+ LQu[x - 1][y - 1]
+ LQu[x][y - 1]
+ LQu[x + 1][y - 1]
+ LQu[x + 1][y]
+ LQu[x + 1][y + 1]
+ LQu[x][y + 1]
+ LQu[x - 1][y + 1]
- 8 * '0');
}
在ASCII碼表中
'0' = 48
'1' = 49
'2' = 50
'3' = 51
所以在字符'1' - 字符'0' = (59-48 = 1)
用%d列印就能列印出數字1;
計算雷的個數 因為雷用'1'表示
所以將字符'1'轉換為 數字1相加即可
先把8個'1'相加 再減去(8個'0') 得到雷的個數
傳過來用int 接收加上'0' 轉換成字符'3' 列印到螢屏上即可;
int L = LS(LQu, x, y);
PCha[x][y] = (L+'0');
恭喜你呀!?(?>?<?)? 完成了一個大專案
快來瓶快樂水慶祝一下!
完整代碼如下
test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void game()
{
//創建雷區
char LQu[ROWS][COLS]; //存放雷的資訊
char PCha[ROWS][COLS];//排查雷的資訊
//初始化
CShi(LQu, ROWS, COLS,'0');//雷區
CShi(PCha,ROWS, COLS,'*');//排查區
//列印初始化
//DY(LQu, ROW, COL);//雷區
printf("共有%d個雷\n",LEI);
DY(PCha, ROW, COL);//排查區
//生成雷
S_L(LQu, ROW, COL,LEI);
printf("\n");
//DY(LQu, ROW, COL);//雷區
//排查雷
P_C(LQu,PCha, ROW, COL);
DY(PCha, ROW, COL);//排查區
}
void emnu()
{
printf("************************\n");
printf("******* 1.play *******\n");
printf("******* 0.exly *******\n");
printf("************************\n");
}
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do {
//列印選單
emnu();
printf("請選擇輸入開始游戲:> ");
scanf("%d", &input);
switch (input)
{
case 1:
game();
//printf("游戲開始\n");
break;
case 0:
printf("游戲結束\n");
break;
default:
printf("輸入錯誤,請重新選擇!\n");
break;
}
} while (input);
return 0;
}
game.h
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define LEI 10
//初始化
void CShi(char CShi[ROWS][COLS], int rows, int cols,char ret);//雷區
//列印初始化
void DY(char LQu[ROWS][COLS],int rows,int cols);//雷區
//生成雷
void S_L(char LQu[ROWS][COLS], int row, int col,int lei);
//排查雷
char P_C(char LQu[ROWS][COLS], char PCha[ROWS][COLS], int row, int col);
game.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
//初始化雷區
void CShi (char CShi[ROWS][COLS], int rows, int cols,char ret)
{
int i = 0;
for (i = 0; i < rows; i++)
{
int j = 0;
for (j = 0; j < cols; j++)
{
CShi[i][j] = ret;
}
}
}
//列印
void DY(char LQu[ROWS][COLS], int row, int col)
{
int i = 0;
for (i = 0; i <= row; i++)
{
printf("%d ", i);
}
printf("\n");
for (i = 1; i <= row; i++)
{
int j = 0;
printf("%d ", i);
for (j = 1; j <= col; j++)
{
printf("%c ", LQu[i][j]);
}
printf("\n");
}
printf("\n");
}
//生成雷
void S_L(char LQu[ROWS][COLS], int row, int col,int lei)
{
int i = lei;
while(i)
{
int x = rand() % row+1;
int y = rand() % col+1;
if (LQu[x][y] != '1')
{
LQu[x][y] = '1';
i--;
}
}
}
//判斷周圍的雷數
int LS(char LQu[ROWS][COLS], int x,int y)
{
return (LQu[x-1][y]
+ LQu[x - 1][y - 1]
+ LQu[x][y - 1]
+ LQu[x + 1][y - 1]
+ LQu[x + 1][y]
+ LQu[x + 1][y + 1]
+ LQu[x][y + 1]
+ LQu[x - 1][y + 1]
- 8 * '0');
}
//排查
char P_C(char LQu[ROWS][COLS], char PCha[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int win = 0;
//判斷坐標合法
while (win<row*col-LEI)
{
printf("請輸入坐標:");
scanf("%d %d", &x, &y);
//排查雷
if ((x > 0 && x <=row) && (y > 0 && y <=col))
{
if (LQu[x][y] != '1')
{
//判斷周圍有幾個雷
int L = LS(LQu, x, y);
PCha[x][y] = (L+'0');
DY(PCha, ROW, COL);//排查區
win++;
}
else
{
printf("很遺憾,你輸了\n\n");
DY(LQu, ROW, COL);//雷區
break;
}
}
else
{
printf("坐標非法,請重新輸入!\n\n");
}
}
if (win == ROW * COL - LEI)
{
printf("恭喜你勝利了\n\n");
}
}
如果與任何疑問 歡迎留言 我看到后隨時為你 解答疑問
希望這篇文章對初學C語言的你有所幫助
如果喜歡的話 記得點贊收藏哦!
下次再見?(?>?<?)?
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/413640.html
標籤:其他
下一篇:猜數字游戲+懲罰
