c語言實現含遞歸清場版掃雷遊戲

一,設計思路

想必大傢都玩過掃雷

 這便是一個標準的掃雷,換做代碼實現,我們需要考慮以下幾點:

1.棋盤的設計與初始化

2.在棋盤中放入雷

3.統計雷數

4.如何實現“一片”的效果

5.輸贏的判斷

接下來我們進行具體操作。

二.實現方式

1.菜單的打印

對任意一個遊戲,菜單是必不可少的,也是最簡單的部分,直接上代碼

void menu()
{
	printf("------------------掃雷------------------\n");
	printf("---------------1.開始遊戲---------------\n");
	printf("---------------0.退出遊戲---------------\n");
}
int main()
{
	srand((unsigned int)time(NULL));
	int a = 0;
	do
	{
		menu();
		scanf("%d", &a);
		if (a == 0)
		{
			break;
		}
		game();
	} while (a);
	return 0;
}

其中srand是為瞭求隨機值,用來佈置雷

2.game函數

主菜單完後進入game函數,在game函數裡我們就要開始主要的遊戲部分,如棋盤初始化與打印等,當然這些步驟都依靠函數完成,game函數隻相當於集合瞭一系列的遊戲模塊

void game()
{
	char mine[ROWS][COLS];
	char show[ROWS][COLS];
	initeboard(mine, ROWS, COLS, '0');
	initeboard(show, ROWS, COLS, '*');//初始棋盤
	displayboard(show, ROW, COL);//打印棋盤
	mine_make(mine, ROW, COL);//設置雷
	//displayboard(mine, ROW, COL);
	find_mine(mine, show, ROWS, COLS);//排查雷
 
}

3.棋盤的初始化與打印

可以看到,我在game函數裡初始瞭兩個棋盤,為什麼要兩個呢?

其實,一個是為瞭放置瞭雷,一個為瞭展示給玩傢,為什麼不用一個呢,我們要在放雷處用’1′,表示不放雷處用‘0’,這樣計算一個坐標周圍雷的數量就會更簡單,接下來看一段代碼:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ROW 10
#define COL 10
#define ROWS ROW+2
#define COLS COL+2

這裡我們看到定義瞭一個ROWS和COLS這又是為何呢?

回歸棋盤

 掃雷時當你確認一個點時,它會對此點周圍的八個點進行排查看是否有淚,當坐標位於紅線處時沒有無法判斷八個,因此有瞭ROWS與COLS,這時,有人就會問瞭:那埋雷的地方用ROW COL就可以瞭,還不用擔心雷跑到外邊我們加的框,想法很好,但我們有兩個棋盤,必須對應,而且也不存在跑出雷的情況,往下分析你就會知道

void initeboard(char board[ROWS][COLS], int cols, int rows,char s)//棋盤初始化,此處用瞭個節省步驟的方法,不用兩個棋盤依次初始化
{
	int i = 0;
	int j = 0;
	for (i = 0; i < rows; i++)
	{
		for (j = 0; j < cols; j++)
		{
			board[i][j] = s;
		}
	}
}
void displayboard(char board[ROWS][COLS], int row, int col)//棋盤打印
{
	int i = 0;
	int j = 0;
	printf(" ");//與行中打印的0%d對應
	for (j = 0; j <=col; j++)
	{
		printf(" %d  ", j);
	}
	printf("\n");
	printf("-");
	for (j = 1; j <= col + 1; j++)
	{
		printf("---");
		printf("|");
	}
	printf("\n");//列對應打印完成
	for (i = 1; i <= row; i++)
	{
		if (i <= 9)
		{
			printf(" 0%d ", i);
		}
		else
		printf(" %d ", i);
		printf("|");
		for (j = 1; j <= col; j++)
		{
			printf(" %c ", board[i][j]);
			printf("|");
		}
		printf("\n");
		printf("-");
		for (j = 1; j <= col+1; j++)
		{
			printf("---");
			printf("|");
		}
		printf("\n");//行對應嵌套在內部 打印的數前加0是為瞭讓當行數大於9時能夠對應 如09與10
	}
}

棋盤的打印做瞭行列對應,所以可能有點不明顯

 4.雷的放置,雷的個數

雷的放置很簡單,在棋盤‘0’,處放置就行,因為我們對隨機數的算式使隨機數隻會出現在0-9沒有跑出的情況

