簡易掃雷小遊戲
- 遊戲介紹
- 功能設計
- 具體實作
-
- 棋盤的建立
- 初始化
- 布置雷
- 棋盤展示
- 玩家第一次落子時不踩雷
- 統計落子處周圍雷的個數
- 遞歸實作周圍無雷時自動展開的功能
- 統計目前棋盤已清掃的空格數,以判斷最終掃雷是否成功
- 遊戲效果
本文所介紹的掃雷僅僅是用C語言的一些最基本的文法所實作,并沒有涉及高深的資料結構與算法,僅僅是為了鞏固筆者最近所學的C語言文法。若有錯誤還望多多指教。
遊戲介紹
掃雷是一款十分經典的電腦休閑單機遊戲,遊戲目标是在最短的時間内根據點選格子出現的數字找出所有非雷格子,同時避免踩雷,踩到一個雷即全盤皆輸。
功能設計
- 簡易的圖形化界面
- 玩家通過輸入坐标以選擇要掃雷的位置。
- 玩家第一次落子一定不踩雷
- 顯示選擇的坐标周圍雷的個數,若周圍沒有雷則自動展開。
具體實作
在這裡具體介紹幾個核心功能,完整代碼見Gitee: 傳送門.
棋盤的建立
這裡建立了兩個二維數組,一個用于雷的布置,一個用于圖形化的展示.
#define ROW 9
#define COL 9
#define ROWS ROW + 2
#define COLS ROW + 2
char mine[ROWS][COLS] = { 0 };
char show[ROWS][COLS] = { 0 };
棋盤的格式為9x9,這裡建立11x11的二維數組是為了當玩家選擇坐标在棋盤周圍時,正确顯示所落子處四周雷的個數。
是以,這裡将存放雷的數組最外層全部初始化為0(0表示無雷,1表示雷)。
用于展示的數組則全部初始化為“ * ” ,通過僞随機數的生成,來生成初始雷的坐标
初始化
Init(mine, ROW, COL, '0');
Init(show, ROW, COL, '*');
void Init(char board[ROWS][COLS], int row, int col, char set)
{
int i = 0 ;
int j = 0 ;
for (i = 0; i < row + 2; i++)
{
for (j = 0; j < col + 2; j++)
{
board[i][j] = set;
}
}
}
布置雷
這裡雷的布置采用了生成随機數的方法,具體方式為調用rand()函數,并在調用rand()函數之前,先用srand()為僞随機數生成器播撒種子,種子采用系統時鐘來生成。
需要引用的頭檔案和定義:
#include<stdlib.h>
#include<time.h>
#define COUNT 10 //雷的個數
要注意的是srand()一定要在rand()之前使用,否則每次随機種子就是一定的,那麼産生出來的随機數就是固定的。這裡把srand()放在主函數一開始實作
雷坐标的生成:
Set_Mine(mine, ROW, COL,COUNT);
void Set_Mine(char mine[ROWS][COLS], int row, int col, int count)
{
while (count)
{
int x = rand() % row + 1;
int y = rand() % col + 1;
if (mine[x][y] == '0')
{
mine[x][y] = '1';
count--;
}
}
}
棋盤展示
Display(show, ROW, COL);
```handlebars
void Display(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
printf("******掃雷遊戲*******\n");
for (i = 0; i < row + 1; i++)
{
printf("%d ", i);
for (j = 1; j < col + 1; j++)
{
if (i == 0)
printf("%d ", j);
else
printf("%c ", board[i][j]);
}
printf("\n");
}
}
具體效果:
用于展示的棋盤:(周圍的數字為友善玩家輸入坐标)
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnLwETM4QTOzMTM1ATNwEjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
用于放置雷的棋盤:
掃雷
這裡将統計落子處四周雷的個數,實作周圍無雷時自動展開的功能以及統計已排查的無雷坐标個數以确定玩家赢的條件分别封裝為單獨的函數,具體實作如下:
Sweep(mine, show, ROW, COL, COUNT);
void Sweep(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int count)
{
int x = 0;
int y = 0;
int judge = 0;
while (judge < row*col - count)
{
printf("請輸入要掃除的坐标: \n");
scanf("%d %d", &x, &y);
if (x < 0 || y < 0 || x > row || y > col)
printf("坐标非法,請重新輸入:\n");
else if (show[x][y] != '*')
printf("該坐标已被掃除,請重新輸入:\n");
if(judge == 0)
No_mine(mine, show, x, y, row, col);
if (mine[x][y] != '1')
{
Spread(x, y, mine, show, row, col);
Display(show, row, col);
}
else
{
printf("你被炸死了\n");
break;
}
Stat_judge(show, &judge, row, col);
}
if (judge == row * col - count)
{
printf("恭喜你排雷成功\n");
}
}
玩家第一次落子時不踩雷
void No_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int i, int j, int row, int col)
{
if (mine[i][j] == '1')
{
while (1)
{
int x = rand() % row + 1;
int y = rand() % col + 1;
if (mine[x][y] == '0')
{
mine[x][y] = '1';
break;
}
}
mine[i][j] = '0';
}
}
統計落子處周圍雷的個數
int Count_Mine(int x, int y, char mine[ROWS][COLS])
{
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';
}
遞歸實作周圍無雷時自動展開的功能
void Spread(int x, int y, char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
char count = Count_Mine(x, y, mine) + '0';
if (count != '0')
show[x][y] = count;
else
{
show[x][y] = ' ';
if (x - 1 > 0 && show[x - 1][y] == '*')
Spread(x - 1, y, mine, show, row, col);
if (y - 1 > 0 && show[x][y - 1] == '*')
Spread(x, y - 1, mine, show, row, col);
if (y + 1 < col + 1 && show[x][y + 1] == '*')
Spread(x, y + 1, mine, show, row, show);
if (x + 1 < row + 1 && show[x + 1][y] == '*')
Spread(x + 1, y, mine, show, row, col);
}
}
統計目前棋盤已清掃的空格數,以判斷最終掃雷是否成功
void Stat_judge(char show[ROWS][COLS], int* judge, int row, int col)
{
int i = 0;
int j = 0;
for (i = 1; i < row + 1; i++)
{
for (j = 1; j < col + 1; j++)
{
if (show[i][j] != '*')
(*judge)++;
}
}
}
遊戲效果
自動展開
踩雷
勝利