C语言-扫雷

完整扫雷

请添加图片描述

1. 说明

扫雷大家应该都知道,翻开一个格子,显示的数字就是周围 8 格所含的雷数。例如,红色框框里的 1 周围 8 格就只有一个雷。

2. 思路

  1. 我们定义两个数组来实现,show 数组存放玩家看到的棋盘,mine 数组存放隐藏的雷盘

  2. 这两个数组搭配使用,就能计算某个位置周围的雷数,并且修改 show 数组来显示这个位置的雷数。

请添加图片描述

  1. 但是如果计算边缘格子周围的雷数时,数组会越界。

  2. 我们只要在周围留一圈就能解决这个问题

    • 如下图所示,假设我们要玩 9x9 的大小,我们的数组大小就定义为 11x11

请添加图片描述

3. 各个功能实现

3.1 雷盘初始化与打印

1)雷盘定义

请添加图片描述

扫描二维码关注公众号,回复: 14723498 查看本文章

请添加图片描述

  1. 初始化雷盘
  2. 初始化 show,mine 两个数组,show 存放 ‘*’ , mine 存放 ‘0’
void init_board(char board[ROWS][cols], int rows, int cols, char set)
{
    
    
int i = 0;
int j = 0;
for (i = 0; i < rows; i++)
{
    
    
for (j = 0; j < cols; j++)
{
    
    
board[i][j] = set;
}
}
}
打印雷盘
//打印 show 雷盘

void display_board(char board[ROWS][cols], int row, int col)
{
    
    
int i = 0;
int j = 0;

    //这里打印上面一行数字
    printf("|");
    for (j = 0; j <= col; j++)
    {
    
    
    	printf(" %-2d |", j);
    }
    printf("\n");


    for (i = 1; i <= row; i++)
    {
    
    
    	printf("|");
    	for (j = 0; j <= col; j++)
    	{
    
    
    		printf("----|");//打印两行之间的分割线
    	}
    	printf("\n");

    	printf("|");
    	printf(" %-2d |", i);//打印左边一列数字

    	for (j = 1; j <= col; j++)
    	{
    
    
    		printf(" %2c |",board[i][j]);//打印show数组

    	}
    	printf("\n");
    }

}

效果图:

请添加图片描述

2) 随机布置雷

  1. 随机布置雷,将 mine 中的 ‘0’ 改为 ‘1’

  2. 随机布置雷,在 mine 数组里随机设置 COUNT 个雷

void set_mine(char mine[ROWS][cols], int row, int col)
{
    
    
int count = COUNT;
while (count)
{
    
    
int x = rand() % row + 1;
int y = rand() % col + 1;

    	if (mine[x][y] == '0')
    	{
    
    
    		mine[x][y] = '1';  //地雷设置为 '1'
    		count--;
    	}
    }
}

3.2 玩家排查雷

1) 获取坐标周围雷数

1… 计算该坐标在 mine 中 周围 '1’的个数
2… 获取一个格子周围的雷数

int get_mine_count(char mine[ROWS][cols], int x, int y)
{
    
    
//mine 中存放的是字符'0' 和 '1'
return (mine[x][y + 1] +
mine[x - 1][y + 1] +
mine[x - 1][y] +
mine[x - 1][y - 1] +
mine[x][y - 1] +
mine[x + 1][y - 1] +
mine[x + 1][y] +
mine[x + 1][y + 1] - 8 \* '0');
}

2) 递归展开

请添加图片描述

  1. 我们玩扫雷时,翻开一个格子会展开一片,如上图所示,翻开黑格子,展开紫色区域。
  2. 我们可以用递归来实现
  3. 当这个格子周围没雷时,显示空白,然后继续递归它周围的八个格子
  4. 有雷时,显示雷数,停止递归。
void expand(char mine[ROWS][cols], char show[ROWS][cols], int x, int y, int\* win)
{
    
    

    if (x >= 1 && x <= ROW && y >= 1 && y <= COL) //限制在棋盘内展开,防止越界
    {
    
    
    	int count = get_mine_count(mine, x, y);//获取雷数

    	if (count == 0) //四周没雷,进入递归展开
    	{
    
    
    		show[x][y] = ' ';//四周没雷的改为 空格  ' '


    		int i = 0;
    		//向四周共8个位置递归
    		for (i = x - 1; i <= x + 1; i++)
    		{
    
    
    			int j = 0;
    			for (j = y - 1; j <= y + 1; j++)
    			{
    
    

    				//只对 '*' 进行展开,防止死循环
    				if (show[i][j] == '*')
    				{
    
    
    					expand(mine, show, i, j, win);
    				}

    			}
    		}
    	}
    	else   //四周有雷显示雷数
    	{
    
    
    		show[x][y] = count + '0';
    	}

    	//记录展开的数量
    	(*win)++;
    }
}

3)胜负判断

  1. 这里定义了一个 win 来表示翻开的格子数,当翻开的格子数量 = 行 x 列 - 雷数 ===> 排雷成功。
  2. 玩家排查雷
