• 【项目】扫雷小游戏(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 
    #include 		//用于调用随机种子
    #include 		//设置随机种子的参数需要调用该库函数time
    #include 	//用于执行一些命令行(后面再看)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2. 定义常量

    #define ROW 9		//设置行
    #define COL 9		//设置列
    #define COUNT 10	//设置地雷数量
    
    #define ROWS ROW+2	//扫雷数组实际的行
    #define COLS COL+2	//扫雷数组实际的列
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    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
    • 2
    • 3
    • 4
    • 5

    五、源文件实现

    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;
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    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--;
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    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");
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    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');
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    六、测试文件实现

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

    1. 游戏菜单

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

    void menu(void)
    {
    	printf("****************************\n");
    	printf("*********  1. play  ********\n");
    	printf("*********  0. exit  ********\n");
    	printf("****************************\n");
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    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);
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    七、完整代码

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

  • 相关阅读:
    K8S:kubeadm搭建K8S+Harbor 私有仓库
    从MLPerf谈起:如何引领AI加速器的下一波浪潮
    第1章 算法和数据结构
    坐标转换&点云变换&姿态互转| 基于Eigen的坐标转换库-TransForms3d
    什么是服务器集群?海外服务器集群的优势?
    egg.js sequelize数据库操作配置
    Java NIO 学习
    【ES】笔记-Map介绍与API
    使用tftpd更新开发板内核
    Crack:GoJS 2.2.18 -2022-09-08 update
  • 原文地址:https://blog.csdn.net/weixin_52811588/article/details/126691000