自制扫雷小游戏

目录

一.创建项目

二.菜单制作

1.游戏的页面设计

2.游戏规则   

三.棋盘制作以及初始化

1.棋盘初始化

2.模式设置

3.布置雷

4.计算坐标周围雷数

四.屏幕输出设计

1.棋盘输出函数

2.屏幕呈现状态

 3.递归扫雷

4.游戏结束的条件

5.清屏处理

五.原码:

1.头文件game.h

2.源文件game.c

3.源文件main.c


一.创建项目

首先我们创建项目准备一个头文件game.h用来做函数的声明,一个源文件game.c用来写函数,最后用一个源文件main.c来作主函数的运行。

 需要在game.c和text.c中包含一下头文件,要注意自己写的头文件要用双引号引用如下:

4e35e341857e4394a3d5a0ac5873355d.png

二.菜单制作

b7f4eaae27bc4af5aaf9b9a3c33542b1.png

b0ee7241bd2442cdb6151ce9e82f173e.png

game函数:

1.游戏的页面设计

我们可以想象做以下这样一个页面,让玩家输入坐标来排雷。

bbfe3856fd9a4cc4a4b3b00b294ddec6.png

2.游戏规则   

(1).输入坐标位置是雷,游戏失败。
(2).如果不是雷,则在该位置标记出周围一圈雷的个数,玩家继续输入。
(3).如果不是雷,而且周围一圈都没有雷(即显示数字0),那么,将显示周围一片周围雷数都为0的区域,只到遇到非零。

(4).当排除所有不是雷的地方(即只剩下有雷的地方未显示)游戏胜利。

三.棋盘制作以及初始化

我们需要制作3个棋盘

第一个棋盘用来布置雷(数组a[rs][cs])

第二个棋盘用来呈现给玩家看(数组b[rs][cs])

第三个棋盘用来储存每个坐标周围雷的个数(数组e[rs][cs])

1.棋盘初始化

  因为考虑到计算每个坐标周围雷数的时候可能会发生数组越界,所以我们要制作一个9*9,10个雷的扫雷游戏时,实际我们需要做一个(9+2)*(9+2)的棋盘格,而只用给玩家显示9*9的棋盘。其中多加的两行两列只是为了防止数组越界,不必布置雷。

5e4d63971f744c758ed892b7ffe67fe4.png

我们用a,b,e三个二级指针来模拟三个二维数组

a矩阵来布置雷,b矩阵用来呈现给用户看,e矩阵来储存每个个坐标周围雷的个数

rs,cs,L分别表示雷区的长宽和雷的个数

写一个二级指针模拟二维数组的函数relc

2.模式设置

Sleep函数可以实现睡眠,Sleep(600)表示睡眠600毫秒用这样一个函数可以增加游戏效果,然后我们可以写一个color函数来设置控制台颜色入下:

#include<stdio.h>
#include<Windows.h>
#include<stdlib.h>
void color(int k)
{
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), k);
}
int main()
{
	for (int i = 1; i <= 255; i++)
	{
		color(i);
		printf("%3d ", i);
		if (i%15==0)
			printf("\n");
	}
	color(15);
	return 0;
}

上面代码的输出结果如下:

