【项目】扫雷小游戏(C语言)

【项目】—— 扫雷小游戏(C语言)

一、游戏介绍

使用C语言实现的一个扫雷小游戏,这里没有美观的鼠标可点触窗口,只有初学者面对的让人心酸的黑框框,以及需要键盘输入坐标的输入模式。

游戏功能

  1. 打开游戏,有一个进入游戏和退出游戏的界面
  2. 进入游戏,展示一个 9 × 9 9\times9 9×9的方格,每个位置都是空格
  3. 玩家开始输入排雷的坐标,如果该位置是雷,则游戏结束,玩家失败
  4. 如果该位置不是雷,则显示周围一圈的8个格子雷的数量,玩家继续输入坐标排雷
  5. 所有非雷位置全部排查时,游戏结束,玩家胜利

二、设计思路和结构

1. 设计思路

  1. 定义一个二维数组作为扫雷的范围,该数组是一个 9 × 9 9\times9 9×9的方格,随机在10个位置上设置10个雷
  2. 再次定义一个二维数组作为展示给用户的界面,该界面是一个 9 × 9 9\times9 9×9的方格,方格中没有字符
  3. 用户每次输入坐标,若是该坐标在扫雷数组上设置地雷,则会在展示界面的该坐标上显示*,并提示游戏结束
  4. 若是该界面上没有地雷,则会计算该坐标周围 3 × 3 3\times3 3×3个方格中有几个地雷,并将数字填入展示界面的方格中,展示给用户
  5. 用户每次输入坐标,对应位置显示出该位置的数字或雷,直到用户踩到地雷或排除所有雷时游戏结束

2. 设计结构

  1. test.c:测试源文件,含有main函数,是进入程序的入口
  2. game.c:游戏源文件,实现游戏内的函数定义
  3. game.h:游戏头文件,包含源文件需要包含的头文件,实现宏定义,对游戏内的函数进行声名

三、相关问题

1. 如何设置地雷

先将二维数组初始化成全0,调用随机函数,生成 9 × 9 9\times9 9×9范围内的坐标,并将该地雷所在坐标置为数字1

1

2. 如何计算输入坐标的数字

  1. 在扫雷数组的输入坐标周围的 3 × 3 3\times3 3×3位置上含有地雷的数字为1,没有地雷的数字为0,所以将这9个位置中存储的数字加起来就是该位置周围地雷的数量,将该数字以字符形式展示给展示界面即可
  2. 但是扫雷数组最边上一圈的坐标周围并没有 3 × 3 3\times3 3×3范围的数字,若是直接相加则会数组越界,所以我们在上下左右各延展一行或一列,该行或该列不放置地雷

2

3. 如何判断输赢

  1. 输赢是在用户输入坐标后进行判断,用户每次输入坐标都会有计数器计算用户排过多少雷。
  2. 用户输入坐标,若该位置在扫雷数组中是地雷,则游戏结束,玩家失败
  3. 若是该位置不是地雷,计算周围地雷数量,放置在展示数组的指定坐标中,此时判断未排除的数量是否达到雷的数量,若是达到则游戏结束,玩家胜利。

四、头文件实现

1. 引入头文件

#pragma once			//防止头文件重复包含
#include <stdio.h>
#include <stdlib.h>		//用于调用随机种子
#include <time.h>		//设置随机种子的参数需要调用该库函数time
#include <Windows.h>	//用于执行一些命令行(后面再看)

2. 定义常量

#define ROW 9		//设置行
#define COL 9		//设置列
#define COUNT 10	//设置地雷数量

#define ROWS ROW+2	//扫雷数组实际的行
#define COLS COL+2	//扫雷数组实际的列

3. 函数声明

void InitBoard(char board[ROWS][COLS], int rows, int cols, char c);				//初始化
void SetMine(char mine[ROWS][COLS], int row, int col, int count);				//部署地雷
void DisplayBoard(char board[ROWS][COLS], int row, int col);					//打印展示界面
_Bool FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);	//排查地雷
int get_mine_count(char mine[ROWS][COLS], int row, int col, int x, int y);		//获取该子周围的雷的数量

五、源文件实现

1. 初始化