mine_make(char mine[ROWS][COLS], int row, int col)//設置雷
{
	int count = 10;
	while (count)
	{
		int x = rand() % 10;
		int y = rand() % 10;
		if (mine[x][y] == '0')
		{
			mine[x][y] = '1';
			count--;
		}
	}
}

雷的個數就需要一定考慮瞭:

首先,我們需要把周圍八個位置是否有雷,有多少個雷判斷出來,這時我們設計‘0′ ‘1’類型就排上用場瞭,但是註意,這是字符,不是數字

ASCII碼表

 一張表 讓我們知道如何轉型

當然返回的數字記得轉成字符類型

int get_mine(char mine[ROWS][COLS], int i, int j)//得到一個坐標附近雷的個數
{
	return mine[i - 1][j - 1] + mine[i - 1][j] + mine[i - 1][j + 1] +
		mine[i][j - 1] + mine[i][j + 1] +
		mine[i + 1][j - 1] + mine[i +1 ][j] + mine[i + 1][j + 1] - 8 * '0';//此處我們的數字其實是字符,用此方法可以轉為數字整形
}

5.遞歸實現一片效果

當不為雷是會展開附近一片不為雷,提高遊戲效率

void spread(char show[ROWS][COLS], char mine[ROWS][COLS], int x, int y)//遞歸方法實現一大片
{
	show[x][y] = ' ';//先讓輸入金的坐標處變為空格,因為已經判定過雷所以可以直接轉空格
	int i = 0;
	int j = 0;
	int ret = 0;
	for (i = x - 1; i <= x + 1; i++)
	{
		for (j = y - 1; j <= y + 1; j++)//嵌套for循環表示輸入坐標包括自生及周圍八個
		{
			if (i > 0 && i <= ROW && j > 0 && j <= COL && mine[i][j] != '1' && show[i][j] == '*')//防止出現負坐標,避免有雷,避免輸入重復
			{
				ret = get_mine(mine, i, j);//判斷ret是0或非0,並得出周圍雷數
				if (!ret)//如果ret=0,!ret便是非0;為真
				{
					spread(show, mine, i, j);//遞歸
				}
				if (ret)//ret!=0時為真,便打印數
				{
					show[i][j] = ret + '0';//使數字轉成對應字符
				}
			}
 
		}
	}
}

效果展示:

 6.排查雷

負責判斷是否被炸死及遊戲勝利

void find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)//排查雷
{
	printf("請輸入坐標\n");
	int i = 0;
	int j = 0;
	int win = 0;
	while (row*col-10)//因為是十個雷,所以是—10,因為下總數減10就贏瞭,所以可以以此跳出循環,當然要是雷部位10,定一個變量就行,此處就不改瞭
	{
		scanf("%d %d", &i, &j);
		if (mine[i][j] == '1')
		{
			printf("你掛瞭\n");
			displayboard(mine, ROW, COL);
			break;
		}
		else
		{
			show[i][j] = get_mine(mine, i, j)+'0';
			spread(show,mine, i, j);
			displayboard(show, ROW, COL);
			win++;
		}		
	}
	if (win ==row * col - 10)
	{
		printf("恭喜你,成功瞭\n");
		displayboard(mine, ROW, COL);
	}
}

具體註釋都在代碼裡瞭

