C语言“扫雷”(可以展开)

✍前言:

大家在学习C语言的时候是不是有时候会感觉很枯燥,觉得自己学的知识不能整合运用起来,那今天我给大家带来了一个特别适合小白新手的小游戏,这个小游戏也算是整合了一些简单的,分支循环,函数,数组等一些基础的知识,如果你是刚刚接触C语言,那么这个扫雷小游戏教程非常适合你哦 ! ! !

✈首先,在写游戏前,我们首先要了解一下扫雷游戏:

☀☀☀   扫雷的玩法:在一个9×9(初级)的方块矩阵中随机布置一定量的地雷(初级为10个),再由玩家逐个翻开方块,以找出所有地雷为最终游戏目标。如果玩家翻开的方块有地雷,则游戏结束,如果找到了躲避开所有地雷,那么游戏获胜。

注意:扫雷虽然是一个代码量不大的小游戏,但我们任然要保持好的习惯进行模块化分文件编程:

           test.c   (游戏测试文件)

           game.c  (代码定义文件)

           game.h  (函数声明文件)

 

 我们可以看到扫雷的格子区域是一个 9*9 的矩阵,那么,我们也要同样去实现一个

 实现的逻辑:

 1.我们用键盘输出扫雷的坐标:

   a.如果扫到了雷,那么游戏结束

   b.如果没扫到雷,且围绕扫雷坐标旁边的8个坐标有雷,那么在此左边显示周边的雷的个数

  c.如果没扫到雷,且围绕扫雷坐标旁边的8个坐标都没有雷,那么他将会展开.

 怎么实现:

 我们将会用两个 11*11 的两个二维数组(分为隐形棋盘和显形棋盘),在隐形棋盘上埋雷,寻找雷。再反馈给玩家看的显形棋盘,同时因为两个棋盘的大小和坐标是完全重叠的,所以通过两个棋盘的联动,就可以完成这个简单的小游戏了。

可能有人会问了,我们不是要做一个9*9的棋盘吗,为什么要去创建两个11*11的棋盘呢?看下图 

11*11棋盘中x,y计算周边雷数(红色区域)的时候不用判定边界,黑色区域是我们创建初始化的,但是我们不会去操作黑色区域,蓝色区域是我们操作区域,打印,埋雷,找雷都在蓝色区域找

我现在创建了一个11*11 的棋盘,在后面我们因为要实现输入坐标后计算周边的雷数,如果我们创建一个9*9的棋盘,那么我们就需要去判断一下边界,并且玩家在输入坐标的时候,通常为把第一行第一列的坐标认为1,1。但是我们程序员知道如果创建9*9的棋盘后,第一个坐标是0.0,所以我们要创建大一圈的棋盘。当然了,创建大棋盘我们也需要处理一些具体的细节,※※※比如我们打印棋盘的时候,要注意从下标为1的元素开始打印,到下标为9的时候结束。埋雷找雷的时候都要从1-9中去找。

注意:不能去0和10埋雷找雷,我们把它认定为非法。 

实现代码:

我们一般再写小游戏的时候,通常都会使用do while 语句 ,他会提前循环一次再让我们进行判断。

int main()
{
	srand((size_t)time(NULL));
	int input = 0;
	do
	{
		meun();
		printf("请选择:");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("选择错误请重新选择\n");
			break;
		}
	} while (input);
	return 0;
}

 再进行游戏前,我们肯定需要一个菜单栏并给玩家们提供选项,选择1进入游戏,选择0退出游戏并且结束循环,选择其他的任意数字,会重新进行选择

void meun()
{
	printf("******************************\n");
	printf("************ 扫雷 ************\n");
	printf("*****   1.play  0.exit   *****\n");
	printf("******************************\n");
}

 那让我们继续往下走,当我们选择了1的时候就会执行game()函数,如果选择0,就会退出,其他重新循环,看下图

 

 

 我们可以可以看到,当我们选择1的时候走回走case 1这个通道,去执行game函数,在game函数中我们将写游戏的主体部分

