c语言实现扫雷游戏

  • 分析
    1. 玩法
      扫雷就是要把所有非地雷的格子揭开即胜利;踩到地雷格子就算失败。
      游戏主区域由很多个方格组成。使用鼠标左键随机点击一个方格,方格即被打开并显示出方格中的数字;方格中数字则表示其周围的8个方格隐藏了几颗雷;如果点开的格子为空白格,即其周围有0颗雷,则其周围格子自动打开;如果其周围还有空白格,则会引发连锁反应;在你认为有雷的格子上,点击右键即可标记雷;如果一个已打开格子周围所有的雷已经正确标出,则可以在此格上同时点击鼠标左右键以打开其周围剩余的无雷格。
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
  • 思路
    • 注意事项
      我们使用控制台实现扫雷时,就不能使用鼠标点击,所以通过输入坐标以实现点击操作,右键标记暂不实现
    • 游戏流程
      1. 选择菜单打印,人机交互
      2. 开始游戏
      3. 地图和雷阵初始化
        • 地图初始化为 “*”
        • 雷阵初始化为“0”
        • 坐标随机数布雷为 “x”
      4. 打印地图
      5. 玩家输入坐标点击方块(while循环)
        • 判断输入坐标越界,如果越界重新输入
        • 判断输入坐标是否踩雷,如果踩雷游戏结束
        • 判断剩余雷数是否为开始布置雷数,如果相等则游戏结束游戏成功
        • 每输入一次更新地图
          • 点击一个方格,方格即被打开并显示出方格中的数字,数字表示该格子四周雷数
          • 如果点开的格子为空白格,即其周围有0颗雷,则其周围格子自动打开;如果其周围还有空白格,则会引发连锁反应
        • 更新地图后显示地图
  • 实现
    • 宏定义
      #define ROW 10 //行
      #define COL 10 //列
      #define MINE_NUMBER 10 //列数
      
      后面列数和行数都会加2,将地图设置围墙,防止越界.避免越界检测。
    • 菜单
      void Menu() {
      	printf("--------------\n");
      	printf(" 1. 开始游戏\n");
      	printf(" 0. 退出游戏\n");
      	printf("--------------\n");
      	int choice;
      	scanf("%d", &choice);
      	if (choice == 1)
      	{
      		GameStart();
      	}
      }
      
    • 开始游戏
      void GameStart() {
      	char map[ROW + 2][COL + 2];
      	char mineMap[ROW + 2][COL + 2];
      	// 1.地图初始化
      	mapInit(map, mineMap);
      	// 2.打印地图
      	displayMap(map);
      	// 3.玩家点击地图
      	clickBlock(map, mineMap);
      }
      
    • 地图初始化
      	//初始化地图
      void mapInit(char map[ROW + 2][COL + 2], 
      	char mineMap[ROW + 2][COL + 2]) {
      
      	for (int row = 0; row < ROW + 2; row++)
      	{
      		for (int col = 0; col < COL + 2; col++) {
      			map[row][col] = '*';
      		}
      	}
      	for (int row = 0; row < ROW + 2; row++)
      	{
      		for (int col = 0; col < COL + 2; col++) {
      			mineMap[row][col] = '0';
      		}
      	}
      	srand((unsigned int)time(0));
      	//随机布雷
      	int count = MINE_NUMBER;
      	while (count > 0)
      	{
      		int row = rand() % 10 + 1;
      		int col = rand() % 10 + 1;
      		if (mineMap[row][col] == 'x')
      		{
      			continue;
      		}
      		mineMap[row][col] = 'x';
      		count--;
      	}
      }
      
    • 打印地图
      //打印地图
      void displayMap(char map[ROW + 2][COL + 2]) {
      	printf("   ");
      	for (int i = 1; i < COL + 1; i++)
      	{
      		printf("%d ", i);
      	}
      	printf("\n");
      	for (int i = 1; i < COL; i++)
      	{
      		printf("---");
      	}
      	printf("\n");
      	for (int row = 1; row < ROW + 1; row++)
      	{
      		printf("%02d ", row);
      		for (int col = 1; col < COL + 1; col++)
      		{
      			printf("%c ", map[row][col]);
      		}
      		printf("\n");
      	}
      	printf("\n");
      }
      
    • 玩家点击方块
      //点击方块
      void clickBlock(char map[ROW + 2][COL + 2], 
      char mineMap[ROW + 2][COL + 2]) {
      
      while (1)
      {
      	int row, col;
      	printf("请输入坐标\n");
      	scanf("%d %d", &row, &col);
      	if (row < 1 || row > ROW || col < 1 || col > COL)
      	{
      		printf("输入错误!,请重新输入\n");
      		continue;
      	}
      	if (mineMap[row][col] == 'x')
      	{
      		printf("游戏结束,踩到雷了!\n");
      		displayMap(mineMap);
      		break;
      	}
      	if (reminderMine(map) == MINE_NUMBER)
      	{
      		printf("通关了!\n");
      		displayMap(mineMap);
      		break;
      	}
      	updateMap(map, mineMap, row, col);
      	displayMap(map);
      }
      }
      
    • 剩余雷数检查
      // 剩余地雷
      int reminderMine(char map[ROW + 2][COL + 2])//判断剩余未知区域的个数,个数为雷数时玩家赢
      {
      	int count = 0;
      	for (int row = 1; row < ROW + 1; row++)
      	{
      		for (int col = 1; col < COL + 1; col++) {
      			if (map[row][col] == '*')
      			{
      				count++;
      			}
      		}
      	}
      	return count;
      }
      
    • 地图更新
      // 更新地图
      void updateMap(char map[ROW + 2][COL + 2],
      	char mineMap[ROW + 2][COL + 2], int row, int col) {
      	if (checkAround(mineMap, row, col) != 0)
      	{
      		map[row][col] = checkAround(mineMap, row, col) + '0';
      	}
      	else
      	{
      		openMore(map, mineMap, row, col);
      	}
      }
      
    • 空白格周围展开并连锁反应
      八个方向检测格子中是否为“0”,如果为零继续延伸检测,直到有雷该方向停止检测,递归检测.不为零设置被打开格子附近雷数
      void openMore(char map[ROW + 2][COL + 2],
      char mineMap[ROW + 2][COL + 2], int row, int col) {
      	if (map[row][col] == '*' && mineMap[row][col] == '0')
      	{
      		map[row][col] = checkAround(mineMap, row, col) + '0';
      	}
      	//上
      	if (mineMap[row - 1][col] == '0' && map[row - 1][col] == '*')
      	{
      		map[row - 1][col] = checkAround(mineMap, row - 1, col) + '0';
      		if (checkAround(mineMap, row - 1, col) == 0)
      		{
      			openMore(map, mineMap, row - 1, col);
      		}
      	}
      	//下
      	if (mineMap[row + 1][col] == '0' && map[row + 1][col] == '*')
      	{
      		map[row + 1][col] = checkAround(mineMap, row + 1, col) + '0';
      		if (checkAround(mineMap, row + 1, col) == 0)
      		{
      			openMore(map, mineMap, row + 1, col);
      		}
      	}
      	//左
      	if (mineMap[row][col - 1] == '0' && map[row][col - 1] == '*')
      	{
      		map[row][col - 1] = checkAround(mineMap, row, col - 1) + '0';
      		if (checkAround(mineMap, row, col - 1) == 0)
      		{
      			openMore(map, mineMap, row, col - 1);
      		}
      	}
      	//右
      	if (mineMap[row][col + 1] == '0' && map[row][col + 1] == '*')
      	{
      		map[row][col + 1] = checkAround(mineMap, row, col + 1) + '0';
      		if (checkAround(mineMap, row, col + 1) == 0)
      		{
      			openMore(map, mineMap, row, col + 1);
      		}
      	}
      	// 东北
      	if (mineMap[row - 1][col + 1] == '0' && map[row - 1][col + 1] == '*')
      	{
      		map[row - 1][col + 1] = checkAround(mineMap, row - 1, col + 1) + '0';
      		if (checkAround(mineMap, row - 1, col + 1) == 0)
      		{
      			openMore(map, mineMap, row - 1, col + 1);
      		}
      	}
      	// 西北
      	if (mineMap[row - 1][col - 1] == '0' && map[row - 1][col - 1] == '*')
      	{
      		map[row - 1][col - 1] = checkAround(mineMap, row - 1, col - 1) + '0';
      		if (checkAround(mineMap, row - 1, col - 1) == 0)
      		{
      			openMore(map, mineMap, row - 1, col - 1);
      		}
      	}
      	// 东南
      	if (mineMap[row + 1][col + 1] == '0' && map[row + 1][col + 1] == '*')
      	{
      		map[row + 1][col + 1] = checkAround(mineMap, row + 1, col + 1) + '0';
      		if (checkAround(mineMap, row - 1, col) == 0)
      		{
      			openMore(map, mineMap, row + 1, col + 1);
      		}
      	}
      	// 西南
      	if (mineMap[row + 1][col - 1] == '0' && map[row + 1][col - 1] == '*')
      	{
      		map[row + 1][col - 1] = checkAround(mineMap, row + 1, col - 1) + '0';
      		if (checkAround(mineMap, row + 1, col - 1) == 0)
      		{
      			openMore(map, mineMap, row + 1, col - 1);
      		}
      	}
      }
      
    • 四周环境检测 并返回周围雷数
      // 检查周围环境
      int checkAround(char mineMap[ROW + 2][COL + 2], 
      	int row, int col) {
      
      	int count = 0;
      	//上
      	if (mineMap[row - 1][col] == 'x')
      	{
      		count++;
      	}
      	//下
      	if (mineMap[row + 1][col] == 'x')
      	{
      		count++;
      	}
      	//左
      	if (mineMap[row][col - 1] == 'x')
      	{
      		count++;
      	}
      	//右
      	if (mineMap[row][col + 1] == 'x')
      	{
      		count++;
      	}
      	// 东北
      	if (mineMap[row - 1][col + 1] == 'x')
      	{
      		count++;
      	}
      	// 西北
      	if (mineMap[row - 1][col - 1] == 'x')
      	{
      		count++;
      	}
      	// 东南
      	if (mineMap[row + 1][col + 1] == 'x')
      	{
      		count++;
      	}
      	// 西南
      	if (mineMap[row + 1][col - 1] == 'x')
      	{
      		count++;
      	}
      	return count;
      }
      

写在最后

最近推出了公众号 coding趣谈,一位在读学生的技术提升之路,为您提供一系列我在学习路上的笔记,经验,以及感悟。往与君共勉,共同进步! 欢迎大家来关注哦!
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值