日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學(xué)無(wú)先后,達(dá)者為師

網(wǎng)站首頁(yè) 編程語(yǔ)言 正文

基于C語(yǔ)言掃雷游戲的設(shè)計(jì)與實(shí)現(xiàn)_C 語(yǔ)言

作者:Code_Cao ? 更新時(shí)間: 2021-12-02 編程語(yǔ)言

1 引言

伴隨著信息技術(shù)的快速發(fā)展,近年來(lái),人們的生活已經(jīng)離不開(kāi)計(jì)算機(jī)。生活?yuàn)蕵?lè)幾乎都是在計(jì)算機(jī)上進(jìn)行的。其中的掃雷游戲就是之一。掃雷游戲是微軟公司在1992年在windows系統(tǒng)上發(fā)布的一款益智類小游戲,直到今天這款小游戲依然存在,可見(jiàn)此款游戲的成功。本文將用Visual Studio 2019作為開(kāi)發(fā)工具來(lái)模擬實(shí)現(xiàn)掃雷游戲。經(jīng)過(guò)大一第一學(xué)期的學(xué)習(xí),我們對(duì)C語(yǔ)言的理論及其相關(guān)知識(shí)有了一定的認(rèn)識(shí)和了解。本文可以把我們所學(xué)的理論知識(shí)和實(shí)踐動(dòng)手能力相結(jié)合,另外也可以對(duì)我所學(xué)過(guò)的知識(shí)進(jìn)行復(fù)習(xí)鞏固。通過(guò)探索windows的掃雷小游戲,我們可以巧妙地和這學(xué)期學(xué)過(guò)的C語(yǔ)言相結(jié)合起來(lái)模擬實(shí)現(xiàn)無(wú)界面化簡(jiǎn)易版的掃雷小游戲。

2 相關(guān)工作

準(zhǔn)備Visual Studio 2019開(kāi)發(fā)工具,了解數(shù)據(jù)類型,會(huì)使用選擇語(yǔ)句、循環(huán)語(yǔ)句、函數(shù)、數(shù)組等內(nèi)容。

了解ASCII碼值、隨機(jī)數(shù)的生成。了解二維坐標(biāo)相關(guān)的數(shù)學(xué)知識(shí)。

3 本文方法

3.1玩家游戲思路

進(jìn)入菜單,進(jìn)行選擇是否進(jìn)入,或退出游戲。
進(jìn)入游戲模塊,輸入坐標(biāo)進(jìn)行掃雷。掃到雷,結(jié)束游戲,沒(méi)掃到雷,進(jìn)行標(biāo)記該位置周圍相鄰八個(gè)位置有多少個(gè)雷,直到玩家失敗或者贏掉此游戲。

3.2游戲構(gòu)思細(xì)節(jié)
由于本游戲玩家看到的界面是由9* 9大小的方格構(gòu)成并用字符* 對(duì)B雷盤進(jìn)行覆蓋的畫面,但當(dāng)我們計(jì)算一個(gè)非雷的位置周圍八個(gè)相鄰位置是否有雷時(shí),這樣就會(huì)導(dǎo)致數(shù)組越界,為了防止越界,我們將雷盤設(shè)置為11乘11。因?yàn)槭亲址? 覆蓋,所以對(duì)B雷盤創(chuàng)建用的是字符類型的二維數(shù)組,同時(shí)為了方便實(shí)現(xiàn)一次聲明,兩次調(diào)用等操作。我們把a(bǔ)雷盤也用字符類型的二維數(shù)組進(jìn)行創(chuàng)建。

3.3 游戲設(shè)計(jì)實(shí)現(xiàn)

3.3.1 游戲分三個(gè)模塊,test.c,game.c和game.h。
(1)以模塊化的函數(shù)思想進(jìn)行設(shè)計(jì),使游戲整體思路更加清晰。首先打開(kāi)Visual Studio 2019,創(chuàng)建掃雷游戲的空項(xiàng)目,創(chuàng)建test.c源文件,和game.c源文件,一個(gè)game.h頭文件。c語(yǔ)言中頭文件中一般定義了函數(shù)的聲明、結(jié)構(gòu)體的定義、宏定義。(常量和全局變量最好放到源文件中)。C語(yǔ)言源文件中我們放置一些函數(shù)。來(lái)將游戲的具體實(shí)現(xiàn)。 源文件(test.c)里面放主函數(shù)和游戲的整體功能。
3.3.2 在頭文件中進(jìn)行準(zhǔn)備工作
(1)#define進(jìn)行宏定義,進(jìn)行 InitMine,SetMine,DisplayMine,F(xiàn)indMine等函數(shù)的聲明。

