前言:寫完三子棋后,慢慢地熟悉了這種寫小游戲的程序,之前對于代碼的磁區存盤都還是懵懵的,現在終于有點得心應手啦,話不多說,這次我寫的是掃雷,但是博主水平有限,目前還不能做到圖形化界面,日后有能力時定來修改這篇文章,實作一個帶有圖形化界面的掃雷!
文章目錄
- 1.游戲準備
- 2.主函式
- 3.test函式
- 5.menu函式
- 6.game函式
- 7.初始化雷盤
- 8.放置地雷
- 9.展示雷盤
- 10.玩家排雷
- 11.完整代碼展示
- 11.1 game.c
- 11.3 game.h
- 11.3 test.c
- 12 效果展示
1.游戲準備
先來看看掃雷的樣子

與三子棋一樣,我們可以把要排雷的雷盤?(是這個名字不?)看成一個二維陣列,當我們點擊格子時,格子會顯示周圍一圈的雷數,先要有一個二維陣列來放我們的雷,但我們不可能把這個陣列展示給玩家看(這樣直接開透視了呀),我們得再創建一個二維陣列展示給玩家,這個陣列開始時全是’ * ’ ,當玩家輸入一個坐標時,’ * ’ 會變成周圍一圈的雷數,
經過梳理,游戲的邏輯就清晰了:開始時我們要初始化兩個陣列,一個用來放雷(我們叫這個陣列mine),另一個用來向玩家展示(我們叫它show),接著我們會放置地雷,把show陣列列印給玩家看,玩家輸入坐標,開始排雷,每成功排一次雷,我們都要展示雷盤當場上剩下的格子數等于雷數時,游戲勝利,玩家踩雷時,游戲結束,所以我們這是一個判斷輸贏的函式,大概的程序我們就理清楚了,
還是像三子棋一樣,我們把整個游戲分成三個部分:
test.c — > 程式的運行邏輯
game.c — > 游戲的實作邏輯
game.c — > 存放游戲相關函式的代碼與庫函式的頭檔案
接著是游戲代碼
2.主函式
int main()
{
srand((unsigned int)time(NULL));//設定亂數種子,用來隨機生成地雷
test();
return 0;
}
為了讓代碼看起來整潔,在主函式中呼叫test函式
3.test函式
test函式是游戲運行的邏輯
void test()
{
int input = 0;
do
{
menu();//開始游戲前列印選單
printf("請選擇 > 1/0\n");
scanf("%d", &input);//input變數存放玩家的選擇
switch (input)//根據input的值switch進入不同的分支
{
case 1:
game();//游戲邏輯的實作函式
break;
case 0:
printf("退出游戲\n");
default :
printf("輸入錯誤,請重新輸入\n");
break;
}
} while (input);//玩家可以反復玩游戲,玩家選0時退出游戲
}
代碼實作與三子棋的類似,這次寫這部分代碼時就很熟練了,
5.menu函式
游戲選單(這個就和三子棋一模一樣了)
void menu()
{
printf("***********************\n");
printf("***** 1.開始游戲 ****\n");
printf("***** 0.退出游戲 ****\n");
printf("***********************\n");
}
6.game函式
void game()
{
//雷棋盤與展示棋盤的初始化
char mine[ROWS][COLS] = { '0' };
char show[ROWS][COLS] = { '0' };
//初始化放雷棋盤
InitBoard(mine, ROWS, COLS,'0');
//初始化展示棋盤
InitBoard(show, ROWS, COLS,'*');
//放置地雷
SetMine(mine, ROW, COL);
//列印展示棋盤
DisplayBoard(show, ROW, COL);
//玩家排雷
Find(mine, show, ROW, COL);
}
game函式就是我們剛剛梳理的游戲邏輯,接著我們就要一個個實作這些函式了,
7.初始化雷盤
首先呢,與三子棋不一樣的是,我們這次要初始化兩個棋盤,但是兩個棋盤的初始化內容是不一樣的,這就要求我們的初始化函式要有相對的獨立性來實作對不同陣列的初始化,要怎么做呢?我們可以在函式設定四個引數
- 一個二維陣列
- 陣列的行
- 陣列的列
- 要初始化的內容(mine要初始化的內容就是’0’,show的是’*’)
我們來看看函式的實作
//初始化棋盤
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;//將所有元素初始化
}
}
}
這里解釋為什么定義ROWS,COLS,ROW,COL這四個宏,
mine陣列中,除了雷是用1表示,其他的元素都是用0表示,計算雷數時,把周圍八個元素的值相加,得到的數剛好就是雷數,但是我們對邊界上的元素進行排雷時,會出先陣列的越界訪問,產生意想不到的結果,這當然不是我們想要的,所以,對陣列增加兩行與兩列(假設二維陣列是9 * 9的,增加后變為11 * 11),對11 * 11的陣列初始化,但我們使用的是9 * 9 的陣列,在計算雷數時就不會出現錯誤了,

