欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C語(yǔ)言實(shí)現(xiàn)經(jīng)典掃雷小游戲完整代碼(遞歸展開(kāi)?+?選擇標(biāo)記)

 更新時(shí)間:2022年05月11日 14:57:02   作者:野豬佩奇`  
這篇文章主要介紹了C語(yǔ)言小項(xiàng)目之掃雷游戲帶遞歸展開(kāi)?+?選擇標(biāo)記效果,本代碼中,我們用字符?!?來(lái)標(biāo)識(shí)雷,文中附有完整代碼,需要的朋友可以參考下

大家好,今天我們將一起用C語(yǔ)言實(shí)現(xiàn)一個(gè)經(jīng)典小游戲 – 掃雷,Let is go !

游戲介紹

掃雷游戲相信大家都玩過(guò),上圖就是一個(gè)網(wǎng)頁(yè)版的掃雷,它的規(guī)則是玩家選擇一個(gè)方格,若此方格沒(méi)有地雷,那么該方格會(huì)顯示與它相鄰的八個(gè)方格中雷的個(gè)數(shù),若此方格有地雷,那么游戲失敗,當(dāng)玩家把除了有地雷的方格外的其他方格都成功翻開(kāi)時(shí),游戲勝利。

游戲整體框架

對(duì)于一個(gè)代碼量還算可以的小游戲我們還是利用多文件來(lái)進(jìn)行編程,養(yǎng)成良好習(xí)慣,為以后在公司團(tuán)隊(duì)合作編程打下基礎(chǔ),因此我們把掃雷游戲分成三個(gè)文件來(lái)編寫(xiě):

test.c:游戲邏輯的測(cè)試,包含游戲菜單的打印,游戲設(shè)計(jì)的基本邏輯的展示。

game.c:游戲功能的具體實(shí)現(xiàn),這部分是整個(gè)游戲的核心代碼,一般不會(huì)展示給用戶。

game.h:相關(guān)頭文件的包含、符號(hào)的聲明以及函數(shù)的聲明。

游戲具體功能及實(shí)現(xiàn)

1、雷盤(pán)的定義

對(duì)于掃雷游戲,我們遇到的第一個(gè)問(wèn)題就是:應(yīng)該如何表示掃雷的雷盤(pán)及如何存放布雷、排雷的數(shù)據(jù);我們發(fā)現(xiàn),二維數(shù)組可以很好的解決這個(gè)問(wèn)題。

如上圖:我們定義了兩個(gè)棋盤(pán),分別用來(lái)保存布置雷的信息和排查雷的信息,這樣就可以避免二者相互干擾或者相互覆蓋;

同時(shí),我們使用宏來(lái)定義雷盤(pán)的大小以及雷的個(gè)數(shù),這樣做的好處是當(dāng)我們以后想使用更大的雷盤(pán)或者想增加掃雷的難度的時(shí)候,我們只需要改動(dòng)這里一次即可,增加了代碼的可維護(hù)性。

另外,很多小伙伴可能會(huì)疑惑為什么我這里會(huì)定義兩個(gè)不同ROW和COL,這其實(shí)是為后面的排雷做鋪墊:

如圖:當(dāng)我們排查1位置時(shí),如果1處不是雷,那么我們就會(huì)依次檢查1周?chē)?個(gè)坐標(biāo)是否有地雷,如果有,就會(huì)把地雷的數(shù)量顯示在1位置處;但是當(dāng)我們排查2位置時(shí),我們發(fā)現(xiàn), 數(shù)組排查雷時(shí)會(huì)發(fā)生越界,所以為了避免數(shù)組越界,我們就需要增加一系列限制條件,這樣做無(wú)疑是比較麻煩的,所以有的大佬就想出了這樣一種辦法:在定義數(shù)組長(zhǎng)度時(shí)我們直接在上下左右四個(gè)方向各多給一行的空間,并把這些空間中的數(shù)據(jù)初始化為非雷,這樣,就輕松解決了數(shù)組越界的問(wèn)題,不得不說(shuō),這種方法實(shí)在巧妙!

2、雷盤(pán)的初始化

最開(kāi)始的時(shí)候我們把mine數(shù)組元素全部初始化為字符0,把show數(shù)組元素全部初始化為字符*(給用戶一種神秘的感覺(jué))。

3、布置雷

對(duì)于布置雷我們有兩個(gè)需要注意的地方:

第一是用于隨機(jī)生成坐標(biāo)的rand函數(shù)的種子srand函數(shù)只需要在main函數(shù)中聲明一次即可。

第二是我們?cè)诓贾美椎臅r(shí)候需要檢查該位置是否已經(jīng)有雷,避免重復(fù)布置。

4、排查雷

排查雷的時(shí)候我們首先需要讓用戶輸入需要排查的坐標(biāo),然后判斷坐標(biāo)的合法性及該坐標(biāo)是否已被排查,其次再判斷該坐標(biāo)是否有雷,如果沒(méi)有,就遞歸檢查它周?chē)淖鴺?biāo),直到遇到有雷的坐標(biāo)才停止遞歸,再讓用戶選擇是否需要標(biāo)記雷的信息,最后檢查是否滿足游戲勝利的條件。

5、遞歸式展開(kāi)一片

觀察網(wǎng)頁(yè)版的掃雷我們可以發(fā)現(xiàn),當(dāng)用戶點(diǎn)擊一個(gè)坐標(biāo),如果該坐標(biāo)及其周?chē)淖鴺?biāo)都沒(méi)有雷,那么雷盤(pán)就會(huì)一次性展開(kāi)一片,而這樣設(shè)計(jì)也是比較合理的,因?yàn)槿绻恳粋€(gè)非雷坐標(biāo)都需要玩家排查的話十分影響游戲體驗(yàn);所以,這里我們就利用遞歸的實(shí)現(xiàn)模擬實(shí)現(xiàn)了這個(gè)功能。

6、獲取周?chē)椎膫€(gè)數(shù)

7、標(biāo)記特定位置

同樣:在網(wǎng)頁(yè)版的掃雷中,如果我們確定某一位置一定是雷時(shí),我們可以利用標(biāo)記功能來(lái)標(biāo)識(shí)該坐標(biāo),方便我們后面的判斷。

本代碼中,我們用字符 ! 來(lái)標(biāo)識(shí)雷。

8、打印雷盤(pán)

游戲完整代碼 

1、test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void menu()
{
	printf("*****************************************\n");
	printf("*********  1.play      0.exit   *********\n");
	printf("*****************************************\n");
}
void game()
{
	//定義用于存放雷和顯示雷的數(shù)組
	char mine[ROWS][COLS];
	char show[ROWS][COLS];
	//數(shù)組初始化
	BoardInit(mine, ROWS, COLS, '0');
	BoardInit(show, ROWS, COLS, '*');
	//埋雷
	SetMine(mine, ROW, COL);
	system("cls");   //清除菜單,美觀整潔
	//打印雷盤(pán)
	//BoardPrint(mine, ROW, COL);   //用于自己調(diào)試觀察,在發(fā)布時(shí)注釋掉
	BoardPrint(show, ROW, COL);
	//排雷
	FindMine(mine, show, ROW, COL);
}
int main()
{
	//設(shè)置隨機(jī)數(shù)的種子
	srand((unsigned int)time(NULL));
	int input = 0;
	do
	{
		menu();//菜單
		printf("請(qǐng)選擇:");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戲!\n");
			break;
		default:
			printf("輸入錯(cuò)誤,請(qǐng)重新輸入!\n");
			break;
		}
	} while (input);
	return 0;
}

2、game.h

#pragma once
#include<stdio.h>
#include<windows.h>
#include<time.h>
#include<stdlib.h>
#define ROW 9
#define COL 9
#define ROWS ROW + 2
#define COLS COL + 2
#define MINE_COUNT 10
//數(shù)組初始化
void BoardInit(char board[ROWS][COLS], int rows, int cols, char set);
//埋雷
void SetMine(char board[ROWS][COLS], int row, int col);
//排雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
//打印雷盤(pán)
void BoardPrint(char board[ROWS][COLS], int row, int col);

3、game.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
//數(shù)組初始化
void BoardInit(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;   //set表示要初識(shí)化的字符
		}
	}
}
//埋雷
void SetMine(char board[ROWS][COLS], int row, int col)
{
	int count = MINE_COUNT;
	while (count)
	{
		int x = rand() % row + 1;      //隨機(jī)生成雷的坐標(biāo)
		int y = rand() % col + 1;
		if (board[x][y] == '0')        //檢查該位置是否已經(jīng)有雷
		{
			board[x][y] = '1';
			count--;
		}
	}
}
//打印雷盤(pán)
void BoardPrint(char board[ROWS][COLS], int row, int col)
{
	int i = 0;
	int j = 0;
	printf("------掃雷游戲------\n");
	for (i = 0; i <= row; i++)   //打印行號(hào)
		printf("%d ", i);
	printf("\n");
	for (i = 1; i <= row; i++)
	{
		printf("%d ", i);   //打印列號(hào)
		for (j = 1; j <= col; j++)
		{
			printf("%c ", board[i][j]);
		}
		printf("\n");
	}
	printf("------掃雷游戲------\n");
}
//標(biāo)記雷的位置
void MarkMine(char board[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	while (1)
	{
		printf("請(qǐng)輸入你想要標(biāo)記位置的坐標(biāo)->");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)    //判斷該坐標(biāo)是否合法
		{
			if (board[x][y] == '*')        //判斷該坐標(biāo)是否被排查
			{
				board[x][y] = '!';
				break;
			}
			else
			{
				printf("該位置不能被標(biāo)記,請(qǐng)重新輸入!\n");
			}
		}
		else
		{
			printf("輸入錯(cuò)誤,請(qǐng)重新輸入!\n");
		}
	}
}
//獲取坐標(biāo)周?chē)椎膫€(gè)數(shù)
int GetMineCount(char board[ROWS][COLS], int x, int y)
{
	int i = 0;
	int j = 0;
	int count = 0;
	for (i = x - 1; i <= x + 1; i++)
	{
		for (j = y - 1; j <= y + 1; j++)
		{
			if (board[i][j] == '1')
			{
				count++;
			}
		}
	}
	return count;
}
//遞歸爆炸式展開(kāi)一片
void ExplosionSpread(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int x, int y, int* pw)
{
	if (x >= 1 && x <= row && y >= 1 && y <= col)  //判斷坐標(biāo)是否為排查范圍內(nèi)
	{
		int num = GetMineCount(mine, x, y);   //獲取坐標(biāo)周?chē)椎膫€(gè)數(shù)
		if (num == 0)
		{
			(*pw)++;
			show[x][y] = ' ';   //如果該坐標(biāo)周?chē)鷽](méi)有雷,就把該坐標(biāo)置成空格,并向周?chē)藗€(gè)坐標(biāo)展開(kāi)
			int i = 0;
			int j = 0;
			for (i = x - 1; i <= x + 1; i++)
			{
				for (j = y - 1; j <= y + 1; j++)
				{
					if (show[i][j] == '*')    //限制遞歸條件,防止已經(jīng)排查過(guò)的坐標(biāo)再次遞歸,從而造成死遞歸
						ExplosionSpread(mine, show, row, col, i, j, pw);
				}
			}
		}
		else
		{
			(*pw)++;
			show[x][y] = num + '0';
		}
	}
}
//排雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int win = 0;  //用來(lái)標(biāo)記是否取得勝利
	int* pw = &win;
	char ch = 0;   //用來(lái)接受是否需要標(biāo)記雷
	while (win < row * col - MINE_COUNT)
	{
		printf("請(qǐng)輸入你想要排查的坐標(biāo)->");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)   //判斷坐標(biāo)合法性
		{
			if (mine[x][y] == '1')
			{
				system("cls");
				printf("很遺憾,你被炸死了!\n");
				BoardPrint(mine, row, col);   //被炸死了就打印mine數(shù)組,讓用戶知道自己怎么死的
				break;
			}
			else
			{
				if (show[x][y] != '*')   //判斷是否重復(fù)排查
				{
					printf("該坐標(biāo)已被排查,請(qǐng)重新輸入!\n");
					continue;  //直接進(jìn)入下一次循環(huán)
				}
				else
				{
					ExplosionSpread(mine, show, row, col, x, y, pw);  //爆炸展開(kāi)一片
					system("cls");  //清空屏幕
					BoardPrint(show, row, col);  //打印棋盤(pán)
					printf("需要標(biāo)記雷的位置請(qǐng)輸入y/Y,否則請(qǐng)按任意鍵->");
					while ((ch = getchar()) != '\n');  //清理緩沖區(qū)
					scanf("%c", &ch);
					if (ch == 'Y' || ch == 'y')
					{
						MarkMine(show, row, col);   //標(biāo)記雷
						system("cls");
						BoardPrint(show, row, col);
					}
					else
					{
						continue;
					}
				}
			}
		}
		else
		{
			printf("輸入錯(cuò)誤,請(qǐng)重新輸入!\n");
		}
	}
	if (win == row * col - MINE_COUNT)
	{
		system("cls");
		printf("恭喜你,排雷成功!\n");
		BoardPrint(show, row, col);
		return;
	}
}

游戲效果展示

到此這篇關(guān)于C語(yǔ)言小項(xiàng)目之掃雷游戲完整代碼(遞歸展開(kāi) + 選擇標(biāo)記)的文章就介紹到這了,更多相關(guān)C語(yǔ)言掃雷游戲內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論