游戏的模式设置:

		color(6);
			printf("请选择模式>>\n");
			color(15);
			Sleep(600);
			printf("******** "); color(2); printf("@&*******************&@"); color(15); printf(" ********\n"); Sleep(100);
			printf("**********"); color(11); printf("1.基础 <  9  *  9  >"); color(15); printf("***********\n"); Sleep(100);
			printf("**********"); color(9); printf("2.简单  < 16 * 16 > "); color(15); printf("***********\n"); Sleep(100);
			printf("**********"); color(13); printf("3.困难  < 16 * 30 > "); color(15); printf("***********\n"); Sleep(100);
			printf("**********"); color(4); printf("4.极限  < 36 * 50 > "); color(15); printf("***********\n"); Sleep(100);
			printf("**********"); color(14); printf("5.自定义 < ? * ?>"); color(15); printf("************\n"); Sleep(100);
			printf("******* "); color(2); printf(">+$*******************$+<"); color(15); printf(" *******\n"); Sleep(100);
			k = 0;
			int p = 0;
			int u = 0;
			char** a=NULL, **b=NULL, **e=NULL;
			int rs = 0, cs = 0, L = 0;
			int w;
			while (scanf("%d", &w),w < 1 || w>5)
			{
				color(4);
				printf("输入错误,请输入1,2,3,4或5\n");
				color(6);
				printf("请选择模式>>\n");
				color(15);
			}
			switch (w)
			{
				case 1:
					rs = 11, cs = 11, L = 10;
					break;
				case 2:
					rs = 18,cs = 18,L = 40;
					break;
				case 3:
					rs = 18,cs = 32,L = 99;
					break;
				case 4:
					rs = 38,cs = 52,L = 140;
					break;	
				case 5:
					printf("请输入雷区的长>>\n");
					scanf("%d", &k);
					printf("请输入雷区的宽>>\n");
					scanf("%d", &u);
					printf("雷区中雷的个数>>\n");
					scanf("%d", &p);
					cs = k + 2,rs = u + 2,L = p;
					break;
				default:
					perror("w_error");
					return;
			}

效果如下:

使用刚才写的relc函数中创建棋盘

kkk,le,uuu这些函数可以写在game.c中,但要在game.h中声明。

如下:

3.布置雷

   一个位置要么是雷要么不是,只有两种情况,那么我们就可以用字符 ' 1 ' 表示雷,字符 ' 0 ' 表示没有雷,(这里用字符而不用数字的原因是为了与 ' * ' 保持一致方便后续操作)。

布雷是随机的,所以就要用到一个随机数,这里需要包含头文件<stdlib.h>和<time.h>

4.计算坐标周围雷数

这里我们要知道到  ' 1 ' + ' 1 '并不等于 ' 2 ',字符本身不能相加减,相加减的是它们的Ascll值。

fbd3bef9beb5495d950568dcf821e311.png

abea54f8290b421aad77ae2467b380ce.png

所以我们计算周围雷数的时候用以下操作:

四.屏幕输出设计

1.棋盘输出函数

为了增加用户的体验感,我们可以添加一些颜色,做这样一个输出函数。

效果如下:

1ba6395ac24e4bdf92e8240efed4ca27.png

2.屏幕呈现状态

        玩家输入坐标后用数组a[rs][cs]判断是否为雷(即是否是 ' 1 ')如果是则游戏失败并显示给玩家雷区信息(及棋盘a[rs][cs])。如果不是则把e[rs][cs] (即周围一圈雷的个数)赋值给对应位置的数组b[rs][cs],该过程通过Fo函数递归实现,即下面第3点递归扫雷,最后把数组b[rs][cs]呈现(输出函数实现)给玩家。

 3.递归扫雷

        如果用户输入坐标位置不是雷,而且周围一圈都没有雷(即显示数字0),那么,将显示周围一片周围雷数都为0的区域,直到遇到非零。

4.游戏结束的条件

玩家是需要多次输入的所以需要一个循环,直到游戏成功或失败时退出循环。 

(1)游戏失败退出游戏我们可以在循环中设置一个break语句。

(2)游戏成功退出游戏我们可以写一个函数(muu函数)来计算剩余 ' * ' 的个数,如果为10则退出循环且呈现游戏胜利。

5.清屏处理

为了方便玩家观看我们可以把上一次输出的结果清除后再进行输出。用到一个system函数。

五.原码:

1.头文件game.h

#pragma once
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#include<windows.h>
//棋盘初a,b始化
void kkk(char** a, int n, int m, char f);
//输出棋盘
void print(char** a,int r,int c);
//布置雷区
void le(char** a,int L,int r,int c);
//排查雷区个数
int count(char* a, int m, int n);
//玩家输入
void nnn(char** a, char** b, char** e,int r,int c,int L);
//棋盘c_周围雷数
void uuu(char** a, char** u,int r,int c);
//递归扫雷
void Fo(char** e, char** b, int m, int n,int r,int c);