将扫雷数组初始化为0

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

2. 部署地雷

在扫雷数组上随机设置地雷为1,为了防止生成坐标重复,使用计数器count记录设置好的地雷数量,若是地雷成功设置才会计数

void SetMine(char mine[ROWS][COLS], int row, int col, int count)
{
	while (count > 0)
	{
		int x = rand() % row + 1;
		int y = rand() % col + 1;

		if (mine[x][y] == '0')
		{
			mine[x][y] = '1';
			count--;
		}
	}
}

3. 打印展示界面

需要打印出9宫格的效果,使用-字符作为行,|字符作为列。先打印一行,再打印row行,最后一行和一列要单独处理

void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
	int k = (col - 5) / 2;
	int i = 0;

	printf("-");
	for (i = 0; i <= col; i++)
	{
		if (i < k || i >= 5+k)
		{
			printf("--");
		}
		else
		{
			printf("扫雷小游戏");
			i += 5;
		}
		
	}
	printf("\n");

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

4. 获取该坐标周围雷的数量

将扫雷数组上下左右9个坐标的值加起来就是雷的数量

int get_mine_count(char mine[ROWS][COLS], int row, int col, int x, int y)
{
	return (mine[x - 1][y - 1]
		+ mine[x - 1][y]
		+ mine[x - 1][y + 1]
		+ mine[x][y - 1]
		+ mine[x][y + 1]
		+ mine[x + 1][y - 1]
		+ mine[x + 1][y]
		+ mine[x + 1][y + 1])
		- (8 * '0');
}

5. 排查地雷

输入坐标,并判断是否合法,是否重复,然后判断是否是雷,若都不是,计算该位置周围地雷数量并展示界面,然后判断输赢

_Bool FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int num = 0;	//已排查的数量
	do
	{
		printf("请输入坐标>");
		scanf("%d %d", &x, &y);

		//判断坐标是否非法
		if ((0 < x && x <= row) && (0 < y && y <= col))
		{
			//判断坐标是否重复
			if (show[x][y] == '*')
			{
				//此处是雷
				if (mine[x][y] == '1')
				{
					printf("很遗憾,你被炸死了\n");
					DisplayBoard(mine, row, col);
					break;

				}
				//此处不是雷
				else
				{
					num++;
					int count = get_mine_count(mine, row, col, x, y);
					show[x][y] = (char)count + '0';
					system("cls");
					DisplayBoard(show, row, col);
				}
			}
			else
			{
				printf("该位置已被排查\n");
			}
		}
		else
		{
			printf("坐标输入错误\n");
		}

		//判断输赢
		if (num >= row * col - COUNT)
		{
			printf("恭喜你,你赢了\n");
			DisplayBoard(mine, row, col);
			break;
		}
	} while (1);

	return 0;
}

六、测试文件实现

测试文件是用来测试游戏实现,并写有main函数作为启动程序的入口。

1. 游戏菜单

只有两个选项,开始游戏和推出游戏

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

2. 运行游戏

将游戏逻辑封装成一个函数,调用该函数就可以完整的启动游戏

void game() 
{
	char mine[ROWS][COLS] = { '0' };
	char show[ROWS][COLS] = { '0' };
	//初始化棋盘
	InitBoard(mine, ROWS, COLS, '0');
	InitBoard(show, ROWS, COLS, '*');
	//部署地雷
	SetMine(mine, ROW, COL, COUNT);

	//展示棋盘
	DisplayBoard(show, ROW, COL);
	//玩家排雷
	FindMine(mine, show, ROW, COL);

}

3. main函数

在这里实现菜单和游戏的调用,提供用于开始游戏和结束游戏的选择

int main(void)
{
	srand((unsigned int)time(NULL));

	int input = 0;
	do
	{
		menu();
		printf("请输入操作序号>");
		scanf("%d", &input);

		switch (input)
		{
		case 0:
			printf("欢迎下次光临\n");
			break;
		case 1:
			game();
			break;
		default:
			printf("输入错误,请重新输入\n");
			break;
		}

	} while (0 != input);
	
	return 0;
}

七、完整代码

代码存储于gitee中:点击查看完整代码

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值