正常情況把打印雷盤註釋就行,就可以正常遊戲瞭

 三.完整代碼

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ROW 10
#define COL 10
#define ROWS ROW+2
#define COLS COL+2
void menu()
{
	printf("------------------掃雷------------------\n");
	printf("---------------1.開始遊戲---------------\n");
	printf("---------------0.退出遊戲---------------\n");
}
void initeboard(char board[ROWS][COLS], int cols, int rows,char s)//棋盤初始化,此處用瞭個節省步驟的方法,不用兩個棋盤依次初始化
{
	int i = 0;
	int j = 0;
	for (i = 0; i < rows; i++)
	{
		for (j = 0; j < cols; j++)
		{
			board[i][j] = s;
		}
	}
}
void displayboard(char board[ROWS][COLS], int row, int col)//棋盤打印
{
	int i = 0;
	int j = 0;
	printf(" ");//與行中打印的0%d對應
	for (j = 0; j <=col; j++)
	{
		printf(" %d  ", j);
	}
	printf("\n");
	printf("-");
	for (j = 1; j <= col + 1; j++)
	{
		printf("---");
		printf("|");
	}
	printf("\n");//列對應打印完成
	for (i = 1; i <= row; i++)
	{
		if (i <= 9)
		{
			printf(" 0%d ", i);
		}
		else
		printf(" %d ", i);
		printf("|");
		for (j = 1; j <= col; j++)
		{
			printf(" %c ", board[i][j]);
			printf("|");
		}
		printf("\n");
		printf("-");
		for (j = 1; j <= col+1; j++)
		{
			printf("---");
			printf("|");
		}
		printf("\n");//行對應嵌套在內部 打印的數前加0是為瞭讓當行數大於9時能夠對應 如09與10
	}
}
mine_make(char mine[ROWS][COLS], int row, int col)//設置雷
{
	int count = 10;
	while (count)
	{
		int x = rand() % 10;
		int y = rand() % 10;
		if (mine[x][y] == '0')
		{
			mine[x][y] = '1';
			count--;
		}
	}
}
int get_mine(char mine[ROWS][COLS], int i, int j)//得到一個坐標附近雷的個數
{
	return mine[i - 1][j - 1] + mine[i - 1][j] + mine[i - 1][j + 1] +
		mine[i][j - 1] + mine[i][j + 1] +
		mine[i + 1][j - 1] + mine[i +1 ][j] + mine[i + 1][j + 1] - 8 * '0';//此處我們的數字其實是字符,用此方法可以轉為數字整形
}
void spread(char show[ROWS][COLS], char mine[ROWS][COLS], int x, int y)//遞歸方法實現一大片
{
	show[x][y] = ' ';//先讓輸入金的坐標處變為空格,因為已經判定過雷所以可以直接轉空格
	int i = 0;
	int j = 0;
	int ret = 0;
	for (i = x - 1; i <= x + 1; i++)
	{
		for (j = y - 1; j <= y + 1; j++)//嵌套for循環表示輸入坐標包括自生及周圍八個
		{
			if (i > 0 && i <= ROW && j > 0 && j <= COL && mine[i][j] != '1' && show[i][j] == '*')//防止出現負坐標,避免有雷,避免輸入重復
			{
				ret = get_mine(mine, i, j);//判斷ret是0或非0,並得出周圍雷數
				if (!ret)//如果ret=0,!ret便是非0;為真
				{
					spread(show, mine, i, j);//遞歸
				}
				if (ret)//ret!=0時為真,便打印數
				{
					show[i][j] = ret + '0';//使數字轉成對應字符
				}
			}
 
		}
	}
}
void find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)//排查雷
{
	printf("請輸入坐標\n");
	int i = 0;
	int j = 0;
	int win = 0;
	while (row*col-10)//因為是十個雷,所以是—10,因為下總數減10就贏瞭,所以可以以此跳出循環,當然要是雷部位10,定一個變量就行,此處就不改瞭
	{
		scanf("%d %d", &i, &j);
		if (mine[i][j] == '1')
		{
			printf("你掛瞭\n");
			displayboard(mine, ROW, COL);
			break;
		}
		else
		{
			show[i][j] = get_mine(mine, i, j)+'0';
			spread(show,mine, i, j);
			displayboard(show, ROW, COL);
			win++;
		}		
	}
	if (win ==row * col - 10)
	{
		printf("恭喜你,成功瞭\n");
		displayboard(mine, ROW, COL);
	}
}
void game()
{
	char mine[ROWS][COLS];
	char show[ROWS][COLS];
	initeboard(mine, ROWS, COLS, '0');
	initeboard(show, ROWS, COLS, '*');//初始棋盤
	displayboard(show, ROW, COL);//打印棋盤
	mine_make(mine, ROW, COL);//設置雷
	displayboard(mine, ROW, COL);
	find_mine(mine, show, ROWS, COLS);//排查雷
 
}
int main()
{
	srand((unsigned int)time(NULL));
	int a = 0;
	do
	{
		menu();
		scanf("%d", &a);
		if (a == 0)
		{
			break;
		}
		game();
	} while (a);
	return 0;
}
    

總結

到此這篇關於c語言實現含遞歸清場版掃雷遊戲的文章就介紹到這瞭,更多相關c語言實現掃雷內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: