扫雷游戏的C程序实现

//扫雷游戏实现

1. 设定一个二维数组,作为表示地雷的地图,0表示没地雷,1表示有雷
2. 设定另一个二维数组,作为给玩家看的地图,位置是否被翻开,翻开后显示周围地雷数。
3. 地图初始化(包含布置地雷的过程)。
4. 输入坐标,并对输入进行合理化检查。
5. 判断翻开位置(包括有雷游戏结束,没雷翻开,显示周围有雷数)。

代码如下

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#define ROW 9
#define COL 9
#define MINE_COUNT 10

char mine_map[ROW + 2][COL + 2];
char show_map[ROW + 2][COL + 2];
//ROW + 2 棋盘边框,内容从1--10存放。就不要考虑row和col输入溢出问题

int Menu(int i)//菜单函数,实现游戏开始或者直接退出结束游戏
{
	printf("================\n");
	printf("1. PLAY GAME!\n");
	printf("2. EXIT GAME!\n");
	printf("================\n");
	printf("请输入您的选择:");
	scanf("%d", &i);
	return i;
}

void Init(char mine_map[ROW + 2][COL + 2], 
		  char show_map[ROW + 2][COL + 2])
		  //初始化函数,把两个棋盘初始化为‘0’和‘*’
		  //
{
	int mine_count = 0;
	//memset()函数对一段连续的空间进行赋值操作
	memset(mine_map, '0', (ROW + 2) * (COL + 2));
	memset(show_map, '*', (ROW + 2) * (COL + 2));
	//等效代码如下
	//给mine_map初始化布雷
	//int row, col;
	//int mine_count;
	//for(row = 0; row < ROW + 2; ++row)
	//{
	//	for(col = 0; col < COL + 2; ++col)
	//	{
	//		mine_map[row][col] = '0';
	//	}
	//}
	2. show_map 初始化全为 ‘*’
	//for(row = 0; row < ROW + 2; ++row)
	//{
	//	for(col = 0; col < COL + 2; ++col)
	//	{
	//		show_map[row][col] = '*';
	//	}
	//}
	mine_count = MINE_COUNT;
	while(mine_count > 0)
	{
		int row, col;
		//开始布雷,随机给雷
		row = rand() % ROW + 1;
		col = rand() % COL + 1;
		if(mine_map[row][col] == '1')
		{
			continue;
		}
		mine_map[row][col] = '1';
		mine_count--;
	}
}

void Displaymap(char map[ROW + 2][COL + 2])
//打印棋盘边框打印成1--9,内部空间9*9
{
	int row, col;
	printf("    ");
	for(col = 1; col <= COL; col++)
	{
		printf("%d ", col);
	}
	printf("\n");
	//第一行打印完了
	//接下来打印上边框
	for(col = 1; col <= COL; col++)
	{
		printf("___");
	}
	printf("\n");
	//打印每一行,注意每一行前要带上行号
	for(row = 1; row <= ROW; ++row)
	{
		printf("  %d|", row);
		for(col = 1; col <= COL; ++col)
		{
			printf("%c ", map[row][col]);
		}
		printf("\n");
	}
}

int UpdateShowmap(char mine_map[ROW + 2][COL + 2], 
		  char show_map[ROW + 2][COL + 2], int row, int col)
{
	//把当前位置替换为一个数字(数字表示这个位置周围八个格子有雷的个数)
	int mine_count = 0;
	mine_count = mine_map[row - 1][col - 1] - '0'
		       + mine_map[row - 1][col] - '0'
		       + mine_map[row - 1][col + 1] - '0'
		       + mine_map[row][col - 1] - '0'
		       + mine_map[row][col + 1] - '0'
		       + mine_map[row + 1][col - 1] - '0'
		       + mine_map[row + 1][col] - '0'
		       + mine_map[row + 1][col + 1] - '0';
	//show_map[row][col] = mine_count + '0';
	return mine_count;
}

int show_not_open_count(char show_map[ROW + 2][COL + 2], int row, int col)
//计算棋盘上还没有打开的‘*’的个数 
//判断当返回数 count = MINE_COUNT时 游戏结束,玩家胜
//ROW + 2, COL + 2 当row - 1时就不用考虑溢出的问题
{
	int count = 0;
	for(row = 1; row <= ROW; ++row)
	{
		for(col = 1; col <= COL; ++col)
		{
			if(show_map[row][col] == '*')
			{
				count++;
			}
		}
	}
	return count;
}