void find_mine(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 - COUNT)//当翻开的格子数量 = 行 x 列 - 雷数 ===> 排雷成功
    {
    
    
    	printf("请输入要排查的坐标:>");
    	scanf("%d %d", &x, &y);

    	//检查坐标是否越界
    	if (x >= 1 && x <= row && y >= 1 && y <= col)
    	{
    
    

    		//检查坐标是否排查过了
    		if (show[x][y] == '*')
    		{
    
    

    			if (mine[x][y] == '1')
    			{
    
    
    				system("cls");
    				show_mine(mine, show, row, col);
    				printf("-----------很遗憾,你被炸死了-----------\n");
    				break;
    			}
    			else
    			{
    
    
    				//展开
    				expand(mine, show, x, y, &win);

    				system("cls");//清屏
    				display_board(show, row, col);
    				printf("--------------还需翻开%d格--------------\n", row * col - COUNT - win);
    			}
    		}
    		else
    		{
    
    
    			printf("该坐标已排查,请重新输入\n");
    		}
    	}
    	else
    	{
    
    
    		printf("坐标非法,请重新输入\n");
    	}
    }

    if (win == row* col - COUNT)
    {
    
    
    	system("cls");
        show_mine(mine, show, row, col);//展示地雷位置
        printf("------------恭喜你,排雷成功-----------\n");
    }

}

3) 显示雷位置

显示地雷位置,排雷成功或被炸死后 向玩家展示地雷位置

void show_mine(char mine[ROWS][cols], char show[ROWS][cols], int row, int col)
{
    
    
int i = 0;
for (i = 1; i <= row; i++)
{
    
    
int j = 0;
for (j = 1; j <= COL; j++)
{
    
    
if (mine[i][j] == '1')
{
    
    
show[i][j] = '@'; //将地雷改成 '@'
}
}
}
display_board(show, row, col); //打印
}

4. 游戏试玩

  1. 游戏设置 10 行 ,10 列 ,15 个雷
游戏设置
开始菜单
开始排雷
排雷
  1. 排雷成功

请添加图片描述

  1. 排雷失败

请添加图片描述

5. 游戏完整代码

game.h

头文件 常量定义,函数声明

#pragma once

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

//玩家看到的大小
#define ROW 10
#define COL 10

//实际数组大小,防止越界
#define ROWS ROW+2
#define COLS COL+2

#define COUNT 10//雷数

//初始化棋盘
void init_board(char board[ROWS][cols], int rows, int cols, char set);

//打印棋盘
void display_board(char board[ROWS][cols], int row, int col);

//随机布置雷
void set_mine(char mine[ROWS][cols], int row, int col);

//获取坐标周围地雷数
int get_mine_count(char mine[ROWS][cols], int x, int y);

//显示地雷位置并打印
void show_mine(char mine[ROWS][cols], char show[ROWS][cols], int row, int col);

//递归展开
void expand(char mine[ROWS][cols], char show[ROWS][cols], int x, int y, int\* win);

//排查雷
void find_mine(char mine[ROWS][cols],char show[ROWS][cols],int row, int col);

test.c

游戏测试文件

#define \_CRT_SECURE_NO_WARNINGS 1

#include "game.h"

//菜单
void menu()
{
    
    
printf("======================\n");
printf("|| 扫雷 ||\n");
printf("|| 1-开始游戏 ||\n");
printf("|| 0-退出游戏 ||\n");
printf("======================\n");
}

//游戏流程
void game()
{
    
    
char mine[ROWS][cols] = {
    
     0 };//存放布置的雷(隐藏的)
char show[ROWS][cols] = {
    
     0 };//存放排查的雷(游戏看到的)

    //初始化棋盘
    //mine 全为'0'
    //show 全为'*'
    init_board(mine, ROWS, COLS, '0');
    init_board(show, ROWS, COLS, '*');

    //随机布置雷
    set_mine(mine,ROW,COL);

    //打印棋盘
    //display_board(mine, ROW, COL);
    display_board(show, ROW, COL);
    printf("--------------需要翻开%d格--------------\n", ROW * COL - COUNT);

    //排查雷(游戏开始)
    find_mine(mine, show, ROW, COL);

}

int main()
{
    
    
int input = 0;
srand((unsigned int)time(NULL));

    do
    {
    
    
    	menu();
    	printf("请选择:>");
    	scanf("%d", &input);
    	switch (input)
    	{
    
    
    	case 1:
    		system("cls");
    		game();
    		break;
    	case 0:
    		printf("退出游戏\n");
    		break;
    	default:
    		printf("选择错误,请重新输入\n");
    		break;
    	}
    } while (input);

    return 0;

}

game.c

函数定义

#define \_CRT_SECURE_NO_WARNINGS 1

#include "game.h"

//将两个数组初始化,show 全为'\*' ,mine 全为'0'