所以,我們把ROWS與COLS設定成11,ROW與COL設值成9,
8.放置地雷
初始化后,我們就要放地雷了,
//放置地雷
//這里有個小細節,我們的陣列大小是ROWS * COLS
//但放地雷時只能在ROW * COL大小的陣列中
void SetMine(char board[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int count = CON;
//CON又是一個宏,指的是我們要放置的雷數
//CON在頭檔案中定義
//用count變數接收CON常量的值,放一次雷count減一
while (count)
{
//利用亂數產生坐標
x = rand() % row + 1;
y = rand() % col + 1;
//坐標的值可能相同,所以要判斷坐標是否合理
if (board[x][y] == '0')
{
board[x][y] = '1';
count--;//當count為0時,回圈結束
}
}
}
由于我們要用到rand函式,所以在主函式中,我們呼叫了srand函式設定亂數種子,

9.展示雷盤
展示雷盤的時候,要是直接把雷盤列印出來,玩家輸入坐標時對行號與列號可能會不太確定(畢竟數量有點多嘛),
看得清不?哈哈哈,所以我們要對行與列加上序號,方便玩家確定坐標
//同時列印行號與列號
//我們展示的雷盤大小是ROW * COL
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
//列號的列印
for (i = 0; i <= 9; i++)
{
printf("%d ", i);
}
printf("\n");
for (i = 1; i <= row; i++)
{
//行號的列印
//在列印行之前先列印行號
printf("%d ", i);
for (j = 1; j <= col; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
}

這樣就好認多了
10.玩家排雷
接著就到了玩家進行排雷了,通過玩家輸入坐標,程式把對應的陣列元素賦值成周圍一圈的雷數,要是踩到雷了,提示玩家玩得太菜 游戲結束,但這又有一個細節,我們創建的陣列是字符陣列,放置的是字符,把字符相加得到的是對應的ASCII碼值,所以我們把相加后的值減去八個字符0的ASCII碼值,得到的就是雷數了,我寫了一個num函式來計算雷數,
//num函式回傳型別是整形
int num(char board[ROWS][COLS], int x, int y)
{
//回傳八個周圍元素的相加值,但回傳的得是整形,所以減去八個字符0
return board[x - 1][y]
+ board[x - 1][y - 1] +
board[x][y - 1] +
board[x + 1][y - 1] +
board[x + 1][y] +
board[x + 1][y + 1] +
board[x][y + 1] +
board[x - 1][y + 1] -
8 * '0';
}
接著是玩家排雷的函式
void Find(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
//設定變數接收玩家輸入的值
int win = 0;
//用win變數判斷玩家是否勝利
//win初始值為0,每排一次雷win加一
while (win < ROW * COL - CON)
{
printf("請輸入坐標\n");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= 9 && y >= 1 && y <= 9 && show[x][y] == '*')
//判斷玩家輸入的坐標在雷盤中并且沒有對坐標進行過掃雷
{
if (mine[x][y] == '1')
{
printf("很遺憾,你被炸死了\n");
DisplayBoard(mine, ROW, COL);
//玩家被炸死后展示雷盤
break;
}
else
{
//計算雷的數量
int n = num(mine, x, y);
//把展示雷盤對應的元素賦值成周圍雷數
show[x][y] = n + '0';
//但展示雷盤是字符陣列,雷數要加上字符0
DisplayBoard(show, ROW, COL);
//每次排雷展示雷盤
win++;
}
}
else
printf("輸入錯誤,請重新輸入\n");
}
//當win等于雷盤大小減去雷數時,玩家排雷成功,游戲結束
if (win == ROW * COL - CON)
{
printf("恭喜你,排雷成功\n");
}
}
至此所有的代碼我們就完成了,接著是所有檔案代碼的整體展示
11.完整代碼展示
11.1 game.c
#include"game.h"
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;
}
}
}
//同時列印行號與列號
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
//列號的列印
for (i = 0; i <= 9; i++)
{
printf("%d ", i);
}
printf("\n");
for (i = 1; i <= row; i++)
{
//行號的列印
printf("%d ", i);
for (j = 1; j <= col; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
}
void SetMine(char board[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int count = CON;
while (count)
{
x = rand() % row + 1;
y = rand() % col + 1;
if (board[x][y] == '0')
{
board[x][y] = '1';
count--;
}
}
}
int num(char board[ROWS][COLS], int x, int y)
{
return board[x - 1][y] + board[x - 1][y - 1] + board[x][y - 1] + board[x + 1][y - 1] + board[x + 1][y] + board[x + 1][y + 1] + board[x][y + 1] + board[x - 1][y + 1] - 8 * '0';
}
void Find(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 - CON)
{
printf("請輸入坐標\n");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= 9 && y >= 1 && y <= 9)
{
if (mine[x][y] == '1')
{
printf("恭喜你,你被炸死了\n");
DisplayBoard(mine, ROW, COL);
break;
}
else
{
//計算雷的數量
int n = num(mine, x, y);
show[x][y] = n + '0';
DisplayBoard(show, ROW, COL);
win++;
}
}
else
printf("輸入錯誤,請重新輸入\n");
}
if (win == ROW * COL - CON)
{
printf("恭喜你,排雷成功\n");
}
}
11.3 game.h
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#define ROWS 11
#define COLS 11
#define ROW 9
#define COL 9
#define CON 10
//初始化棋盤
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set);
//展示棋盤
void DisplayBoard(char board[ROWS][COLS], int row, int col);
//放置地雷
void SetMine(char board[ROWS][COLS], int row, int col);
//玩家排雷
void Find(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
11.3 test.c
#include"game.h"
void menu()
{
printf("***********************\n");
printf("***** 1.開始游戲 ****\n");
printf("***** 0.退出游戲 ****\n");
printf("***********************\n");
}
void game()
{
char mine[ROWS][COLS] = { '0' };
char show[ROWS][COLS] = { '0' };
//初始化放雷棋盤
InitBoard(mine, ROWS, COLS,'0');
//初始化展示棋盤
InitBoard(show, ROWS, COLS,'*');
//放置地雷
SetMine(mine, ROW, COL);
//列印展示棋盤
DisplayBoard(show, ROW, COL);
//玩家排雷
Find(mine, show, ROW, COL);
}
void test()
{
int input = 0;
do
{
menu();
printf("請選擇 > 1/0\n");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戲\n");
default :
printf("輸入錯誤,請重新輸入\n");
break;
}
} while (input);
}
int main()
{
srand((unsigned int)time(NULL));
test();
return 0;
}
12 效果展示

排雷成功的效果就是這樣啦
最后:博主水平有限,寫的程式還有不夠完善的地方,對程式的優化這幾天會寫完(雖然不能實作圖形化界面),xdm動動小手點個贊唄
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/357211.html
標籤:其他
下一篇:C語言小游戲之掃雷