2.源文件game.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h";
void kkk(char** a, int n, int m, char f)
{
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < m; j++)
		{
			a[i][j] = f;
		}
	}
}
void color(int k)
{
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), k);
}
void print(char** a, int r, int c)
{
	for (int i = 0; i < c - 4; i++)
	{
		printf(" ");
	}
	color(48);
	printf(" >.p..*-扫雷-*..q.<\n");
	for (int i = 0; i <= c; i++)
	{
		color(14);
		printf("%2d ", i);
	}
	printf("\n");
	for (int i = 1; i <= r; i++)
	{
		color(14);
		printf("%2d ", i);
		for (int j = 1; j <= c; j++)
		{
			switch (a[i][j])
			{
			case '*':
				color(2);
				printf("%2c ", a[i][j]);
				break;
			case '0':
				color(7);
				printf("%2c ", a[i][j]);
				break;
			case '1':
				color(3);
				printf("%2c ", a[i][j]);
				break;
			case '2':
				color(12);
				printf("%2c ", a[i][j]);
				break;
			case '3':
				color(4);
				printf("%2c ", a[i][j]);
				break;
			default:
				color(6);
				printf("%2c ", a[i][j]);
				break;
			}
		}
		printf("\n");
	}
}
void le(char** a, int L, int r, int c)//布雷
{
	srand((unsigned int)time(NULL));
	for (int i = 1; i <= L; i++)
	{
		int x = rand() % r + 1;
		int y = rand() % c + 1;
		if (a[x][y] == '1')
		{
			i--;
			continue;
		}
		a[x][y] = '1';
	}
}
int count(char** a, int m, int n)
{
	int u = 0;
	for (int i = m - 1; i <= m + 1; i++)
	{
		for (int j = n - 1; j <= n + 1; j++)
		{
			u += a[i][j] - '0';
		}
	}
	return u;
}
//
int muu(char** b, int rs, int cs)
{
	int a = 0;
	for (int i = 1; i <= rs-2; i++)
	{
		for (int j = 1; j <= cs-2; j++)
		{
			if (b[i][j] == '*')
			{
				a++;
			}
		}
	}
	return a;
}
//
void nnn(char** a, char** b, char** e, int r, int c,int L)
{
	while (muu(b,r+2,c+2) != L)
	{
		int n, m;
		color(12);
		printf("请输入坐标>>\n");
		scanf("%d%d", &n, &m);
		if (!(n <= r && n > 0 && m > 0 && m <= c))
		{
			printf("输入错误,请重新输入\n");
		}
		else
		{
			if (a[n][m] == '1')
			{
				printf("很遗憾你被炸死了\n");
				print(a,r,c);
				system("color 04");
				color(7);
				break;
			}
			else
			{
				system("cls");
				Fo(e, b, n, m,r,c);
				print(b,r,c);
			}
		}
	}
	if (muu(b,r+2,c+2) == L)
	{
		color(4);
		printf("!!恭喜你通过游戏!!\n");
		color(15);
	}
}
void uuu(char** a, char** u, int r, int c)
{
	for (int i = 1; i <= r; i++)
	{
		for (int j = 1; j <= c; j++)
		{
			u[i][j] = count(a, i, j) + '0';
		}
	}
}
void Fo(char** e, char** b, int n, int m, int r, int c)
{
	if (n > r || n < 1 || m > c || m < 1)
	{
		return;
	}
	if (b[n][m] != '*')
	{
		return;
	}
	b[n][m] = e[n][m];
	if (e[n][m] == '0')
	{
		Fo(e, b, n + 1, m, r, c);
		Fo(e, b, n - 1, m, r, c);
		Fo(e, b, n, m + 1, r, c);
		Fo(e, b, n, m - 1, r, c);
		Fo(e, b, n + 1, m + 1, r, c);
		Fo(e, b, n - 1, m - 1, r, c);
		Fo(e, b, n + 1, m - 1, r, c);
		Fo(e, b, n - 1, m + 1, r, c);
	}
	else
	{
		return;
	}
}