void init_board(char board[ROWS][cols], int rows, int cols, char set)
{
    
    
int i = 0;
int j = 0;
for (i = 0; i < rows; i++)
{
    
    
for (j = 0; j < cols; j++)
{
    
    
board[i][j] = set;
}
}
}

//打印 show 棋盘

void display_board(char board[ROWS][cols], int row, int col)
{
    
    
int i = 0;
int j = 0;

    //这里打印上面一行数字
    printf("|");
    for (j = 0; j <= col; j++)
    {
    
    
    	printf(" %-2d |", j);
    }
    printf("\n");


    for (i = 1; i <= row; i++)
    {
    
    
    	printf("|");
    	for (j = 0; j <= col; j++)
    	{
    
    
    		printf("----|");//打印两行之间的分割线
    	}
    	printf("\n");

    	printf("|");
    	printf(" %-2d |", i);//打印左边一列数字

    	for (j = 1; j <= col; j++)
    	{
    
    
    		printf(" %2c |",board[i][j]);//打印show数组

    	}
    	printf("\n");
    }

}

//随机设置雷,在 mine 数组里随机设置 COUNT 个雷

void set_mine(char mine[ROWS][cols], int row, int col)
{
    
    
int count = COUNT;
while (count)
{
    
    
int x = rand() % row + 1;
int y = rand() % col + 1;

    	if (mine[x][y] == '0')
    	{
    
    
    		mine[x][y] = '1';  //地雷设置为 '1'
    		count--;
    	}
    }

}

//获取一个格子周围的雷数

int get_mine_count(char mine[ROWS][cols], int x, int y)
{
    
    
//mine 中存放的是字符'0' 和 '1'
return (mine[x][y + 1] +
mine[x - 1][y + 1] +
mine[x - 1][y] +
mine[x - 1][y - 1] +
mine[x][y - 1] +
mine[x + 1][y - 1] +
mine[x + 1][y] +
mine[x + 1][y + 1] - 8 \* '0');
}

//递归展开

void expand(char mine[ROWS][cols], char show[ROWS][cols], int x, int y, int\* win)
{
    
    

    if (x >= 1 && x <= ROW && y >= 1 && y <= COL) //限制在棋盘内展开,防止越界
    {
    
    
    	int count = get_mine_count(mine, x, y);//获取雷数

    	if (count == 0) //四周没雷,进入递归展开
    	{
    
    
    		show[x][y] = ' ';//四周没雷的改为 空格  ' '


    		int i = 0;
    		//向四周共8个位置递归调用
    		for (i = x - 1; i <= x + 1; i++)
    		{
    
    
    			int j = 0;
    			for (j = y - 1; j <= y + 1; j++)
    			{
    
    

    				//只对 '*' 进行展开,防止死循环
    				if (show[i][j] == '*')
    				{
    
    
    					expand(mine, show, i, j, win);
    				}

    			}
    		}
    	}
    	else   //四周有雷显示雷数
    	{
    
    
    		show[x][y] = count + '0';
    	}

    	//记录展开的数量
    	(*win)++;
    }

}

//显示地雷位置,排雷成功或被炸死后 向玩家展示地雷位置

void show_mine(char mine[ROWS][cols], char show[ROWS][cols], int row, int col)
{
    
    
int i = 0;
for (i = 1; i <= row; i++)
{
    
    
int j = 0;
for (j = 1; j <= COL; j++)
{
    
    
if (mine[i][j] == '1')
{
    
    
show[i][j] = '@'; //将地雷改成 '@'
}
}
}
display_board(show, row, col); //打印
}

//玩家排查雷

void find_mine(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 - COUNT)//当翻开的格子数量 = 行 x 列 - 雷数 ===> 排雷成功
    {
    
    
    	printf("请输入要排查的坐标:>");
    	scanf("%d %d", &x, &y);

    	//检查坐标是否越界
    	if (x >= 1 && x <= row && y >= 1 && y <= col)
    	{
    
    

    		//检查坐标是否排查过了
    		if (show[x][y] == '*')
    		{
    
    

    			if (mine[x][y] == '1')
    			{
    
    
    				system("cls");
    				show_mine(mine, show, row, col);
    				printf("-----------很遗憾,你被炸死了-----------\n");
    				break;
    			}
    			else
    			{
    
    
    				//展开
    				expand(mine, show, x, y, &win);

    				system("cls");//清屏
    				display_board(show, row, col);
    				printf("--------------还需翻开%d格--------------\n", row * col - COUNT - win);
    			}
    		}
    		else
    		{
    
    
    			printf("该坐标已排查,请重新输入\n");
    		}
    	}
    	else
    	{
    
    
    		printf("坐标非法,请重新输入\n");
    	}
    }

    if (win == row* col - COUNT)
    {
    
    
    	system("cls");
        show_mine(mine, show, row, col);//展示地雷位置
        printf("------------恭喜你,排雷成功-----------\n");
    }

}

猜你喜欢

转载自blog.csdn.net/weixin_64933233/article/details/128601368
今日推荐