//宏定義便于后期的更改
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define ROWS ROW + 2
//設(shè)置11*11的格子防止數(shù)組越界。
#define COLS COL + 2
#define ROW 9
#define COL 9
//以下是對(duì)函數(shù)的聲明
void InitMine(char mine[ROWS][COLS], int row, int col, char set);
void SetMine(char mine[ROWS][COLS], int row, int col);
void DisplayMine(char show[ROWS][COLS], int row, int col);
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
//設(shè)置雷的個(gè)數(shù)
#define minecount 10

3.3.3 test.c中游戲大致功能的實(shí)現(xiàn)
(1)生成菜單欄
對(duì)于玩家來(lái)說(shuō),游戲的開(kāi)始之前需要一個(gè)菜單欄進(jìn)行選擇游戲的開(kāi)始或者退出,這時(shí)候就要用do語(yǔ)句生成菜單欄,并在其中使用switch語(yǔ)句進(jìn)行選擇進(jìn)入或退出游戲。

test()
{
	//用rand()函數(shù)之前需要先用srand函數(shù)。
	srand((unsigned int)time(NULL));
	int n = 0;
	//游戲進(jìn)去之后需要先有個(gè)菜單所以用上do語(yǔ)句
	do
	{
		//打印菜單
		menu();
		scanf("%d", &n);
		switch (n)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戲\n");
			break;
		default:
			printf("請(qǐng)重新選擇\n");
			break;
		}
	} while (n);
}
//程序的入口
int main()
{
	test();
	return 0;
}

(2)調(diào)用game函數(shù)
我們將A盤有mine數(shù)組表示,B盤用show數(shù)組表示。
在switch中調(diào)用game函數(shù)進(jìn)行char mine[ROWS][COLS] = { 0 };char show[ROWS][COLS] = { 0 };等數(shù)組的創(chuàng)建。用InitMine(mine, ROWS, COLS, ‘0');InitMine(show, ROWS, COLS, ' * );進(jìn)行雷盤的初始化。我們?cè)O(shè)置雷為字符1,非雷為字符0。首先,把A盤初始化為非0,即全都不是雷,把B盤初始化為*號(hào)。接著用SetMine(mine, ROW, COL);DisplayMine(show, ROW, COL)運(yùn)用隨機(jī)數(shù)生成函數(shù),向A盤隨機(jī)布置雷;//用B盤進(jìn)行展示雷的信息和結(jié)果,接著用FindMine(mine, show, ROW, COL);進(jìn)行排雷

game()
{
	system("cls");//對(duì)畫面進(jìn)行清屏,使頁(yè)面簡(jiǎn)潔。
	char mine[ROWS][COLS] = { 0 };//創(chuàng)建11*11數(shù)組
	char show[ROWS][COLS] = { 0 };
	//第一次傳mine數(shù)組名
	InitMine(mine, ROWS, COLS, '0');
	//第二次傳show數(shù)組名
	InitMine(show, ROWS, COLS, '*');
	//在A雷盤布置雷,所以需要傳mine數(shù)組名
	SetMine(mine, ROW, COL);
	//用B盤進(jìn)行展示雷的信息和結(jié)果
	DisplayMine(show, ROW, COL);
	//進(jìn)行排雷
	FindMine(mine, show, ROW, COL);
}

3.3.4game.c中功能具體實(shí)現(xiàn)
(1)InitMine運(yùn)用雙重for循環(huán),初始化棋盤。
(2)SetMine運(yùn)用隨機(jī)數(shù)的生成,rand函數(shù)()函數(shù),布置雷。
(3)DisplayMine用雙重for循環(huán)遍歷,展示棋盤
(4)FindMine用while循環(huán)和if的嵌套,期間關(guān)鍵在于調(diào)用SpreadMine函數(shù)進(jìn)行遞歸,再調(diào)用is_win函數(shù)進(jìn)行判斷輸贏。

關(guān)鍵部分代碼(遞歸)

void SpreadMine(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
	//調(diào)用CountMine函數(shù)進(jìn)行查找周圍八個(gè)位置雷的個(gè)數(shù)。
	int count = CountMine(mine, x, y);
	if (0 == count)
	{
		show[x][y] = ' ';
		if (show[x][y + 1] == '*')
			SpreadMine(mine, show, x, y + 1);
		if (show[x][y - 1] == '*')
			SpreadMine(mine, show, x, y - 1);
		if (show[x + 1][y] == '*')
			SpreadMine(mine, show, x + 1, y);
		if (show[x + 1][y - 1] == '*')
			SpreadMine(mine, show, x + 1, y - 1);
		if (show[x + 1][y + 1] == '*')
			SpreadMine(mine, show, x + 1, y + 1);
		if (show[x - 1][y] == '*')
			SpreadMine(mine, show, x - 1, y);
		if (show[x - 1][y + 1] == '*')
			SpreadMine(mine, show, x - 1, y + 1);
		if (show[x - 1][y - 1] == '*')
			SpreadMine(mine, show, x - 1, y - 1);
	}
	else
	{
		//如果該位置是雷,則將雷的個(gè)數(shù)顯示在此位置
		show[x][y] = count + '0';
		//由于‘0'的的ASCII碼值為48,‘1'的ASCII碼值是49.
		// 所以
		//1 + '0' = '1'
		//2 + '0' = '2'
	}
}