3.源文件main.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
#include<assert.h>
#include<stdio.h>
char** relc(char** a,int rs,int cs)
{
	a = (char**)malloc(sizeof(char*) * rs);
	assert(a);
	for (int i = 0; i < rs; i++)
	{
		a[i] = (char*)malloc(sizeof(a[0][0]) * cs);
		assert(a[i]);
	}
	return a;
}
void menu()
{
	while (1)
	{
		printf("*************扫雷游戏**************\n");
		printf("***********************************\n");
		printf("************* 1.play **************\n");
		printf("************* 0.exit **************\n");
		printf("***********************************\n");
		printf("请选择->>:\n");
		char k;
		scanf("%c", &k);
		if (k == '0')
		{
			printf("游戏已退出");
			return;
		}
		while(k!='1')
		{
			color(4);
			printf("输入错误,请选择0或1\n");
			color(15);
			printf("请选择->>:\n");
			scanf("%c", &k);
			color(15);
		}
		color(6);
			printf("请选择模式>>\n");
			color(15);
			Sleep(600);
			printf("******** "); color(2); printf("@&*******************&@"); color(15); printf(" ********\n"); Sleep(100);
			printf("**********"); color(11); printf("1.基础 <  9  *  9  >"); color(15); printf("***********\n"); Sleep(100);
			printf("**********"); color(9); printf("2.简单  < 16 * 16 > "); color(15); printf("***********\n"); Sleep(100);
			printf("**********"); color(13); printf("3.困难  < 16 * 30 > "); color(15); printf("***********\n"); Sleep(100);
			printf("**********"); color(4); printf("4.极限  < 36 * 50 > "); color(15); printf("***********\n"); Sleep(100);
			printf("**********"); color(14); printf("5.自定义 < ? * ?>"); color(15); printf("************\n"); Sleep(100);
			printf("******* "); color(2); printf(">+$*******************$+<"); color(15); printf(" *******\n"); Sleep(100);
			k = 0;
			int p = 0;
			int u = 0;
			char** a=NULL, **b=NULL, **e=NULL;
			int rs = 0, cs = 0, L = 0;
			int w;
			while (scanf("%d", &w),w < 1 || w>5)
			{
				color(4);
				printf("输入错误,请输入1,2,3,4或5\n");
				color(6);
				printf("请选择模式>>\n");
				color(15);
			}
			switch (w)
			{
				case 1:
					rs = 11, cs = 11, L = 10;
					break;
				case 2:
					rs = 18,cs = 18,L = 40;
					break;
				case 3:
					rs = 18,cs = 32,L = 99;
					break;
				case 4:
					rs = 38,cs = 52,L = 140;
					break;	
				case 5:
					printf("请输入雷区的长>>\n");
					scanf("%d", &k);
					printf("请输入雷区的宽>>\n");
					scanf("%d", &u);
					printf("雷区中雷的个数>>\n");
					scanf("%d", &p);
					cs = k + 2,rs = u + 2,L = p;
					break;
				default:
					perror("w_error");
					return;
			}
			a = relc(a, rs, cs);//申请空间
			b = relc(b, rs, cs);//......
			e = relc(e, rs, cs);//......
			kkk(a, rs, cs, '0');//kkk函数把矩阵a初始化为全'0'
			kkk(b, rs, cs, '*');//把矩阵a初始化为全'*'
			le(a,L,rs-2,cs-2);//在矩阵a中布置L个雷
			uuu(a, e, rs - 2, cs - 2);//计算每个坐标周围雷的个数并存入e中
			system("cls");
			if (w == '4')
			{
				color(12);
				printf(" 展开全屏效果更佳哦!\n");
			}
			for (int i = 0; i <= cs-2; i++)
			{
				color(14);
				printf("%2d ", i);
			}
			printf("\n");
			for (int i = 1; i <= rs-2; i++)
			{
				color(14);
				Sleep(10);
				printf("%2d ", i);
				for (int j = 1; j <= cs-2; j++)
				{
					color(2);
					Sleep(10);
					printf("%2c ", b[i][j]);
				}
				printf("\n");
			}
			nnn(a, b, e,rs-2,cs-2,L);
	}
}
int main()
{
	menu();
	return 0;
}

  • 40
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值