其他分享
首页 > 其他分享> > C语言小项目(2)——扫雷(基础版)

C语言小项目(2)——扫雷(基础版)

作者:互联网

C语言小项目(2)——扫雷(基础版)

前言

扫雷游戏是C语言初学者都需要练习的一个小项目,本文所实现的扫雷为最基础的版本(即一次只能扫一格),实际的扫雷游戏会有一种功能:在玩家点击格子的时候会向外展开,直到即将遇到雷为止。本文目前暂无实现这一功能。

代码详解

一、主函数

int main()
{
	int i = 0;
	srand((unsigned int)time(NULL));
	do
	{
		menu();//打印菜单
		scanf("%d", &i);
		switch (i)
		{
		case 1:
			game();
			break;
		case 0:
			printf("游戏结束\n");
			break;
		default:
			printf("输入错误,请重新输入\n");
			break;
		}
	} while (i);
	return 0;
}

1、srand((unsigned int)time(NULL))

为随机数生成器,后续布置雷的时候需要利用到rand()函数。

2、do-while循环

用于玩家多次游玩,直到玩家选择游戏结束,则终止循环。
menu()函数为菜单函数,用于打印简易菜单供玩家选择。

void menu()
{
	printf("*************************\n");
	printf("****** 1、开始游戏 ******\n");
	printf("****** 0、结束游戏 ******\n");
	printf("*************************\n");
}

运用switch-case函数,若玩家输入"1",则开始游戏;若玩家输入"0",则游戏结束,同时循环中止;若玩家输入其他数字,则会提示玩家并让玩家重新输入,直到输入的数字为"0"或者"1"为止。

二、游戏实现函数

本扫雷游戏的实现依靠两个二维数组:mine数组用于系统随机布置雷,show数组展现给玩家,供玩家进行排雷。当除了雷以外的格子都被玩家选中之后,玩家获得胜利。

void game()
{
	//初始化
	char mine[ROWS][COLS] = { 0 };//存放布置雷的信息
	char show[ROWS][COLS] = { 0 };//存放玩家操作的信息
	//初始化布置雷界面
	Init_board(mine, ROWS, COLS, '0');
	//初始化玩家操作界面
	Init_board(show, ROWS, COLS, '*');
	//随机生成雷
	Mine_set(mine, ROW, COL);
	//打印扫雷界面
	Display_board(show, ROW, COL);
	//排雷
	Mine_sweep(mine, show, ROW, COL);
}

1、char mine[ROWS][COLS] = { 0 },char show[ROWS][COLS] = { 0 }

用于创建并初始化二维数组,作为扫雷的界面
本项目采用9*9的格子,为了便于日后的修改,此处采用了define ROW和COL的方式。
除了ROW和COL之外,额外定义了ROWS和COLS这两个变量名。玩家在扫雷的时候,若没有选到雷,被选中的格子会显示周围雷的个数,但边界处的格子在计算时会有一部分的格子在边界外,如果不加以处理的话不利于之后的计算。因此,本项目选择额外在最外围加了一圈,这样的即便是边界处也可以计算周围的雷的个数。

#define ROW 9
#define COL 9

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

2、void Init_board(char board[ROWS][COLS], int row, int col, char set)

该函数声明为扫雷界面初始化函数声明,将mine初始化为字符’0’,show初始化为’*’(此处通过建立char类型的变量set,赋予set不同的值,可以将界面初始化为任何字符,避免了需要建立两个函数分别初始化mine和show

void Init_board(char board[ROWS][COLS], int row, int col, char set)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			board[i][j] = set;
		}
	}
}

3、Mine_set(mine, ROW, COL)

该函数用于随机生成雷。利用count计数,若该处未布置雷,则放置字符’1’代表雷(此处放置’1’便于之后的计算周围雷的个数),count相应减1。

void Mine_set(char board[ROWS][COLS], int row, int col)
{
	int count = easy_mode;
	while (count > 0)
	{
		int x = rand() % row + 1;
		int y = rand() % col + 1;
		if (board[x][y] == '0')
		{
			board[x][y] = '1';
			count--;
		}
	}
}

此处通过定义了easy_mode,便于日后对于雷的个数进行修改。

#define easy_mode 10

4、Display_board(show, ROW, COL)

该函数作用为打印界面供玩家进行扫雷,除了9*9格子外额外打印了行号和列号便于玩家输入坐标进行排雷。