void game()
{
	char concealboard[ROWS][COLS] = { 0 };//隐藏的棋盘
	char showboard[ROWS][COLS] = { 0 };//展示的棋盘

	Initboard(concealboard, ROWS, COLS,'0');//初始化隐藏的棋盘,全部初始化为字符0
	Initboard(showboard, ROWS, COLS,'*');//初始化显示的棋盘,全部初始化为字符*

	
	Displayboard(showboard, ROW, COL);//打印给玩家看的棋盘

	Setboard(concealboard, ROW, COL);//为隐藏的棋盘中设置雷
	

	Findbomb(concealboard, showboard, ROW, COL);//在隐藏的棋盘中寻找雷,再通过联动显示的棋盘打印出来
	
}

 再写游戏主体前我们先过一遍思路:

1.首先我们需要两个11*11的棋盘

2.初始化两个棋盘

3.打印出给玩家展示的棋盘

4.操作隐藏的棋盘,在隐藏的棋盘随机设置10个雷

5.在隐藏棋盘寻找雷: 
                               a.输入坐标在隐藏的棋盘中找雷,踩到雷,游戏结束

                               b.没踩到雷,那么将计算周边8个坐标的雷的个数,并在显示棋盘中显                                    示周边雷个数

                               c.没踩到雷,并且周边也没有雷,那么显示的棋盘将会以输出坐标为中                                    心展开

1.两个11*11棋盘

char concealboard[ROWS][COLS] = { 0 };//隐藏的棋盘
	char showboard[ROWS][COLS] = { 0 };//展示的棋盘

2.初始化函数

void Initboard(char board[ROWS][COLS], int rows, int cols, char ch)
{
	for (int i = 0; i < rows; i++)
	{
		for (int j = 0; j < cols; j++)
		{
			board[i][j] = ch;
		}
	}
}

3.打印函数

void Displayboard(char board[ROWS][COLS], int row, int col)
{
	printf("-------------------\n");
	for (int i = 0; i <= row; i++)
	{
		printf("%d ",i);
	}
	printf("\n");
	for (int i = 1; i <= row; i++)
	{
		printf("%d ", i);
		for (int j = 1; j <= col; j++)
		{
			printf("%c ", board[i][j]);
		}
		printf("\n");
	}
	printf("-------------------\n");
}

4.埋雷函数

void Setboard(char board[ROWS][COLS], int row, int col)//布置雷
{
	int x = 0;
	int y = 0;
	int count = BOMB;
	while (count)
	{
		x = rand() % row + 1;
		y = rand() % col + 1;
		if (board[x][y] == '0')
		{
			board[x][y] = '1';
			count--;
		}
	}
}

※※※5.找雷的函数 

 我们可以看到找雷函数中又包括了几个功能函数,我解释一下:

1.如果踩到了雷,执行打印函数,给玩家打印出隐藏雷的棋盘示意玩家

2.如果不是雷执行展开函数(展开函数中同时会执行计算雷个数的函数)

3.判断胜利的函数,因为我们游戏有自动展开功能,所以判断胜利我们只需要计算 * 号的个数就可以,如果是10个 * 号 ,就判断赢

void Findbomb(char concealboard[ROWS][COLS], char showboard[ROWS][COLS], int row, int col)//找雷
{
	
	int x = 0;
	int y = 0;
	
	
	while (1)
	{
		
		printf("请输入要找的坐标:");
		scanf("%d%d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col && showboard[x][y] =='*')
		{
			if (concealboard[x][y] == '1')//如果是雷结束游戏
			{
				printf("很遗憾,您被炸死了!\n");
				Displayboard(concealboard, row, col);
				break;
			}
			else//如果不是,就计算一下周边雷的个数,和进行展开
			{
				open(concealboard, showboard, x, y);
				system("cls");
				Displayboard(showboard, row, col);
				if (Win(showboard, row, col))//
				{
					break;
				}
			}
		}
		else
		{
			printf("坐标不合法,请重新输入:\n");
		}
	}
	if (Win(showboard, row, col))
	{
		printf("恭喜你,成功排雷\n");
	}
}
		return;
	}
}

