【C语言】实现简单的多功能扫雷游戏

该博客详细介绍了如何使用C语言在命令行界面实现扫雷游戏的主要功能,包括设置雷区、显示游戏界面、玩家标记和排雷、检查胜利条件等。通过输入坐标进行操作,游戏具有标记、取消标记及退出等功能。代码结构清晰,逻辑严谨。
摘要由CSDN通过智能技术生成

一、浅谈扫雷游戏的功能和实现

  通过C语言,在命令台中,通过菜单显示,输入相应的序号实现相应的功能,
并且根据经典扫雷游戏,实现以下功能

  1. 通过数组的下标输入,实现排雷的位置,如果周围有雷,那么排雷的位置将显示雷的数目。
  2. 如果踩到雷,将会显示其它雷并且结束游戏。
  3. 有标记功能,也能取消标记,并且限定标记的数目。
  4. 如果扫雷的位置周围没有雷,那么可以对整个位置制空。

在这里插入图片描述在这里插入图片描述

二、扫雷功能的实现

1、测试页和头文件的准备

测试页Test.c,其中包括菜单和实现菜单里的部分功能。

//Test.c
#include"game.h"

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

//进入game的菜单,因为每次都要选择需要标记,还是扫雷,还是取消标记
void game()
{
	char mine[ROWS][COLS] = { 0 }; //棋盘记录 雷('1')和非雷('0')的位置
	char show[ROWS][COLS] = { 0 }; //显示的棋盘
	char set[ROWS][COLS] = { 0 }; //记录的棋盘 记录有无排雷和有无标记

	InitBoard(mine, '0');
	InitBoard(show, '*');
	InitBoard(set, '*');

	SetMine(mine, ROW, COL);	
	DisplayBoard(mine, ROW, COL);
	DisplayBoard(show, ROW, COL);

	int input = 0;
	int win = 0;
	int mark = 0; //记录标记数
	do {
		printf("【1、进入标记功能   2、进入排雷过程   3、取消标记功能   0、退出】\n\n");
		printf("请输入:");
		scanf("%d", &input);

		switch (input)
		{
		case 1:
			Mark(show, set, ROW, COL, &mark);
			break;

		case 2:
			DisplayBoard(show, ROW, COL); //先打印显示的扫雷盘
			FindMine(show, mine, set, ROW, COL, &input); //然后进入扫雷功能
			win = CheckNum(show, ROW, COL); 
			if (ROW * COL - EASY_COUNT == win)
			{
				printf("游戏获胜!\n");
				input = 0;
			}
			break;

		case 3:
			DelMark(show, set, ROW, COL, &mark);
			break;

		case 0:
			system("cls");
			break;

		default:
			printf("输入错误,请重新输入。\n");
			break;
		}

	} while (input);
}


int main()
{
	int input = 0;
	srand((unsigned int)time(NULL));
	do {
		menu();
		printf("请输入:");
		scanf("%d", &input);

		switch (input)
		{
		case 0:
			printf("退出成功。\n");
			break;
		case 1:
			game();
			break;
		default:
			printf("输入错误,请重新输入。\n");
			break;
		}

	} while (input);
	return 0;
}

头文件game.h

//game.h
#include <stdio.h>
#include <time.h>

//显示的扫雷盘行列
#define ROW 9
#define COL 9

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

//雷的数量
#define EASY_COUNT 10

//初始化数组
void InitBoard(char board[ROWS][COLS],char set);

//打印扫雷盘
void DisplayBoard(char board[ROWS][COLS], int row, int col);

//设置雷的个数
void SetMine(char board[ROWS][COLS], int row, int col);

//如何找到雷以及找到雷的反应
void FindMine(char show[ROWS][COLS], char mine[ROWS][COLS], char set[ROWS][COLS], int row, int col, int* input);

//扫雷位置周围没雷的制空
void set_blank(char show[ROWS][COLS], char set[ROWS][COLS], char mine[ROWS][COLS], int x, int y);

//标记功能
void Mark(char show[ROWS][COLS], char set[ROWS][COLS], int row, int col, int* mark);

//取消标记
void DelMark(char show[ROWS][COLS], char set[ROWS][COLS], int row, int col, int* mark);

//判断输赢的计数
int CheckNum(char show[ROWS][COLS], int x, int y);

下面实现具体的功能

2、初始化、打印和定义雷的数目功能实现

在这里插入图片描述
一个专门储存雷的数组雷盘,和一个供用户操作的数组雷盘

//game.c
//初始化
void InitBoard(char board[ROWS][COLS],char set)
{
	int i = 0, j = 0;
	for (i = 0; i < ROWS; i++)
	{
		for (j = 0; j < COLS; j++)
		{
			board[i][j] = set;
		}
	}
	
}