4 結(jié)果與分析

本文實(shí)現(xiàn)了掃雷游戲的基本功能,根據(jù)提示,輸入坐標(biāo)從而實(shí)現(xiàn)掃雷。如果踩到雷就會(huì)退出游戲。如果剩下的*號(hào)等于雷數(shù),則贏得游戲。如果輸入坐標(biāo)不對(duì),則重新輸入。最后通過(guò)遞歸實(shí)現(xiàn)了掃雷一片展開(kāi)的功能。待有提高的是實(shí)現(xiàn)圖形界面化和用鼠標(biāo)操作界面可以學(xué)習(xí)EasyX來(lái)進(jìn)一步優(yōu)化。

5 總結(jié)

通過(guò)對(duì)此掃雷游戲的設(shè)計(jì)和實(shí)現(xiàn),我們回顧了C語(yǔ)言的大半部分知識(shí)并對(duì)其中的細(xì)節(jié)進(jìn)行了剖析。學(xué)習(xí)了C語(yǔ)言編程風(fēng)格,了解了一些較常用的知識(shí)。我們對(duì)二維數(shù)組的應(yīng)用,函數(shù)的聲明,定義,和調(diào)用,以及if,switch選擇語(yǔ)句和for,do,while循環(huán)語(yǔ)句有了更深刻的理解,提升了我們的邏輯思維能力。同時(shí)對(duì)ASCII碼,隨機(jī)數(shù)生成的應(yīng)用也有了一些了解。另外,也提升了我們的模塊化思維能力,比如我們用三個(gè)模塊來(lái)構(gòu)建此游戲。并且游戲中每個(gè)功能的實(shí)現(xiàn)都是由函數(shù)模塊構(gòu)成的。

GitHub源碼鏈接:

https://github.com/CaoCoder/C_code

整體代碼

頭文件

//宏定義便于后期的更改
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define ROWS ROW + 2
//設(shè)置11*11的格子防止數(shù)組越界。
#define COLS COL + 2
#define ROW 9
#define COL 9
//以下是對(duì)函數(shù)的聲明
void InitMine(char mine[ROWS][COLS], int row, int col, char set);
void SetMine(char mine[ROWS][COLS], int row, int col);
void DisplayMine(char show[ROWS][COLS], int row, int col);
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
//設(shè)置雷的個(gè)數(shù)
#define minecount 10

源文件

