文章目錄
- 一、游戲規則
- 二、設計思路
- 三、程式設計+分段決議
- 游戲基本流程+功能函式
- 1.創建地圖并初始化 init函式
- 兩個二維陣列 ShowMap&MineMap
- 2.列印地圖 Print函式
- 3.玩家確認要排查的位置
- 4.判斷是否踩雷
- 5.更新排查后的地圖 Update
- 6.判定輸贏
- 四、完整代碼
- 五、補充
一、游戲規則
把所有非地雷的地圖格子排查掉,即勝利,踩到地雷格子即失敗!
二、設計思路

三、程式設計+分段決議
游戲基本流程+功能函式

1.創建地圖并初始化 init函式
init 初始化函式
陣列創建好后,我們要對兩個陣列進行初始化,用雙重回圈有些許麻煩,這里使用memset實作,memset功能是把一段記憶體上的每個位元組都設定成一個具體的值, memset(第一段記憶體起始的地址,具體想要轉換成什么樣的值,記憶體的長度)
//1.初始化地圖
void init(char ShowMap[MAX_ROW][MAX_COL], char MineMap[MAX_ROW][MAX_COL]) {
//for (int row = 0; row < MAX_ROW; row++) {
// for (int col = 0; col < MAX_COL; col++) {
// ShowMap[row][col] = '*';
// MineMap[row][col] = '0';
// }
//}
memset(ShowMap, '*', MAX_ROW * MAX_COL);
//此處計算記憶體的長度不能用sizeof,會隱式轉化成指標!因此用sizeof求的是一個指標的長度,并非陣列的長度
memset(MineMap, '0', MAX_ROW * MAX_COL);
srand((unsigned int)time(0));//隨機種子
int MineCount = 0;
while (MineCount<MINE_COUNT) {
int row = rand() % MAX_ROW;//隨即生成10個位置 存放地雷
int col = rand() % MAX_COL;
if (MineMap[row][col] == '1') {
continue;
}
MineMap[row][col] = '1';
MineCount++;
}
}