//打印扫雷盘
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
	printf("\n\n\t扫雷\n\n");
	int i = 0, j = 0;
	//为了方便看扫雷盘的横纵坐标位置,先打印一行的纵坐标数
	for (i = 0; i <= col; i++)
	{
		printf("%d ", i);
	}
	printf("\n");
	
	
	for (i = 1; i <= row; i++)
	{
		printf("%d ", i);//打印一列的行坐标数
		for (j = 1; j <= col; j++)
		{
			printf("%c ", board[i][j]); //打印扫雷盘的字符
		}
		printf("\n");
	}
	printf("\n\n");
}

//设置雷的个数
void SetMine(char board[ROWS][COLS], int row, int col)
{
	int count = EASY_COUNT;

	while (count)
	{
		int x = rand() % row + 1;
		int y = rand() % col + 1;
		if (board[x][y] == '0')
		{
			board[x][y] = '1';
			count--;
		}
		
	}
}

3、排雷功能的实现

在这里插入图片描述

//game.c
//排雷功能的实现
void FindMine(char show[ROWS][COLS], char mine[ROWS][COLS], char set[ROWS][COLS], int row, int col ,int* input)
{
		int x = 0, y = 0;
		printf("请输入坐标:");
		scanf("%d%d", &x, &y);
		while (show[x][y] != '*' && show[x][y]!='!' && x < 1 || y < 1 || x > row || y > col)
		{
			printf("输入错误,请重新输入.\n");
			scanf("%d%d", &x, &y);
		}

		if (mine[x][y] == '1')
		{
			/*system("cls");*/
			DisplayBoard(mine, ROW, COL);
			printf("踩到雷了,游戏结束!\n");
			(*input) = 0;
			return;
		}

		//排雷的位置,以及展开
		if (show[x][y] == '*' || show[x][y]=='!')//为*和已经标记了的位置!,都可以进行排雷
		{
			/*system("cls");*/
			set_blank(show, set, mine, x, y);//进入制空
			DisplayBoard(show, ROW, COL);
		}
}

//在排雷的过程中,对制空和排雷位置计数的实现
void set_blank(char show[ROWS][COLS], char set[ROWS][COLS], char mine[ROWS][COLS], int x, int y)
{
	//防止越界
	if (x<1 || x>ROW || y<1 || y>COL)
	{
		return;
	}

	//防止分布过多空白
	if (mine[x][y] == '1')
	{
		return;
	}

	int i = 0, j = 0;
	int count = get_mine_count(mine, x, y);

	//如果周围八个不为0,这个点直接计雷数
	if (count != 0)
	{
		show[x][y] = count + '0';
		set[x][y] = '#'; //表示已经排过雷
	}

	//周围为0制空,以及递归遍历
	if (count == 0)
	{
		for (i = x - 1; i <= x + 1; i++)
		{
			for (j = y - 1; j <= y + 1; j++)
			{
				//排过雷就跳过
				if (set[i][j] == '#')
				{
					continue;
				}
				show[i][j] = ' ';
				set[i][j] = '#';
				set_blank(show, set, mine, i, j);
			}
		}
	}
}

//因为是字符,所以在对排雷位置周围8个位置计数时,需要减去8个'0'得到int类型数。
int get_mine_count(char mine[ROWS][COLS], 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';
}

//输赢检查除雷数的其它字符个数
int CheckNum(char show[ROWS][COLS], int x, int y)
{
	int count = 0;
	for (int i = 1; i <= x; i++)
	{
		for (int j = 1; j <= y; j++)
		{
			if (show[i][j] != '*')
			{
				count++;
			}
		}
	}
	return count;
}

4、标记、和取消标记的实现

在这里插入图片描述
在这里插入图片描述

void Mark(char show[ROWS][COLS],char set[ROWS][COLS], int row, int col,int* mark)
{
	if ((*mark) > EASY_COUNT)
	{
		printf("已超出最大标记数。\n");
		return;
	}
	
	int x = 0, y = 0;
	printf("请输入需要标记的位置:");
	scanf("%d%d", &x, &y);
	while(set[x][y] == '#')
	{
		printf("标记位置错误,请重新输入\n");
		scanf("%d%d", &x, &y);
	}
	
	system("cls");
	set[x][y] = show[x][y];//保存一下标记前的字符,取消的时候恢复
	show[x][y] = '!';
	(*mark)++;
	DisplayBoard(show, ROW, COL);

}

void DelMark(char show[ROWS][COLS], char set[ROWS][COLS], int row, int col, int* mark)
{
	if ((*mark) == 0)
	{
		printf("无标记。\n");
		return;
	}
	int x = 0, y = 0;
	printf("请输入需要取消标记的位置:");
	scanf("%d%d", &x, &y);
	while (show[x][y] != '!')
	{
		printf("选择取消标记位置错误,请重新输入\n");
		scanf("%d%d", &x, &y);
	}
	system("cls");
	show[x][y] = set[x][y];
	set[x][y] = '*';
	DisplayBoard(show, ROW, COL);
}

5、效果展示

在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值