1. 掃雷游戲分析和設(shè)計(jì)
掃雷游戲的起源可以追溯到20世紀(jì)60年代,當(dāng)時(shí)這款游戲是由IBM開發(fā)出來的。在80年代初,微軟公司將其收歸旗下,并將其作為Windows操作系統(tǒng)自帶的一款游戲。自此以后,掃雷成為了Windows用戶最喜歡的休閑游戲之一,也受到了全球范圍內(nèi)的玩家喜愛。
現(xiàn)在,我們使用C語(yǔ)言,來實(shí)現(xiàn)一個(gè)簡(jiǎn)單的掃雷游戲。
1.1 掃雷游戲的功能說明
? 使?控制臺(tái)實(shí)現(xiàn)經(jīng)典的掃雷游戲
? 游戲可以通過菜單實(shí)現(xiàn)繼續(xù)玩或者退出游戲
? 掃雷的棋盤是9*9的格子(可以自定義拓展)
? 默認(rèn)隨機(jī)布置10個(gè)雷(可以自定義拓展)
? 可以排查雷:
? 如果位置不是雷,就顯示周圍有幾個(gè)雷
? 如果位置是雷,就炸死,游戲結(jié)束
? 把除10個(gè)雷之外的所有非雷都找出來,排雷成功,游戲結(jié)束
1.2 游戲的分析和設(shè)計(jì)?
掃雷棋盤是一個(gè)9×9的方格,所以我們首先想到用二維數(shù)組創(chuàng)建9×9棋盤,用來存放棋盤內(nèi)容。
? ? ? ? ? ? ? ? ? ? ? 0為非雷,1為雷
掃雷的基本邏輯是:選擇一個(gè)方格,若是雷,則游戲失?。蝗舨皇抢?,則該方格顯示周圍一圈8個(gè)方格中雷的個(gè)數(shù)。
例如選擇2行3列,該方格不是雷,而它的周圍一圈中2行2列為雷,共1個(gè)雷,則2行3列顯示“1”,表示它的周圍一圈有一個(gè)雷。
但是當(dāng)我們選擇最外圈的一個(gè)方格時(shí),它的周圍無法構(gòu)成8個(gè)方格;并且我們知道數(shù)組是從0開始的,因此會(huì)有0行0列這樣的坐標(biāo)產(chǎn)生。
為了解決這樣的問題,我們需要準(zhǔn)備兩個(gè)11×11棋盤,相比于9×9棋盤,多出的兩行兩列用來解決剛才提出的兩個(gè)問題。一個(gè)棋盤用來在后臺(tái)布置雷,一個(gè)棋盤用來在前臺(tái)讓玩家排雷。
? ? ? ? ? ?為了不造成沖突,我們令‘0’為非雷(字符0),‘1’為雷(字符1)
用來布置雷的棋盤,我們命名為mine,用來排雷的棋盤全部顯示‘*’來保持神秘感,命名為show。
char mine[11][11]={0};//存放布置好的雷的信息
char show[11][11]={0};//存放排查好的雷的信息
2.游戲代碼實(shí)現(xiàn)
2.1前置過程
在程序主體文件test.c中,我們實(shí)現(xiàn)菜單功能,游戲主體功能,以及main函數(shù)集中調(diào)用功能:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include"game.h"
void menu()
{
printf("***********************\n");
printf("****** 1.游戲開始 ******\n");
printf("****** 0.退出游戲 ******\n");
printf("***********************\n");
}
void game()
{
//掃雷游戲
//mine數(shù)組存放布置好的雷的信息
//show數(shù)組存放排查出的雷的信息
//初始化棋盤
//布置雷
//打印棋盤
//排查雷
}
void test()
{
menu();
printf("請(qǐng)選擇:-->");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("游戲結(jié)束,退出游戲\n");
break;
default:
printf("選擇錯(cuò)誤,重新選擇\n");
break;
}
}
int main()
{
test();
return 0;
}
接著在聲明文件game.h中,使用宏定義,定義棋盤大小和雷的個(gè)數(shù),這樣做可以非常方便的調(diào)整參數(shù),后期不用調(diào)整很多代碼。
#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define EASY_COUNT 10//雷
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
所以我們的數(shù)組可以表示為
//mine數(shù)組存放布置好的雷的信息
char mine[ROWS][COLS] = { 0 };
//show數(shù)組存放排查出的雷的信息
char show[ROWS][COLS] = { 0 };
2.2功能模塊實(shí)現(xiàn)
2.2.1實(shí)現(xiàn)初始化棋盤的功能
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
{
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
board[i][j] = set;
}
}
}
由于我們需要初始化兩個(gè)棋盤,可以用形參set作為媒介,為不同的棋盤輸入不同的內(nèi)容,就可以只用一個(gè)函數(shù)初始化兩個(gè)棋盤了。
2.2.2布置雷的功能
void SetMine(char board[ROWS][COLS], int row, int col)
{
int count = EASY_COUNT;
while (count)
{
int x = rand() % row + 1;
int y = rand() % col + 1;
if (board[x][y] == '0')
{
board[x][y] = '1';
count--;
}
}
}
為了實(shí)現(xiàn)雷的隨機(jī)性,我們需要srand隨機(jī)函數(shù):srand((unsigned int)time(NULL));
以及包含的頭文件#include<stdlib.h>及#include<time.h>,來隨機(jī)生成橫縱坐標(biāo)x和y,用來生成雷,也就是‘1’。
2.2.3打印棋盤的功能
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
printf("------掃雷游戲------\n");
//打印列號(hào)
for (int i = 0; i <= col; i++)
{
printf("%d ", i);
}
printf("\n");
//打印行號(hào)
for (int i = 1 ; i <= row; i++)
{
printf("%d ", i);
for (int j = 1; j <= col; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
}
為了更快速的確定坐標(biāo),除了打印9×9的棋盤,我們還需要在棋盤上側(cè)和左側(cè)打印列和行,用for循環(huán)即可實(shí)現(xiàn)。
2.2.4排查雷的功能
'0'是48
'1'是49
'1'-'0'是1
代碼實(shí)現(xiàn)排雷的邏輯是:如果該方格不是雷,則將周圍8個(gè)方格相加減去8×'0',得到的數(shù)字就是周圍雷的個(gè)數(shù),并將它顯示在該方格中。
static int GetMineCount(char mine[ROWS][COLS], int x, int y)
{
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 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("請(qǐng)輸入要排查的坐標(biāo):");
scanf("%d %d", &x, &y);
//判斷坐標(biāo)有效性
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (mine[x][y] == '1')
{
printf("很遺憾,你被炸死了\n");
DisplayBoard(mine, ROW, COL);
break;
}
else
{
//該坐標(biāo)不是雷,就得統(tǒng)計(jì)坐標(biāo)周圍有幾個(gè)雷
int count = GetMineCount(mine, x, y);
show[x][y] = count + '0';
DisplayBoard(show, ROW, COL);
win++;
}
}
else
{
printf("錯(cuò)誤坐標(biāo),請(qǐng)重新輸入\n");
}
}
if (win == row * col - EASY_COUNT)
{
printf("恭喜你排雷成功!\n");
DisplayBoard(mine, ROW, COL);
}
}
在該功能中,我們局部聲明GetMineCount函數(shù),為FindMine排查雷函數(shù)提供顯示一個(gè)方格周圍有幾個(gè)雷的功能。
當(dāng)然,也可以取消GetMineCount函數(shù)的局部聲明,并在game.h中添加聲明,使其全局可用。
到此,一個(gè)簡(jiǎn)單粗略的掃雷游戲就已經(jīng)實(shí)現(xiàn),不過我們還可以提供更多功能來讓游戲變得更有可玩性。
2.3 掃雷游戲的擴(kuò)展
2.3.1 是否可以選擇游戲難度
? 簡(jiǎn)單 9*9 棋盤,10個(gè)雷
? 中等 16*16棋盤,40個(gè)雷
? 困難 30*16棋盤,99個(gè)雷
接著在聲明文件game.h中,使用宏定義,定義棋盤大小和雷的個(gè)數(shù),這樣做可以非常方便的
調(diào)整參數(shù),后期不用調(diào)整很多代碼。
先前我們使用宏定義棋盤大小和雷的個(gè)數(shù),就是為了可以更加方便的自定義游戲難度
以? 中等 16*16棋盤,40個(gè)雷 為例,只需要修改EASY_COUNT,ROW,COL的值,就可以輕松實(shí)現(xiàn)拓展。
#define EASY_COUNT 40//雷
#define ROW 16
#define COL 16
#define ROWS ROW+2
#define COLS COL+2
2.3.2如果排查位置不是雷,周圍也沒有雷,可以展開周圍的一片
在該程序中,如果選定一個(gè)方格,其顯示零,我們需要手動(dòng)選定它周圍8個(gè)方格來獲取更多信息。
為了更加快速方便,我們可以在排查雷功能的判斷該方格是否為雷中加入一些代碼:
{
//該坐標(biāo)不是雷,就得統(tǒng)計(jì)坐標(biāo)周圍有幾個(gè)雷
int count = GetMineCount(mine, x, y);
show[x][y] = count + '0';
if (count == 0)
{
count = GetMineCount(mine, x - 1, y - 1);
show[x - 1][y - 1] = count + '0';
count = GetMineCount(mine, x - 1, y);
show[x - 1][y] = count + '0';
count = GetMineCount(mine, x - 1, y + 1);
show[x - 1][y + 1] = count + '0';
count = GetMineCount(mine, x, y - 1);
show[x][y - 1] = count + '0';
count = GetMineCount(mine, x, y + 1);
show[x][y + 1] = count + '0';
count = GetMineCount(mine, x + 1, y - 1);
show[x + 1][y - 1] = count + '0';
count = GetMineCount(mine, x + 1, y);
show[x + 1][y] = count + '0';
count = GetMineCount(mine, x + 1, y + 1);
show[x + 1][y + 1] = count + '0';
}
DisplayBoard(show, ROW, COL);
win++;
}
這樣就實(shí)現(xiàn)了,如果選定一個(gè)方格顯示0,那么將自動(dòng)打印出它周圍8個(gè)方格。
例如我們選中(4 5),一共會(huì)將9個(gè)方格都顯示出來,更加方便快速。
更多功能,我再研究一下.....
最后附上完整代碼!
3.完整代碼實(shí)現(xiàn)
3.1 test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include"game.h"
void menu()
{
printf("***********************\n");
printf("****** 1.游戲開始 ******\n");
printf("****** 0.退出游戲 ******\n");
printf("***********************\n");
}
void game()
{
//完成掃雷游戲
//mine數(shù)組存放布置好的雷的信息
char mine[ROWS][COLS] = { 0 };
//show數(shù)組存放排查出的雷的信息
char show[ROWS][COLS] = { 0 };
//初始化棋盤
InitBoard(mine, ROWS, COLS, '0');
InitBoard(show, ROWS, COLS, '*');
//布置雷
//在9*9棋盤上隨機(jī)布置10個(gè)雷
SetMine(mine, ROW, COL);
//DisplayBoard(mine, ROW, COL);
//打印棋盤
//DisplayBoard(mine, ROW, COL);
DisplayBoard(show, ROW, COL);
//排查雷
FindMine(mine, show, ROW, COL);
}
void test()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();
printf("請(qǐng)選擇:-->");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("游戲結(jié)束,退出游戲\n");
break;
default:
printf("選擇錯(cuò)誤,重新選擇\n");
break;
}
} while (input);
}
int main()
{
test();
return 0;
}
3.2 game.h
#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define EASY_COUNT 10//雷
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
//初始化棋盤
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);
3.3 game.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
{
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
board[i][j] = set;
}
}
}
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
printf("------掃雷游戲------\n");
//打印列號(hào)
for (int i = 0; i <= col; i++)
{
printf("%d ", i);
}
printf("\n");
//打印行號(hào)
for (int i = 1 ; i <= row; i++)
{
printf("%d ", i);
for (int j = 1; j <= col; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
}
void SetMine(char board[ROWS][COLS], int row, int col)
{
int count = EASY_COUNT;
while (count)
{
int x = rand() % row + 1;
int y = rand() % col + 1;
if (board[x][y] == '0')
{
board[x][y] = '1';
count--;
}
}
}
static int GetMineCount(char mine[ROWS][COLS], int x, int y)
{
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 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("請(qǐng)輸入要排查的坐標(biāo):");
scanf("%d %d", &x, &y);
//判斷坐標(biāo)有效性
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (mine[x][y] == '1')
{
printf("很遺憾,你被炸死了\n");
DisplayBoard(mine, ROW, COL);
break;
}
else
{
//該坐標(biāo)不是雷,就得統(tǒng)計(jì)坐標(biāo)周圍有幾個(gè)雷
int count = GetMineCount(mine, x, y);
show[x][y] = count + '0';
if (count == 0)
{
count = GetMineCount(mine, x - 1, y - 1);
show[x - 1][y - 1] = count + '0';
count = GetMineCount(mine, x - 1, y);
show[x - 1][y] = count + '0';
count = GetMineCount(mine, x - 1, y + 1);
show[x - 1][y + 1] = count + '0';
count = GetMineCount(mine, x, y - 1);
show[x][y - 1] = count + '0';
count = GetMineCount(mine, x, y + 1);
show[x][y + 1] = count + '0';
count = GetMineCount(mine, x + 1, y - 1);
show[x + 1][y - 1] = count + '0';
count = GetMineCount(mine, x + 1, y);
show[x + 1][y] = count + '0';
count = GetMineCount(mine, x + 1, y + 1);
show[x + 1][y + 1] = count + '0';
}
DisplayBoard(show, ROW, COL);
win++;
}
}
else
{
printf("錯(cuò)誤坐標(biāo),請(qǐng)重新輸入\n");
}
}
if (win == row * col - EASY_COUNT)
{
printf("恭喜你排雷成功!\n");
DisplayBoard(mine, ROW, COL);
}
}
以上就是全部?jī)?nèi)容,非常感謝大家的閱讀!給卑微的作者一個(gè)贊吧哈哈哈哈!我會(huì)繼續(xù)努力的!文章來源:http://www.zghlxwxcb.cn/news/detail-807265.html
原創(chuàng)by:高耳機(jī)High-Earphone文章來源地址http://www.zghlxwxcb.cn/news/detail-807265.html
到了這里,關(guān)于【C語(yǔ)言】代碼實(shí)現(xiàn) 掃雷 游戲及進(jìn)階功能(初學(xué)者詳解)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!