??業精于勤,荒于嬉;行成于思,毀于隨,
??2021農歷辛丑牛年,祝所有人心想事成,萬事勝意!
??二維陣列練習第二彈,實作掃雷小游戲,
文章目錄
- 一、掃雷游戲規則
- 二、游戲流程
- 三、掃雷游戲的雙層陣列
- 兩個二維陣列
- 布雷陣列巧妙的設計
- 四、程式設計
- 頭檔案
- 游戲實作框架
- 功能函式
- InitBoard
- DisplayBoard
- SetMine
- FindMine
- 五、完整程式
- 六、游戲測驗
- 七、寫在后面
一、掃雷游戲規則
??把所有非地雷的格子揭開即勝利,踩到地雷格子即失敗,
二、游戲流程
電腦列印游戲選單(1.開始游戲 0.退出游戲)——>玩家選擇(開始游戲——>進入游戲函式)——>電腦列印出雷盤——>玩家輸入需要排雷的坐標——>可能性1:被炸死 可能性2:坐標安全,系統顯示出周圍八個格子內的地雷總數——>雷盤更新——>玩家輸入需要排雷的坐標,繼續排雷——>游戲勝利
三、掃雷游戲的雙層陣列
??前文有寫到三(多)子棋小游戲,三子棋游戲只需要一個陣列就夠了,但是對于掃雷游戲的實作,一個陣列是不夠的,需要創建兩個陣列,
兩個二維陣列
??第一個陣列,存放雷的分布資訊,面向游戲設計者創建,暫且稱之為雷盤布置陣列,簡稱布雷陣列,(1代表雷,0代表安全坐標,這里是符號’1’和符號’0’)如下所示,
0 1 2 3 4 5 6 7 8 9
1 0 0 0 0 0 1 0 1 0
2 0 0 0 0 0 0 1 0 0
3 0 1 0 0 0 0 1 1 0
4 0 0 0 0 0 0 0 0 0
5 0 0 0 0 1 0 0 0 0
6 0 0 0 0 0 0 0 0 0
7 0 0 0 0 1 0 0 0 0
8 0 1 0 0 0 0 1 0 0
9 0 0 0 0 0 0 0 0 0
??第二個陣列,存放排雷后的雷盤中雷的分布個數資訊,面向玩家創建,暫且稱之為玩家陣列,如下所示,
0 1 2 3 4 5 6 7 8 9
1 * * * * * * * * *
2 * * * * * * * * *
3 * * 1 * * * * * *
4 * * * * * * * * *
5 * * * * * * * * *
6 * * * * * * * * *
7 * * * * * * * * *
8 * * * * * * * * *
9 * * * * * * * * *
布雷陣列巧妙的設計
??程式設計的時候,需要判斷玩家坐標周圍八個格子中雷的總個數,那么這就帶來一個問題:
??玩家選擇邊角最外環的一層坐標和玩家選擇內環坐標判斷方法不同,目測有兩種解決方案,
??第一種:加if判斷
如果是最外面的一圈的就單獨拉出來判斷其周圍的雷的總數,但是這又導致了一個問題,四個角和每條棱的判斷方法各不相同,所以這個解決方案很繁瑣,
??第二種:巧妙地讓布雷陣列膨脹一圈
假設讓布置雷的雷盤是11X11規格的,但是只在9X9的格子里布雷,那么對于每個9X9格子里的坐標,判斷周圍格子里雷的總數的演算法都是一樣的,(把巧妙打在公屏上!!!)
四、程式設計
??創建三個檔案,game.h 游戲的頭檔案functions.c游戲所用到功能函式 game.c 游戲框架 三個檔案,
頭檔案
??頭檔案的書寫是一步一步需要什么寫什么建立而來的,這里先把所有的宏定義、庫函式參考、函式宣告放這里,后面用到會有解釋,
#define _CRT_SECURE_NO_WARNINGS 1
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define EASY_COUNT 10
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
void test(void);
void menu(void);
void game(void);
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[ROW][COL], int row, int col);
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
游戲實作框架
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include "game.h"
int main(void)
{
test();
return 0;
}
//游戲執行測驗框架
void test(void)
{
int input = 0;
do {
menu();//系統列印游戲選單,呼叫menu函式
printf("請選擇:>>>");
scanf("%d", &input);
switch (input)//switch開關陳述句,作用顯而易見
{
case 1:
game();//呼叫game函式
break;
case 2:
printf("退出游戲\n");
input = 0;
break;
default:
printf("輸入值無效\n");
break;
}
} while (input);
}
//選單列印函式
void menu(void)
{
printf("************************************\n");
printf("*****1.開始游戲 0.退出游戲******\n");
printf("************************************\n");
}
//游戲主函式
void game(void)
{
//第一步,創建兩個陣列,一個是布盤陣列,一個是用戶陣列
//兩個陣列大小相同,屬于疊加的雙層結構,
char mine[ROWS][COLS] = { 0 };
char show[ROWS][COLS] = { 0 };
//第二步,初始化
InitBoard(mine, ROWS, COLS, '0');//初始化兩個陣列,
InitBoard(show, ROWS, COLS, '*');
//第三步,布置雷
SetMine(mine, ROW, COL);//布置雷
DisplayBoard(mine, ROW, COL);//列印雷盤分布,上帝視角,測驗需要,
DisplayBoard(show, ROW, COL);//更新列印好后的雷盤
//第四步,掃雷
FindMine(mine, show, ROW, COL);
}
功能函式
??游戲主函式中除游戲框架外的所有函式,習慣單獨寫在一個檔案里,
InitBoard
??陣列創建好,需要對兩個陣列進行初始化,但是因為兩個陣列初始化的分辨元素不一樣,所以這里加入一個呼叫引數set,
//初始化函式
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;//讓布雷陣列全部元素為字符'0',玩家陣列全部為字符'*'
}
}
}
DisplayBoard
??初始化函式寫好之后可以先寫雷盤列印函式進行核驗,所以先介紹DisplayBoard函式,
//雷盤列印
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
printf("\n");//列印個換行符分割下,不是必要
//列印列號
for (i = 0; i <= row; 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");
}
printf("\n");//列印個換行符分割下,不是必要
}
SetMine
??陣列初始化好就要布置雷了,采用隨機值的方法進行布雷,傳遞整個陣列,但需要控制雷的分布只出現在內環9*9的網格里,
//布置雷盤
void SetMine(char board[ROWS][COLS], int row, int col)
{
int count = EASY_COUNT;
srand((unsigned int)time(NULL));//使用系統時間作為隨機值的種子
while (count)//控制雷的個數
{
int x = rand() % row + 1;
int y = rand() % col + 1;
if (board[x][y] == '0')
{
board[x][y] = '1';
count--;
}
}
}
FindMine
??進行掃雷,如果玩家踩雷就被炸死,未踩雷,系統報告周圍雷的個數,
//掃雷
void FindMine(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 - EASY_COUNT)
{
printf("請輸入排查雷的坐標:>>>");
scanf("%d%d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (mine[x][y] == '1')
{
printf("\n啊哦,你被炸死了!!!\n");
DisplayBoard(mine, row, col);
break;
}
else
{//計算周圍8個方塊中雷的總數
int count = (mine[x - 1][y] + mine[x - 1][y - 1] +
mine[x][y - 1] + mine[x + 1][y - 1] +
mine[x + 1][y] + mine[x + 1][y + 1] +
mine[x][y + 1] + mine[x - 1][y + 1]) - 8 * '0';
show[x][y] = count + '0';
DisplayBoard(show, row, col);
win++;//玩家輸入一次win加一次,等到棋盤上只有雷就勝利了
}
}
else
{
printf("非法輸入!!!\n");
}
}
}
五、完整程式
#define _CRT_SECURE_NO_WARNINGS 1
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define EASY_COUNT 10
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
void test(void);
void menu(void);
void game(void);
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 FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include "game.h"
int main(void)
{
test();
return 0;
}
//游戲執行測驗框架
void test(void)
{
int input = 0;
do {
menu();//系統列印游戲選單,呼叫menu函式
printf("請選擇:>>>");
scanf("%d", &input);
switch (input)//switch開關陳述句,作用顯而易見
{
case 1:
game();//呼叫game函式
break;
case 2:
printf("退出游戲\n");
input = 0;
break;
default:
printf("輸入值無效\n");
break;
}
} while (input);
}
//選單列印函式
void menu(void)
{
printf("************************************\n");
printf("*****1.開始游戲 0.退出游戲******\n");
printf("************************************\n");
}
//游戲主函式
void game(void)
{
//第一步,創建兩個陣列,一個是布盤陣列,一個是用戶陣列,兩個陣列大小相同,屬于疊加的雙層結構,
char mine[ROWS][COLS] = { 0 };
char show[ROWS][COLS] = { 0 };
//第二步,初始化
InitBoard(mine, ROWS, COLS, '0');//初始化兩個陣列,
InitBoard(show, ROWS, COLS, '*');
//第三步,布置雷
SetMine(mine, ROW, COL);//布置雷
DisplayBoard(mine, ROW, COL);//列印雷盤分布,上帝視角,測驗需要,
DisplayBoard(show, ROW, COL);//更新列印好后的雷盤
//第四步,掃雷
FindMine(mine, show, ROW, COL);
}
#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;//讓布雷陣列全部元素為字符'0',玩家陣列全部為字符'*'
}
}
}
//列印雷盤
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
printf("\n");//列印個換行符分割下,不是必要
//列印列號
for (i = 0; i <= row; 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");
}
printf("\n");//列印個換行符分割下,不是必要
}
//布置雷盤
void SetMine(char board[ROWS][COLS], int row, int col)
{
int count = EASY_COUNT;
srand((unsigned int)time(NULL));//使用系統時間作為隨機值的種子
while (count)//控制雷的個數
{
int x = rand() % row + 1;
int y = rand() % col + 1;
if (board[x][y] == '0')
{
board[x][y] = '1';
count--;
}
}
}
//掃雷
void FindMine(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 - EASY_COUNT)
{
printf("請輸入排查雷的坐標:>>>");
scanf("%d%d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (mine[x][y] == '1')
{
printf("\n啊哦,你被炸死了!!!\n");
DisplayBoard(mine, row, col);
break;
}
else
{//計算周圍8個方塊中雷的總數
int count = (mine[x - 1][y] + mine[x - 1][y - 1] +
mine[x][y - 1] + mine[x + 1][y - 1] +
mine[x + 1][y] + mine[x + 1][y + 1] +
mine[x][y + 1] + mine[x - 1][y + 1]) - 8 * '0';
show[x][y] = count + '0';
DisplayBoard(show, row, col);
win++;//玩家輸入一次win加一次,等到棋盤上只有雷就勝利了
}
}
else
{
printf("非法輸入!!!\n");
}
}
}
六、游戲測驗
??這里將ROW和COL更改成3,EASY_COUNT改成了5進行測驗,
************************************
*****1.開始游戲 0.退出游戲******
************************************
請選擇:>>>1
0 1 2 3
1 1 1 0
2 1 0 1
3 0 0 1
0 1 2 3
1 * * *
2 * * *
3 * * *
請輸入排查雷的坐標:>>>1 1
啊哦,你被炸死了!!!
0 1 2 3
1 1 1 0
2 1 0 1
3 0 0 1
************************************
*****1.開始游戲 0.退出游戲******
************************************
請選擇:>>>1
0 1 2 3
1 0 1 1
2 1 0 1
3 0 1 0
0 1 2 3
1 * * *
2 * * *
3 * * *
請輸入排查雷的坐標:>>>2 2
0 1 2 3
1 * * *
2 * 5 *
3 * * *
請輸入排查雷的坐標:>>>1 1
0 1 2 3
1 2 * *
2 * 5 *
3 * * *
請輸入排查雷的坐標:>>>3 1
0 1 2 3
1 2 * *
2 * 5 *
3 2 * *
請輸入排查雷的坐標:>>>3 3
0 1 2 3
1 2 * *
2 * 5 *
3 2 * 2
恭喜你,歷經千辛萬苦排雷成功!
************************************
*****1.開始游戲 0.退出游戲******
************************************
請選擇:>>>
七、寫在后面
??總的來說,這個程式只用了四個功能函式(處游戲框架外)實作了基本的掃雷程式,但是游戲還是非常雞肋的,在真正的掃雷游戲中,當玩家選擇的坐標周圍八個坐標均沒有雷時雷盤會之間展開,這還是很必要的,因為當掃雷的棋盤很大時,一個一個的選擇坐標實屬太沒有游戲體驗了,這個需要加入一個遞回展開函式,
??加入遞回展開后,游戲勝利判斷條件也需要改變,相對復雜,所以寫在了下一篇博客,歡迎各位大佬進行檢閱、批評和指正,非常感謝!!!非常感謝!!!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/259558.html
標籤:其他