void Display_board(char board[ROWS][COLS], int row, int col)
{
	int i = 0;
	int j = 0;
	//打印列号
	for (j = 0; j <= col; j++) {
		printf("[%d]", j);
	}
	printf("\n");

	for (i = 1; i <= row; i++)
	{
		printf("[%d]", i);//打印行号
		for (j = 1; j <= col; j++)
		{
			printf(" %c ", board[i][j]);
		}
		printf("\n");

5、Mine_sweep(mine, show, ROW, COL)

该函数为整个扫雷游戏的核心。当玩家选择了所有除了雷以外的格子时,玩家获得胜利。

void Mine_sweep(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int win = 0;
	while (win < row * col - easy_mode)
	{
		printf("请输入排查的坐标:");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (mine[x][y] == '1')
			{
				printf("你被炸死了,游戏结束\n");
				Display_board(mine, ROW, COL);
				break;
			}
			else
			{
				int n = get_mine_amount(mine, x, y);//判断周围雷的个数
				show[x][y] = n + '0';
				win++;
				Display_board(show, ROW, COL);
			}
		}
		else
		{
			printf("超出范围,请重新输入\n");
		}
	}
	if (win == row * col - easy_mode)
	{
		printf("恭喜你,获得胜利\n");
		Display_board(mine, ROW, COL);
	}
}

玩家输入坐标后,首先要排查玩家输入的坐标是否在界面范围内,若在范围内,继续判断玩家是否踩到了雷,若踩到雷则跳出循环游戏结束,反之则利用get_mine_amount(mine, x, y)函数计算周围雷的个数,并将个数打印在界面上,供玩家进行下一步的判断。
此处利用了一个小技巧:一个数字加上字符’0’可以转变成相对应的字符(数字加上字符’0’相当于该数字加上’0’的ASCII码值)。
因此在get_mine_amount函数中,我们只需加总玩家选中的坐标周围8个格子里的字符后减去8乘上’0’,即可得到对应的雷的个数的数字,这也是先前选择字符’1’作为雷的标记的原因。

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

由于二维数组show是char类型的,因此在赋值的时候需要加上字符’0’将数字转变为对应字符。

代码展示

一、game.h

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

//定义行、列
#define ROW 9
#define COL 9

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

#define easy_mode 10

//初始化扫雷界面
void Init_board(char board[ROWS][COLS], int row, int col, char set);

//打印扫雷界面
void Display_board(char board[ROWS][COLS], int row, int col);

//随机生成雷
void Mine_set(char board[ROWS][COLS], int row, int col);

//排雷
void Mine_sweep(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);

二、test.c

#define _CRT_SECURE_NO_WARNINGS
#include "game.h"

//菜单函数
void menu()
{
	printf("*************************\n");
	printf("****** 1、开始游戏 ******\n");
	printf("****** 0、结束游戏 ******\n");
	printf("*************************\n");
}

//扫雷游戏
void game()
{
	//初始化
	char mine[ROWS][COLS] = { 0 };//存放布置雷的信息
	char show[ROWS][COLS] = { 0 };//存放玩家操作的信息
	//初始化布置雷界面
	Init_board(mine, ROWS, COLS, '0');
	//初始化玩家操作界面
	Init_board(show, ROWS, COLS, '*');
	//随机生成雷
	Mine_set(mine, ROW, COL);
	//打印扫雷界面
	Display_board(show, ROW, COL);
	//排雷
	Mine_sweep(mine, show, ROW, COL);
}


//主函数
int main()
{
	int i = 0;
	srand((unsigned int)time(NULL));
	do
	{
		menu();//打印菜单
		scanf("%d", &i);
		switch (i)
		{
		case 1:
			game();
			break;
		case 0:
			printf("游戏结束\n");
			break;
		default:
			printf("输入错误,请重新输入\n");
			break;
		}
	} while (i);
	return 0;
}

三、game.c

#define _CRT_SECURE_NO_WARNINGS
#include "game.h"

//初始化扫雷界面
void Init_board(char board[ROWS][COLS], int row, int col, char set)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			board[i][j] = set;
		}
	}
}

//打印扫雷界面
void Display_board(char board[ROWS][COLS], int row, int col)
{
	int i = 0;
	int j = 0;
	//打印列号
	for (j = 0; j <= col; j++) {
		printf("[%d]", j);
	}
	printf("\n");

	for (i = 1; i <= row; i++)
	{
		printf("[%d]", i);//打印行号
		for (j = 1; j <= col; j++)
		{
			printf(" %c ", board[i][j]);
		}
		printf("\n");
	}
}

//随机生成雷
void Mine_set(char board[ROWS][COLS], int row, int col)
{
	int count = easy_mode;
	while (count > 0)
	{
		int x = rand() % row + 1;
		int y = rand() % col + 1;
		if (board[x][y] == '0')
		{
			board[x][y] = '1';
			count--;
		}
	}
}

//判断周围雷的个数
int get_mine_amount(char mine[ROWS][COLS], int x, int y)
{
	return mine[x - 1][y - 1] + mine[x][y - 1] + mine[x + 1][y - 1]
		+ mine[x - 1][y] + mine[x + 1][y]
		+ mine[x - 1][y + 1] + mine[x][y + 1] + mine[x + 1][y + 1]
		- 8 * '0';
}

//排雷
void Mine_sweep(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int win = 0;
	while (win < row * col - easy_mode)
	{
		printf("请输入排查的坐标:");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (mine[x][y] == '1')
			{
				printf("你被炸死了,游戏结束\n");
				Display_board(mine, ROW, COL);
				break;
			}
			else
			{
				int n = get_mine_amount(mine, x, y);//判断周围雷的个数
				show[x][y] = n + '0';
				win++;
				Display_board(show, ROW, COL);
			}
		}
		else
		{
			printf("超出范围,请重新输入\n");
		}
	}
	if (win == row * col - easy_mode)
	{
		printf("恭喜你,获得胜利\n");
		Display_board(mine, ROW, COL);
	}
}

总结

本项目基本实现了扫雷游戏,但仍旧存在较大的修改空间,例如利用递归实现选中格子之后的展开功能……

标签:COLS,ROWS,项目,int,mine,C语言,char,扫雷,board
来源: https://blog.csdn.net/m0_61166151/article/details/122030977