练手小项目--C语言超详细动态内存版扫雷

扫雷小游戏相信大家都玩过吧,这次我们自己用动态内存来实现一下扫雷游戏!!!

要做出来扫雷小游戏肯定要先理解它的机制和玩法。
在这里插入图片描述
1、方格中又若干个雷,点到雷上,游戏结束,走完没有雷的格子,游戏通关。

2、没有雷的方格的数字代表的含义:表示周围一圈的八个方格中又几个雷。


既然熟悉了游戏规则,那我们来编写每个模块的函数吧。

1、首先需要创建出来一个二维矩阵,每个元素代表游戏中的每个方格

//创建二维矩阵
char** creatMat(int row, int col)
{
	//增加2行2列,便于计算每个位置雷的个数
	//创建一个指针数组
	char** Mat = (char**)malloc(sizeof(char*)*(row + 2));//动态开辟内存
	for (int i = 0; i < row+2; i++)
	{
		Mat[i] = (char*)malloc(sizeof(char)*(col + 2));//动态开辟内存
	}
	return Mat;
}

在这里插入图片描述

2、将这个二维矩阵的所有元素都初始化为字符ch

//初始化二维矩阵
void initMat(char** Mat, int row, int col, char ch)
{
	for (int i = 0; i < row + 2; i++)
	{
		for (int j = 0; j < col + 2; j++)
		{
			Mat[i][j] = ch;
		}
	}
}

3、随机在不同的格子中放入雷,用‘*’表示。

//随机埋雷
void setMine(char** Mat, int row, int col)
{
	int count = MINE_NUM;	//定义雷数
	while (count)
	{
		//x:1-row	 y:1-col
		int x = rand() % row + 1;
		int y = rand() % col + 1;
		//若格子不为*(雷),则在格子埋下雷,雷数减一
		if (Mat[x][y] != '*')
		{
			Mat[x][y] = '*';	
			count--;
		}
	}
}

4、编写显示这个二维矩阵的函数

//打印二维矩阵
void showMat(char** Mat, int row, int col)
{
	printf("-------------------------------------\n");
	//打印列:0 1 2 3 4...col
	for (int i = 0; i <= col; i++)
	{
		printf("%d ", i);
	}
	printf("\n");
	//打印行:1 2 3 4 5...row
	for (int i = 1; i <= row; i++)
	{
		printf("%d ", i);
		for (int j = 1; j <= col; j++)
		{
			printf("%c ", Mat[i][j]);
		}
		printf("\n");
	}
	printf("-------------------------------------\n");
}

5、打开格子,如果格子中没有雷,就会显示格子周围的8个格子中雷的个数。
这里我画一个图:
在这里插入图片描述

//返回没有雷的格子上的数字
int getMineNum(char** Mat, int row, int col, int x, int y)
{
	//旋转矩阵
	static int posOffset[8][2] = { { -1, -1 }, { -1, 0 }, { -1, 1 }, { 0, -1 }, { 0, 1 }, { 1, -1 }, { 1, 0 }, { 1, 1 } };
	int count = 0;
	//依次遍历8个格子
	for (int i = 0; i < 8; i++)
	{
		int nx = x + posOffset[i][0];
		int ny = y + posOffset[i][1];
		//如果有雷,则数字加一
		if (Mat[nx][ny] == '*')
		{
			count++;
		}
	}
	return count;
}

6、如何判断游戏输赢,输入的格子若是雷则游戏结束
每走一步记录一下步数,如果步数等于没有雷的格子数,则胜利

//游戏模块
void game(char** mineMat, char** mineInfo,int row,int col)
{
	int step = 0;
	while (step < row*col - MINE_NUM)
	{
		int x, y;
		printf("请输入一个坐标:\n");
		scanf("%d%d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (mineMat[x][y] == '*')
			{
				printf("game over!!\n");
				showMat(mineMat, row, col);
				break;
			}
			//获取x,y位置周围雷的个数
			int num = getMineNum(mineMat, row, col, x, y);
			mineInfo[x][y] = num + '0';
			showMat(mineInfo, row, col);
			//成功执行了一步
			step++;
		}
		else
		{
			printf("位置无效,重新输入\n");
		}
	}
	if (step == row*col - MINE_NUM)
	{
		printf("you are win!\n");
	}
}

8、最后不要忘记free掉开辟的内存以及把指向堆的指针置为NULL

//释放动态开辟的空间
void freeMat(char** Mat, int row, int col)
{
	for (int i = 0; i < row; i++)
	{
		//释放每一行的空间
		free(Mat[i]);
	}
	//释放指针数组的空间
	free(Mat);
}

到这里每个模块的函数就已经编写好了,接下来只需要在头文件引入每个函数以及定义一个main函数来调用每个模块就ok啦