下面的是展开函数,首先计算周边雷的个数,如果周边有雷,那么就在显示棋盘显示雷的个数,如果周边没有雷,并且不是空格符,那么就将此此坐标制成空格符号,并向周边递归展开

int get_count(char concealboard[ROWS][COLS],int x,int y)//计算周边8个坐标的雷数
{
	return (concealboard[x - 1][y - 1] + concealboard[x - 1][y] +
		concealboard[x - 1][y + 1] + concealboard[x][y - 1] +
		concealboard[x][y + 1] + concealboard[x + 1][y - 1] +
		concealboard[x + 1][y] + concealboard[x + 1][y + 1]) - 8 * '0';
}
void open(char concealboard[ROWS][COLS], char showboard[ROWS][COLS], int x, int y)//排雷展开
{
	int count = 0;
	count=get_count(concealboard, x, y);
	if (count != 0)//不是雷,且周边有雷
	{
		showboard[x][y] = count + '0';
		
		return;
	}
	else if(showboard[x][y] != ' ')//不是雷,并且周边没雷
	{
		showboard[x][y] = ' ';//把当前坐标制成空格符号,以防止死递归
		
		for (int i = x-1; i <= x+1; i++)
		{
			for (int j =y-1;j<=y+1;j++)
			{
				open(concealboard, showboard, i, j);//对周边8个坐标展开
			}
		}
	}
	else
	{
		return;
	}
}

 判断胜利的函数,很多人都会计算没踩雷的次数,当次数是row*col-bomb=71的时候获胜,如果是没有展开函数,那么就是正确的。但是如果实现了展开的功能,就不可以这样写,我自己也实际测试过,这样是无法停止的。

所以我认为可以计算显示棋盘的 * 号的数量 ,当* 号的数量正好是雷的个数,那么就获胜

bool Win(char showboard[ROWS][COLS], int row, int col)
{
	int count = 0;
	for (int i = 1; i <=row; i++)
	{
		for (int j = 1; j <=row; j++)
		{
			if (showboard[i][j] == '*')
			{
				count++;//计算*号数量
			}
		}
	}
	return count == BOMB;//如果*号为10个,说明找到了10个雷,获胜
}

✌✌✌游戏测试截图 

 

 上面模块化的功能我们已经实现,下面让我们看一下完整的代码

game.h

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include <stdbool.h>
#include <Windows.h>
#define ROW 9
#define COL 9

#define ROWS ROW+2
#define COLS COL+2

#define BOMB 10


void Initboard(char board[ROWS][COLS], int rows, int cols, char ch);//初始化棋盘

void Displayboard(char board[ROWS][COLS], int row, int col);//打印棋盘

void Setboard(char board[ROWS][COLS], int row, int col);//布置雷

void Findbomb(char concealboard[ROWS][COLS], char showboard[ROWS][COLS], int row, int col);//找雷

game.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"

void Initboard(char board[ROWS][COLS], int rows, int cols, char ch)
{
	for (int i = 0; i < rows; i++)
	{
		for (int j = 0; j < cols; j++)
		{
			board[i][j] = ch;
		}
	}
}

void Displayboard(char board[ROWS][COLS], int row, int col)
{
	printf("-------------------\n");
	for (int i = 0; i <= row; i++)
	{
		printf("%d ",i);
	}
	printf("\n");
	for (int i = 1; i <= row; i++)
	{
		printf("%d ", i);
		for (int j = 1; j <= col; j++)
		{
			printf("%c ", board[i][j]);
		}
		printf("\n");
	}
	printf("-------------------\n");
}