兩個二維陣列 ShowMap&MineMap
第一個陣列存放地圖的排查狀態,面向玩家創建,展示給玩家,稱之為ShowMap,如下所示:
char ShowMap[MAX_ROW][MAX_COL] = { 0 };
* * * * * * * * *
* * * * * * * * *
* * * * * * * * *
* * * * * * * * *
* * * * * * * * *
* * * * * * * * *
* * * * * * * * *
* * * * * * * * *
* * * * * * * * *
第二個陣列存放地雷的分布資訊,面向游戲設計者創建,稱之為MineMap,如下所示:
char MineMAP[MAX_ROW][MAX_COL] = { 0 };
1 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 1 0
0 1 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 1
0 0 0 0 0 0 1 0 0
0 1 0 0 0 0 0 0 0
0 0 0 0 0 1 0 0 0
0 0 0 0 0 0 0 0 1
2.列印地圖 Print函式
此處形參命名為theMap是希望這個函式同時具備列印兩張地圖的功能,只叫map也不太合適,因為C++標準庫中有一個 std::map
使用雙for回圈實作地圖的列印
void Print(char theMap[MAX_ROW][MAX_COL]) {
for (int row = 0; row < MAX_ROW; row++) {
for (int col = 0; col < MAX_COL; col++) {
printf("%c ", theMap[row][col]);
}
printf("\n");
}
}
3.玩家確認要排查的位置
玩家確定排查位置:在主函式中寫一個while回圈即可實作!
玩家輸入要排查的坐標時,一定不要忘了合法性判定!
1.越界判定
2.重復排查判定
while (1) {
Print(ShowMap);
int row = 0;
int col = 0;
printf("請輸入要排查的坐標(row,col):");
scanf("%d %d", &row, &col);
//合法性判定
//1.越界判定
if (row<0 || row>=MAX_ROW || col<0 || col>=MAX_COL) {
printf("您輸入的坐標已越界,請重新輸入:\n");
continue;
}
//2.重復排查判定
if (ShowMap[row][col] != '*') {
printf("您輸入的坐標位置已被排查,請重新輸入:\n");
continue;
}
4.判斷是否踩雷
玩家輸入坐標排查地圖格子,我們初始化的時候,
while (1) {
int row = 0;
int col = 0;
printf("請輸入要排查的坐標(row,col):");
scanf("%d %d", &row, &col);
if (MineMap[row][col] == '1') {
printf("您踩雷了!游戲結束!!\n");
break;
}
}
5.更新排查后的地圖 Update
Update函式 即實作未踩雷,進行已排查地圖格子周圍格子地雷的個數統計
計算中間位置周圍格子的地雷數count,邊角位置和中間位置不參與計算,使用雙for回圈實作count的計數
周圍格子的表示方式如下圖:

void Update(char ShowMap[MAX_ROW][MAX_COL], char MineMap[MAX_ROW][MAX_COL], int row, int col) {
int count = 0;
for (int r = row - 1; r <= row + 1; r++) {
for (int c = col - 1; c <= col + 1; c++) {
if (r < 0 || r >= MAX_ROW || c < 0 || c >= MAX_COL) { //超出地圖范圍,直接跳出進入下次回圈
continue;
}
if (r == row && c == col) { //中間位置不參與計算 直接進入下次回圈
continue;
}
if (MineMap[r][c] == '1') {
count++;
}
}
}
ShowMap[row][col] = '0' + count;//類似這種轉換 僅限C中使用
//不能直接給賦值,因為 數值是int型別,ShowMap是char型,
//ShowMap[row][col] =2 此時row ,col的位置元素就設定成了ASCII值為2的字符 而不是字符'2'
}
6.判定輸贏
進行掃雷,如果玩家踩雷就被炸死,未踩雷,系統報告周圍雷的個數,直到所有非地雷地圖格子都被排查 即獲勝!
int main(){
char ShowMap[MAX_ROW][MAX_COL] = { 0 };
char MineMap[MAX_ROW][MAX_COL] = { 0 };
init(ShowMap, MineMap);
int openedCount = 0;
while (1) {
Print(ShowMap);
int row = 0;
int col = 0;
printf("請輸入要排查的坐標(row,col):");
scanf("%d %d", &row, &col);
//合法性判定
//1.越界判定
if (row<0 || row>=MAX_ROW || col<0 || col>=MAX_COL) {
printf("您輸入的坐標已越界,請重新輸入:\n");
continue;
}
//2.重復排查判定
if (ShowMap[row][col] != '*') {
printf("您輸入的坐標位置已被排查,請重新輸入:\n");
continue;
}
if (MineMap[row][col] == '1') {
printf("您踩雷了!游戲結束!!\n");
break;
}
system("cls");
//更新ShowMap
Update(ShowMap,MineMap,row,col);
openedCount++;
if (openedCount == MAX_COL * MAX_COL - MINE_COUNT) {
printf("恭喜您!贏得勝利!\n");
}
}
system("pause");
return 0;
}
四、完整代碼
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<time.h>
#define MAX_ROW 9
#define MAX_COL 9
#define MINE_COUNT 10
//1.初始化地圖
void init(char ShowMap[MAX_ROW][MAX_COL], char MineMap[MAX_ROW][MAX_COL]) {
//for (int row = 0; row < MAX_ROW; row++) {
// for (int col = 0; col < MAX_COL; col++) {
// ShowMap[row][col] = '*';
// MineMap[row][col] = '0';
// }
//}
memset(ShowMap, '*', MAX_ROW * MAX_COL);//(第一段記憶體起始的地址,具體想要轉換成什么樣的值,記憶體的長度)
//此處計算記憶體的長度不能用sizeof,會隱式轉化成指標!因此用sizeof求的是一個指標的長度,并非陣列的長度
//memset功能是把 一段記憶體上的每個位元組都設定成一個具體的值
memset(MineMap, '0', MAX_ROW * MAX_COL);//memset 雖然在string頭檔案里,但與字串沒關系,只是方式放錯了,現在改不了,因為“向前兼容!”
srand((unsigned int)time(0));
int MineCount = 0;
while (MineCount<MINE_COUNT) {
int row = rand() % MAX_ROW;//隨即生成10個位置 存放地雷
int col = rand() % MAX_COL;//這樣生成亂數可能會重復,
if (MineMap[row][col] == '1') {
continue;
}
MineMap[row][col] = '1';
MineCount++;
}
}
void Print(char theMap[MAX_ROW][MAX_COL]) {
for (int row = 0; row < MAX_ROW; row++) {
for (int col = 0; col < MAX_COL; col++) {
printf("%c ", theMap[row][col]);
}
printf("\n");
}
}
void Update(char ShowMap[MAX_ROW][MAX_COL], char MineMap[MAX_ROW][MAX_COL], int row, int col) {
int count = 0;
//if (MineMap[row - 1][col - 1] == '1') {
//count++;
//}
for (int r = row - 1; r <= row + 1; r++) {
for (int c = col - 1; c <= col + 1; c++) {
if (r < 0 || r >= MAX_ROW || c < 0 || c >= MAX_COL) { //超出地圖范圍,直接跳出進入下次回圈
continue;
}
if (r == row && c == col) { //中間位置不參與計算 直接進入下次回圈
continue;
}
if (MineMap[r][c] == '1') {
count++;
}
}
}
ShowMap[row][col] = '0' + count;//類似這種轉換 僅限C中使用
//不能直接給賦值,因為 數值是int型別,ShowMap是char型,
//ShowMap[row][col] =2 此時row ,col的位置元素就設定成了ASCII值為2的字符 而不是字符'2'
}
int main(){
//Menu();
char ShowMap[MAX_ROW][MAX_COL] = { 0 };
char MineMap[MAX_ROW][MAX_COL] = { 0 };
init(ShowMap, MineMap);
int openedCount = 0;
while (1) {
Print(ShowMap);
int row = 0;
int col = 0;
printf("請輸入要排查的坐標(row,col):");
scanf("%d %d", &row, &col);
//合法性判定
//1.越界判定
if (row<0 || row>=MAX_ROW || col<0 || col>=MAX_COL) {
printf("您輸入的坐標已越界,請重新輸入:\n");
continue;
}
//2.重復排查判定
if (ShowMap[row][col] != '*') {
printf("您輸入的坐標位置已被排查,請重新輸入:\n");
continue;
}
if (MineMap[row][col] == '1') {
printf("您踩雷了!游戲結束!!\n");
break;
}
system("cls");
//更新ShowMap
Update(ShowMap,MineMap,row,col);
openedCount++;
if (openedCount == MAX_COL * MAX_COL - MINE_COUNT) {
printf("恭喜您!贏得勝利!\n");
}
}
system("pause");
return 0;
}
五、補充
#define MAX_ROW 9 //地圖行寬
#define MAX_COL 9 //地圖列寬
#define MINE_COUNT 10
在創建地圖時,建立了兩個二維陣列,ShowMap[9][9] 和 MineMap[9][9],代碼中沒有直接寫9,是用宏給一個定義,避免這些魔幻數字的出現!大大增加代碼的可讀性~~
srand((unsigned int)time(0));//隨機種子
int row = rand() % MAX_ROW;//隨即生成10個位置 存放地雷
int col = rand() % MAX_COL;
rand() 用于生成亂數,但不是生成真正的亂數
srand()用于設定供rand使用的亂數種子
第一次呼叫rand之前沒有呼叫srand,那么系統會為你自動呼叫srand,自動呼叫傳參值為1,這樣的話,采用相同的種子則每次生成的亂數便會重復,故我們常常使用“時間戳”來初始化~包含在頭檔案<time.h>中
這里不做詳細的解釋,后序會出 rand&srand 篇!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/280981.html
標籤:其他
下一篇:小游戲三子棋