#define _CRT_SECURE_NO_WARNINGS
#include "12_9game.h"http://引用自己創(chuàng)建的頭文件用雙引號(hào)
//對(duì)9*9雷區(qū)遍歷查*的數(shù)量和minecount進(jìn)行比較。
int is_win(char show[ROWS][COLS], int row, int col)
{
	int i = 0;
	int j = 0;
	int c = 0;
	for (i = 1; i <= row; i++)
	{
		for (j = 1; j <= col; j++)
		{
			if ('*' == show[i][j])
			{
				c++;
			}
		}
	}
	return c;
}
//用遞歸,進(jìn)行實(shí)現(xiàn)一片展開(kāi)的功能
void SpreadMine(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
	//調(diào)用CountMine函數(shù)進(jìn)行查找周圍八個(gè)位置雷的個(gè)數(shù)。
	int count = CountMine(mine, x, y);
	if (0 == count)
	{
		show[x][y] = ' ';
		if (show[x][y + 1] == '*')
			SpreadMine(mine, show, x, y + 1);
		if (show[x][y - 1] == '*')
			SpreadMine(mine, show, x, y - 1);
		if (show[x + 1][y] == '*')
			SpreadMine(mine, show, x + 1, y);
		if (show[x + 1][y - 1] == '*')
			SpreadMine(mine, show, x + 1, y - 1);
		if (show[x + 1][y + 1] == '*')
			SpreadMine(mine, show, x + 1, y + 1);
		if (show[x - 1][y] == '*')
			SpreadMine(mine, show, x - 1, y);
		if (show[x - 1][y + 1] == '*')
			SpreadMine(mine, show, x - 1, y + 1);
		if (show[x - 1][y - 1] == '*')
			SpreadMine(mine, show, x - 1, y - 1);
	}
	else
	{
		//如果該位置是雷,則將雷的個(gè)數(shù)顯示在此位置
		show[x][y] = count + '0';
		//由于‘0'的的ASCII碼值為48,‘1'的ASCII碼值是49.
		// 所以
		//1 + '0' = '1'
		//2 + '0' = '2'
	}
}
//查找非雷位置周圍八個(gè)位置有多少雷
int CountMine(char mine[ROWS][COLS], int x, int y)
{
	return  (mine[x - 1][y + 1] + mine[x][y + 1]
		+ mine[x + 1][y + 1] + mine[x - 1][y]
		+ mine[x + 1][y] + mine[x - 1][y - 1]
		+ mine[x][y - 1] + 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 c = row * col - minecount;

	while (1)
	{
		printf("請(qǐng)輸入坐標(biāo)(x,y):");
		scanf("%d%d", &x, &y);
		//將輸入的坐標(biāo)限制在9*9的雷區(qū)
		if (x <= row && x >= 1 && y <= col && y >= 1)
		{
			if (mine[x][y] == '0')
			{
				SpreadMine(mine, show, x, y);
				system("cls");
				DisplayMine(show, ROW, COL);
				if (is_win(show, ROW, COL) == minecount)
				{
					printf("恭喜你贏了!\n");
					DisplayMine(mine, ROW, COL);
					break;
				}
			}
			else
			{
				printf("很遺憾你被炸死了~\n");
				DisplayMine(mine, ROW, COL);
				break;
			}
		}
		else
		{
			printf("輸入坐標(biāo)越界,請(qǐng)重新輸入:");
		}
	}
}
//初始化棋盤,一個(gè)函數(shù),兩次調(diào)用。
void InitMine(char mine[ROWS][COLS], int row, int col, char set)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			mine[i][j] = set;
		}
	}
}
//布置雷
void SetMine(char mine[ROWS][COLS], int row, int col)
{

	int c = 0;
	while (c != minecount)
	{
		int x = rand() % row + 1;
		//用rand()函數(shù)對(duì)9求余得到0~9這十個(gè)數(shù),再加一就得到1~10.
		int y = rand() % col + 1;
		if (mine[x][y] == '0')
		{
			//如果此位置為‘0',即非雷
			//則設(shè)置為‘1',即雷
			mine[x][y] = '1';
			c++;
		}
	}
}
//運(yùn)用雙重循環(huán)打印9*9的B雷區(qū)
void DisplayMine(char show[ROWS][COLS], int row, int col)
{
	int i = 0;
	int j = 0;
	for (i = 0; i <= row; i++)
	{
		printf("%d ", i);
		for (j = 1; j <= col; j++)
		{
			if (0 == i)
			{
				printf("%d ", j);
			}
			else
			{
				printf("%c ", show[i][j]);
			}
		}
		printf("\n");
	}
}

源文件

#define _CRT_SECURE_NO_WARNINGS
#include "12_9game.h"
game()
{
	system("cls");//對(duì)畫面進(jìn)行清屏,使頁(yè)面簡(jiǎn)潔。
	char mine[ROWS][COLS] = { 0 };//創(chuàng)建11*11數(shù)組
	char show[ROWS][COLS] = { 0 };
	//第一次傳mine數(shù)組名
	InitMine(mine, ROWS, COLS, '0');
	//第二次傳show數(shù)組名
	InitMine(show, ROWS, COLS, '*');
	//在A雷盤布置雷,所以需要傳mine數(shù)組名
	SetMine(mine, ROW, COL);
	//用B盤進(jìn)行展示雷的信息和結(jié)果
	DisplayMine(show, ROW, COL);
	//進(jìn)行排雷
	FindMine(mine, show, ROW, COL);
}
menu()
{
	printf("┏━━━━━━┓━━━━━━━━━━━━━━━━━━━━┓━━━━━━━━━━━┓\n");
	printf("┣━━━━━━┫━━━━━━1.PLAY━━━━━━━━┫━━━━━━━━━━━┫\n");
	printf("┣━━━━━━┫━━━━━━1.EXIT━━━━━━━━┫━━━━━━━━━━━┫\n");
	printf("┗━━━━━━┛━━━━━━━━━━━━━━━━━━━━┛━━━━━━━━━━━┛\n");
}
test()
{
	//用rand()函數(shù)之前需要先用srand函數(shù)。
	srand((unsigned int)time(NULL));
	int n = 0;
	//游戲進(jìn)去之后需要先有個(gè)菜單所以用上do語(yǔ)句
	do
	{
		//打印菜單
		menu();
		scanf("%d", &n);
		switch (n)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戲\n");
			break;
		default:
			printf("請(qǐng)重新選擇\n");
			break;
		}
	} while (n);
}
//程序的入口
int main()
{
	test();
	return 0;
}

原文鏈接:https://blog.csdn.net/qq2466200050/article/details/121803433

欄目分類
最近更新