void Setboard(char board[ROWS][COLS], int row, int col)//布置雷
{
	int x = 0;
	int y = 0;
	int count = BOMB;
	while (count)
	{
		x = rand() % row + 1;
		y = rand() % col + 1;
		if (board[x][y] == '0')
		{
			board[x][y] = '1';
			count--;
		}
	}
}
int get_count(char concealboard[ROWS][COLS],int x,int y)//计算周边8个坐标的雷数
{
	return (concealboard[x - 1][y - 1] + concealboard[x - 1][y] +
		concealboard[x - 1][y + 1] + concealboard[x][y - 1] +
		concealboard[x][y + 1] + concealboard[x + 1][y - 1] +
		concealboard[x + 1][y] + concealboard[x + 1][y + 1]) - 8 * '0';
}
void open(char concealboard[ROWS][COLS], char showboard[ROWS][COLS], int x, int y)//排雷展开
{
	int count = 0;
	count=get_count(concealboard, x, y);
	if (count != 0)//不是雷,且周边有雷
	{
		showboard[x][y] = count + '0';
		
		return;
	}
	else if(showboard[x][y] != ' ')//不是雷,并且周边没雷
	{
		showboard[x][y] = ' ';//把当前坐标制成空格符号,以防止死递归
		
		for (int i = x-1; i <= x+1; i++)
		{
			for (int j =y-1;j<=y+1;j++)
			{
				open(concealboard, showboard, i, j);//对周边8个坐标展开
			}
		}
	}
	else
	{
		return;
	}
}
bool Win(char showboard[ROWS][COLS], int row, int col)
{
	int count = 0;
	for (int i = 1; i <=row; i++)
	{
		for (int j = 1; j <=row; j++)
		{
			if (showboard[i][j] == '*')
			{
				count++;//计算*号数量
			}
		}
	}
	return count == BOMB;//如果*号为10个,说明找到了10个雷,获胜
}
void Findbomb(char concealboard[ROWS][COLS], char showboard[ROWS][COLS], int row, int col)//找雷
{
	
	int x = 0;
	int y = 0;
	
	
	while (1)
	{
		
		printf("请输入要找的坐标:");
		scanf("%d%d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col && showboard[x][y] =='*')
		{
			if (concealboard[x][y] == '1')//如果是雷结束游戏
			{
				printf("很遗憾,您被炸死了!\n");
				Displayboard(concealboard, row, col);
				break;
			}
			else//如果不是,就计算一下周边雷的个数,和进行展开
			{
				open(concealboard, showboard, x, y);
				system("cls");
				Displayboard(showboard, row, col);
				if (Win(showboard, row, col))//
				{
					break;
				}
			}
		}
		else
		{
			printf("坐标不合法,请重新输入:\n");
		}
	}
	if (Win(showboard, row, col))
	{
		printf("恭喜你,成功排雷\n");
	}
}

test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"

void meun()
{
	printf("******************************\n");
	printf("************ 扫雷 ************\n");
	printf("*****   1.play  0.exit   *****\n");
	printf("******************************\n");
}
void game()
{
	char concealboard[ROWS][COLS] = { 0 };//隐藏的棋盘
	char showboard[ROWS][COLS] = { 0 };//展示的棋盘

	Initboard(concealboard, ROWS, COLS,'0');//初始化隐藏的棋盘,全部初始化为字符0
	Initboard(showboard, ROWS, COLS,'*');//初始化显示的棋盘,全部初始化为字符*

	
	Displayboard(showboard, ROW, COL);//打印给玩家看的棋盘

	Setboard(concealboard, ROW, COL);//为隐藏的棋盘中设置雷
	

	Findbomb(concealboard, showboard, ROW, COL);//在隐藏的棋盘中寻找雷,再通过联动显示的棋盘打印出来
	
}
int main()
{
	srand((size_t)time(NULL));
	int input = 0;
	do
	{
		meun();
		printf("请选择:");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("选择错误请重新选择\n");
			break;
		}
	} while (input);
	return 0;
}

以上就是全部代码,还有很多需要优化的地方,我之后也会继续改良,如有错误和不足的地方。欢迎大家指正,完结撒花

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值