void Open_around_not_mine(char mine_map[ROW + 2][COL + 2], 
		  char show_map[ROW + 2][COL + 2], int row, int col)
		 //判断打开的位置周八个格子的周围总共有多少雷数,并赋予该位置周围雷数显示 
{
	if(mine_map[row - 1][col - 1] == '0')
	{
		show_map[row - 1][col - 1] =
			//计算show_map[row - 1][col - 1]周围的雷数
			UpdateShowmap(mine_map, show_map, row - 1, col - 1) + '0';
	}
	if(mine_map[row - 1][col] == '0')
	{
		show_map[row - 1][col] = 
			UpdateShowmap(mine_map, show_map, row - 1, col) + '0';
	}
	if(mine_map[row - 1][col + 1] == '0')
	{
		show_map[row - 1][col + 1] = 
			UpdateShowmap(mine_map, show_map, row - 1, col + 1) + '0';
	}
	if(mine_map[row][col - 1] == '0')
	{
		show_map[row][col - 1] = 
			UpdateShowmap(mine_map, show_map, row, col - 1) + '0';
	}
	if(mine_map[row][col + 1] == '0')
	{
		show_map[row][col + 1] = 
			UpdateShowmap(mine_map, show_map, row, col + 1) + '0';
	}
    if(mine_map[row + 1][col - 1] == '0')
	{
		show_map[row + 1][col - 1] = 
			UpdateShowmap(mine_map, show_map, row + 1, col - 1) + '0';
	}
	if(mine_map[row + 1][col] == '0')
	{
		show_map[row + 1][col] = 
			UpdateShowmap(mine_map, show_map, row + 1, col) + '0';
	}
	if(mine_map[row + 1][col + 1] == '0')
	{
		show_map[row + 1][col + 1] = 
			UpdateShowmap(mine_map, show_map, row + 1, col + 1) + '0';
	}
}

void Game()
{
	//char mine_map[ROW + 2][COL + 2];
	//char show_map[ROW + 2][COL + 2];
	clock_t start_time, finish_time;
	//clock tick不是CPU的一个时钟周期,而是C/C++的一个基本计时单位
	double deadline;
	Init(mine_map, show_map);
	Displaymap(show_map);
	start_time = clock();//记录开始时间
	//clock() 函数,返回从开启这个程序进程程序中调用clock()
	//函数时之间的CPU时钟计时单元(clock tick)数(挂钟时间),返回单位是毫秒
	while(1)
	{
		int row = 0;
		int col = 0;
		int not_mine_count = 0;
		int is_mine_count = 0;
		printf("请输入您要翻开的位置[row, col]:");
		scanf("%d %d", &row, &col);
		//判断输入坐标的合法性
		if(row < 1 || row > ROW ||col < 1 || col > COL)
		{
			printf("您输入的位置不合法,请重新输入!\n");
			continue;
		}
		if(mine_map[row][col] == '1')
		{
			printf("您踩雷了,游戏结束!        ");
			finish_time = clock();//取结束时间
			deadline = (double)(finish_time - start_time) / CLOCKS_PER_SEC;
			//可以用常量CLOCKS_PER_SEC, 这个常量表示每一秒(per second)有多少个时钟计时单元
			printf("用时 %f 秒\n", deadline);
			Displaymap(mine_map);
			break;
		}
		//计算翻开位置不是雷的数量
		not_mine_count = UpdateShowmap(mine_map, show_map, row, col);
		//赋予翻开位置周围的总共的雷数
		show_map[row][col] = not_mine_count + '0';
		//翻开输入位置周围的八个位置,并计算出这八个位置周围的雷数并显示
		Open_around_not_mine(mine_map, show_map, row, col);
		Displaymap(show_map);
		is_mine_count = show_not_open_count(show_map, row, col);
		//计算棋盘上剩余没翻开的格子的个数
		if(is_mine_count ==  MINE_COUNT)
			//玩家棋盘的*数等于 雷阵上的雷数时
		{
			printf("恭喜您,扫雷成功!      ");
			finish_time = clock();//取结束时间
			deadline = (double)(finish_time - start_time) / CLOCKS_PER_SEC;
			printf("用时 %f 秒\n", deadline);
			Displaymap(show_map);
			break;
		}
	}
}

int main()
{
	int choice = 0;
	srand((unsigned int)time(0));
	while(1)
	{
	    choice = Menu(choice);
	    if(choice == 1)
	    {
		    Game();
	    }
	    else
	    {
		    printf("GOOD BYE!\n");
			break;
	    }
	}
	system("pause");
	return 0;
}

运行结果演示:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值