最后附上源码

game.h文件

#ifndef __GAME_H__

#include<stdio.h>
#include<stdlib.h>

#define ROW 10
#define COL 10
#define MINE_NUM 20

char** creatMat(int row, int col);

void initMat(char** Mat, int row, int col, char ch);

void setMine(char** Mat, int row, int col);

void showMat(char** Mat, int row, int col);

int getMineNum(char** Mat, int row, int col, int x, int y);

void game(char** mineMat, char** mineInfo, int row, int col);

void freeMat(char** Mat, int row, int col);

void test();

#endif

game.c文件

#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"

//创建二维矩阵
char** creatMat(int row, int col)
{
	//增加2行2列,便于计算每个位置雷的个数
	//创建一个指针数组
	char** Mat = (char**)malloc(sizeof(char*)*(row + 2));//动态开辟内存
	for (int i = 0; i < row+2; i++)
	{
		Mat[i] = (char*)malloc(sizeof(char)*(col + 2));//动态开辟内存
	}
	return Mat;
}

//初始化二维矩阵
void initMat(char** Mat, int row, int col, char ch)
{
	for (int i = 0; i < row + 2; i++)
	{
		for (int j = 0; j < col + 2; j++)
		{
			Mat[i][j] = ch;
		}
	}
}

//随机埋雷
void setMine(char** Mat, int row, int col)
{
	int count = MINE_NUM;	//定义雷数
	while (count)
	{
		//x:1-row	 y:1-col
		int x = rand() % row + 1;
		int y = rand() % col + 1;
		//若格子不为*(雷),则在格子埋下雷,雷数减一
		if (Mat[x][y] != '*')
		{
			Mat[x][y] = '*';	
			count--;
		}
	}
}

//打印二维矩阵
void showMat(char** Mat, int row, int col)
{
	printf("-------------------------------------\n");
	//打印列:0 1 2 3 4...col
	for (int i = 0; i <= col; i++)
	{
		printf("%d ", i);
	}
	printf("\n");
	//打印行:1 2 3 4 5...row
	for (int i = 1; i <= row; i++)
	{
		printf("%d ", i);
		for (int j = 1; j <= col; j++)
		{
			printf("%c ", Mat[i][j]);
		}
		printf("\n");
	}
	printf("-------------------------------------\n");
}

//返回没有雷的格子上的数字
int getMineNum(char** Mat, int row, int col, int x, int y)
{
	//旋转矩阵
	static int posOffset[8][2] = { { -1, -1 }, { -1, 0 }, { -1, 1 }, { 0, -1 }, { 0, 1 }, { 1, -1 }, { 1, 0 }, { 1, 1 } };
	int count = 0;
	//依次遍历8个格子
	for (int i = 0; i < 8; i++)
	{
		int nx = x + posOffset[i][0];
		int ny = y + posOffset[i][1];
		//如果有雷,则数字加一
		if (Mat[nx][ny] == '*')
		{
			count++;
		}
	}
	return count;
}

//游戏模块
void game(char** mineMat, char** mineInfo,int row,int col)
{
	int step = 0;
	while (step < row*col - MINE_NUM)
	{
		int x, y;
		printf("请输入一个坐标:\n");
		scanf("%d%d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (mineMat[x][y] == '*')
			{
				printf("game over!!\n");
				showMat(mineMat, row, col);
				break;
			}
			//获取x,y位置周围雷的个数
			int num = getMineNum(mineMat, row, col, x, y);
			mineInfo[x][y] = num + '0';
			showMat(mineInfo, row, col);
			//成功执行了一步
			step++;
		}
		else
		{
			printf("位置无效,重新输入\n");
		}
	}
	if (step == row*col - MINE_NUM)
	{
		printf("you are win!\n");
	}
}

//释放动态开辟的空间
void freeMat(char** Mat, int row, int col)
{
	for (int i = 0; i < row; i++)
	{
		//释放每一行的空间
		free(Mat[i]);
	}
	//释放指针数组的空间
	free(Mat);
}

//测试游戏运行
void test()
{
	char** mineMat = creatMat(ROW, COL);	//雷位置
	char** mineInfo = creatMat(ROW, COL);	//用户界面:雷周围的信息

	initMat(mineMat, ROW, COL, '0');
	initMat(mineInfo, ROW, COL, '-');
	setMine(mineMat, ROW, COL);
	printf("雷:\n");
	showMat(mineMat, ROW, COL);
	printf("雷的信息:\n");
	showMat(mineInfo, ROW, COL);

	game(mineMat, mineInfo, ROW, COL);
}

main.c文件

#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"

int main()
{
	srand((unsigned)time(NULL));	//让雷真随机
	test();
	return 0;
}

小伙伴们,学会了吗😜

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值