C语言实现扫雷游戏(自动排雷)

本次讲解扫雷小游戏(小小升级的版本)


前言

游戏规则:根据电脑提示输入位置,当输入的位置让有雷,游戏结束;输入的位置是哪个没有雷,游戏继续,并且会显示周围八个位置的雷的情况


为了让代码更加模块化,首先我们需要分别创建game.h game.c test.c
在这里插入图片描述

一、game.h

game.h 里面存放的是头文件的声明、函数的声明、以及雷盘大小的自由化改动

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
//包含头文件
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

//方便修改雷盘大小
#define ROW 3  
#define COL 3
#define ROWS ROW+2
#define COLS COL+2

//声明初始化雷盘函数
void InitBoard(char board[ROWS][COLS], int rows, int cols, char ret);

//声明打印雷盘函数
void PrintBoard(char board[ROWS][COLS], int row, int col);

//声明布置雷函数
void setmine(char board[ROWS][COLS], int row, int col, int num);

//声明排查雷的函数
void findmine(char secret[ROWS][COLS], char show[ROWS][COLS], int row,int col,int num);

二、test.c

1.主函数 main() 的编写

根据游戏需求,我们需要一个可以提供玩家选择的游戏菜单

void menu()
{
	printf("*************---------------***************\n");
	printf("******---------            ---------*******\n");
	printf("******--------- 1.玩游戏   ---------*******\n");
	printf("\n");
	printf("******--------- 0.退出游戏 --------********\n");
	printf("******---------            ---------*******\n");
	printf("*************---------------***************\n");

}

玩家按照菜单的内容进行选择,根据不同的选择编写 switch 语句

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

		switch (input)
		{
		case 0:
			system("cls");
			system("pause");
			printf("欢迎您的下一次体验,再见!\n");
			break;
		case 1:
			game();
			break;
		default:
			printf("输入错误,请重新选择\n");
			break;
		}
	} while (input);
}

2.游戏系列函数编写game.c

创建一个理想雷盘

char Secret[ROWS][COLS] = { 0 };  //秘密雷盘
char Show[ROWS][COLS] = { 0 };//展示的雷盘

正常来说,扫雷游戏只需要一个雷盘,但是这里设置了两个雷盘的原因是: Secret雷盘是用来存储雷的信息的,这里不能给玩家看;Show雷盘是玩家进行游戏的雷盘,两者有不同的作用,所以需要设置两个规模一样的雷盘。

初始化雷盘

void InitBoard(char board[ROWS][COLS], int rows, int cols, char ret)
{
	memset(board, ret, sizeof(board[0][0]) * rows * cols);
}

因为这里是char类型的数组,所以直接使用memset初始化。

雷盘打印

void PrintBoard(char board[ROWS][COLS], int row, int col)
{
	printf("------------------------扫雷游戏-------------------\n");
	int i = 0, j = 0;
	printf(" ");
	for (i = 1; i <= row; i++)
	{
		printf("%3d ", i);
	}
	printf("\n");
	printf("  +");
	for (i = 0; i < row; i++)
	{
		printf("---+");
	}
	printf("\n");
	
	for (i = 1; i <= row; i++)
	{
		printf("%2d", i);
		printf("|");
		for (j = 1; j <= col; j++)
		{
			printf(" %c |", board[i][j]);
		}
		printf("\n");
		
		printf("  +");
		for (j = 0; j < col; j++)
		{
			printf("---+");
		}
		printf("\n");
	}
	printf("------------------------扫雷游戏-------------------\n");
}

布置雷盘

void setmine(char board[ROWS][COLS], int row, int col, int num)
{
	//随机布雷
	int x = 0;
	int y = 0;
	for (int i = 0; i < num; )
	{
		x = rand() % row + 1;  //x产生[1,row]之间的坐标
		y = rand() % col + 1;  //y产生[1,col]之间的坐标
		if (board[x][y] == '0')
		{
			board[x][y] = '1';
			i++; 
		}
	}
}

模式选择
玩家可以自行选择困难模式,也可以自定义模式

int ModeSelection()
{
	int num = 0;
again:  //玩家选择模式错误时返回到这里
	printf("欢迎玩家来到扫雷游戏\n");
	printf("\n请选择扫雷难度: (num的代表雷的数量)\n");
	printf("A.轻松模式:num=5  B.皱眉头模式:num=15  C.出汗模式:num=30  D.DIY难度(玩家自行输入雷的个数)\n ");
	char pattern = 0;
	getchar();//清空缓存区
	scanf("%c", &pattern);
	switch (pattern)
	{
	case 'A':
	case 'a':
		printf("轻松模式:num=5\n");
		num = 5;
		return num;
		break;
	case 'B':
	case 'b':
		printf("皱眉头模式:num=15\n");
		num = 15;
		return num;
		break;
	case 'C':
	case 'c':
		printf("出汗模式:num=30\n");
		num = 30;
		return num;
		break;
	case 'D':
	case 'd':
		printf("DIY模式:\n");
		printf("请输入想要布置雷的个数:\n");
		getchar();//清楚缓存区
		int intput = 0;
		scanf("%d", &intput);//用户自定义的雷的个数
		num = intput;
		return num;
		break;
	default:
		printf("\n******不好意思,皮蛋还没有此功能按键,请重新选择:******\n\n");
		goto again;
		break;
	}
}

排查雷

  1. 首先需要知道玩家输入的坐标是否合法
  2. 其次需要判断此位置有没有被排查过
  3. 如果没有被排查过,就需要进行递归显示周围雷的数量
void findmine(char secret[ROWS][COLS], char show[ROWS][COLS], int row, int col, int num)
{
	int x = 0;
	int y = 0;
	int win = 0;  //被排查的个数
	while ((row * col - num) > win)
	{
		printf("请输入排雷坐标(格式:行号 列号)\n");
		scanf("%d%d", &x, &y);
		if (show[x][y] != '*')
		{
			printf("该坐标已经被排查过了 请重新输入:\n");
			continue;
		}
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (secret[x][y] == '1')//如果是1就代表是雷,游戏结束
			{
				printf("很遗憾,你失败了\n");
				printf("请看答案:\n");
				PrintBoard(secret, ROW, COL);//失败后,给玩家看答案雷盘
				break;
			}
			else
			{
				Recursive(secret, show, ROW, COL, x, y);  //自动递归排雷函数
				win = is_win(show, ROW, COL);  //计算已经被排查的位置
				PrintBoard(show, ROW, COL);//打印给玩家的雷盘
			}
		}
		else
		{
			printf("坐标非法,请重新输入:\n");
		}
	}
	if (win == (row * col - num))
	{
		printf("恭喜你排雷成功\n");
	}
}

递归进行自动排雷(显示周围雷的情况)

Recursive(char secret[ROWS][COLS], char show[ROWS][COLS], int row, int col, int x, int y)
{
	if (x >= 1 && x <= row && y >= 1 && y <= col)
	{
		int count = countmine(secret, x, y);//计算该坐标周围有几个雷
		if (count == 0)
		{
			show[x][y] = ' ';//周围没有雷的坐标变为空格
			int i = 0, j = 0;
			for (i = x - 1; i <= x + 1; i++)//观察周围八个坐标
			{
				for (j = y - 1; j <= y + 1; j++)
				{
					if (show[i][j] == '*' && (i != x || j != y))//防止重新递归show[x][y]坐标
					{
						Recursive(secret, show, ROW, COL, i, j);
					}

				}
				
			}
		}
		else
		{
			show[x][y] = count + '0';
		}
	}
}

计算周围雷的个数

int countmine(char secret[ROWS][COLS], int x, int y)
{
	int ret = secret[x - 1][y - 1] + secret[x - 1][y] + secret[x - 1][y + 1]
		+ secret[x][y - 1] + secret[x][y + 1]
		+ secret[x + 1][y - 1] + secret[x + 1][y] + secret[x + 1][y + 1] - 8 * '0';
	return ret;
}

计算已经被排查过的位置,进而判断是否还有空位进行排雷游戏

int is_win(char show[ROWS][COLS], int row, int col)
{
	int count1 = 0;//已经被排查的坐标个数
	int i = 0, j = 0;
	for (i = 1; i <= row; i++)
	{
		for (j = 1; j <= col; j++)
		{
			if (show[i][j] != '*')//只要不是*,表示该坐标已经被排查了.
			{
				count1++;
			}
		}
	}
	return count1;
}


整体代码

game.h

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
//包含头文件
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

//方便修改雷盘大小
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2

//声明初始化雷盘函数
void InitBoard(char board[ROWS][COLS], int rows, int cols, char ret);

//声明打印雷盘函数
void PrintBoard(char board[ROWS][COLS], int row, int col);

//声明布置雷函数
void setmine(char board[ROWS][COLS], int row, int col, int num);

//声明排查雷的函数
void findmine(char secret[ROWS][COLS], char show[ROWS][COLS], int row,int col,int num);

test.c

#include "game.h"
void menu()
{
	printf("*************---------------***************\n");
	printf("******---------            ---------*******\n");
	printf("******--------- 1.玩游戏   ---------*******\n");
	printf("\n");
	printf("******--------- 0.退出游戏 --------********\n");
	printf("******---------            ---------*******\n");
	printf("*************---------------***************\n");

}

void game()
{
	//创建雷盘
	char Secret[ROWS][COLS] = { 0 };  //秘密雷盘
	char Show[ROWS][COLS] = { 0 };//展示的雷盘

	//初始化雷盘
	InitBoard(Secret, ROWS, COLS,'0'); //初始化的答案雷盘
	InitBoard(Show, ROWS, COLS, '*');  //初始化的玩家雷盘

	//打印雷盘
	PrintBoard(Show, ROW, COL); //打印给玩家看的雷盘

	//布置雷
	int num = ModeSelection(); //模式选择函数,返回雷的数量
	setmine(Secret, ROW, COL, num); //布置雷函数

	//排查雷
	findmine(Secret, Show, ROW, COL, num);
}
int main()
{
	srand((unsigned int)time(NULL));
	int input = 0;
	do
	{
		menu();
		printf("请选择:");
		scanf("%d", &input); 

		switch (input)
		{
		case 0:
			system("cls");
			system("pause");
			printf("欢迎您的下一次体验,再见!\n");
			break;
		case 1:
			game();
			break;
		default:
			printf("输入错误,请重新选择\n");
			break;
		}
	} while (input);
}

game.c

#include "game.h"

//初始化雷盘函数的定义
void InitBoard(char board[ROWS][COLS], int rows, int cols, char ret)
{
	memset(board, ret, sizeof(board[0][0]) * rows * cols);
}


//打印雷盘函数的定义
void PrintBoard(char board[ROWS][COLS], int row, int col)
{
	printf("------------------------扫雷游戏-------------------\n");
	int i = 0, j = 0;
	printf(" ");
	for (i = 1; i <= row; i++)
	{
		printf("%3d ", i);
	}
	printf("\n");
	printf("  +");
	for (i = 0; i < row; i++)
	{
		printf("---+");
	}
	printf("\n");
	
	for (i = 1; i <= row; i++)
	{
		printf("%2d", i);
		printf("|");
		for (j = 1; j <= col; j++)
		{
			printf(" %c |", board[i][j]);
		}
		printf("\n");
		
		printf("  +");
		for (j = 0; j < col; j++)
		{
			printf("---+");
		}
		printf("\n");
	}
	printf("------------------------扫雷游戏-------------------\n");
}



//模式选择函数的定义(返回设置雷的个数)
int ModeSelection()
{
	int num = 0;
again:  //玩家选择模式错误时返回到这里
	printf("欢迎玩家来到扫雷游戏\n");
	printf("\n请选择扫雷难度: (num的代表雷的数量)\n");
	printf("A.轻松模式:num=5  B.皱眉头模式:num=15  C.出汗模式:num=30  D.DIY难度(玩家自行输入雷的个数)\n ");
	char pattern = 0;
	getchar();//清空缓存区
	scanf("%c", &pattern);
	switch (pattern)
	{
	case 'A':
	case 'a':
		printf("轻松模式:num=5\n");
		num = 5;
		return num;
		break;
	case 'B':
	case 'b':
		printf("皱眉头模式:num=15\n");
		num = 15;
		return num;
		break;
	case 'C':
	case 'c':
		printf("出汗模式:num=30\n");
		num = 30;
		return num;
		break;
	case 'D':
	case 'd':
		printf("DIY模式:\n");
		printf("请输入想要布置雷的个数:\n");
		getchar();//清楚缓存区
		int intput = 0;
		scanf("%d", &intput);//用户自定义的雷的个数
		num = intput;
		return num;
		break;
	default:
		printf("\n******不好意思,皮蛋还没有此功能按键,请重新选择:******\n\n");
		goto again;
		break;
	}
}


//定义布置雷函数
void setmine(char board[ROWS][COLS], int row, int col, int num)
{
	//随机布雷
	int x = 0;
	int y = 0;
	for (int i = 0; i < num; )
	{
		x = rand() % row + 1;  //x产生[1,row]之间的坐标
		y = rand() % col + 1;  //y产生[1,col]之间的坐标
		if (board[x][y] == '0')
		{
			board[x][y] = '1';
			i++; 
		}
	}
}



//统计坐标周围雷的数量
int countmine(char secret[ROWS][COLS], int x, int y)
{
	int ret = secret[x - 1][y - 1] + secret[x - 1][y] + secret[x - 1][y + 1]
		+ secret[x][y - 1] + secret[x][y + 1]
		+ secret[x + 1][y - 1] + secret[x + 1][y] + secret[x + 1][y + 1] - 8 * '0';
	return ret;
}



//自动排雷函数定义
Recursive(char secret[ROWS][COLS], char show[ROWS][COLS], int row, int col, int x, int y)
{
	if (x >= 1 && x <= row && y >= 1 && y <= col)
	{
		int count = countmine(secret, x, y);//计算该坐标周围有几个雷
		if (count == 0)
		{
			show[x][y] = ' ';//周围没有雷的坐标变为空格
			int i = 0, j = 0;
			for (i = x - 1; i <= x + 1; i++)//观察周围八个坐标
			{
				for (j = y - 1; j <= y + 1; j++)
				{
					if (show[i][j] == '*' && (i != x || j != y))//防止重新递归show[x][y]坐标
					{
						Recursive(secret, show, ROW, COL, i, j);
					}

				}
				
			}
		}
		else
		{
			show[x][y] = count + '0';
		}
	}
}


//计算已经被排查的位置
int is_win(char show[ROWS][COLS], int row, int col)
{
	int count1 = 0;//已经被排查的坐标个数
	int i = 0, j = 0;
	for (i = 1; i <= row; i++)
	{
		for (j = 1; j <= col; j++)
		{
			if (show[i][j] != '*')//只要不是*,表示该坐标已经被排查了.
			{
				count1++;
			}
		}
	}
	return count1;
}

//定义排查雷的函数
void findmine(char secret[ROWS][COLS], char show[ROWS][COLS], int row, int col, int num)
{
	int x = 0;
	int y = 0;
	int win = 0;  //被排查的个数
	while ((row * col - num) > win)
	{
		printf("请输入排雷坐标(格式:行号 列号)\n");
		scanf("%d%d", &x, &y);
		if (show[x][y] != '*')
		{
			printf("该坐标已经被排查过了 请重新输入:\n");
			continue;
		}
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (secret[x][y] == '1')//如果是1就代表是雷,游戏结束
			{
				printf("很遗憾,你失败了\n");
				printf("请看答案:\n");
				PrintBoard(secret, ROW, COL);//失败后,给玩家看答案雷盘
				break;
			}
			else
			{
				Recursive(secret, show, ROW, COL, x, y);  //自动递归排雷函数
				win = is_win(show, ROW, COL);  //计算已经被排查的位置
				PrintBoard(show, ROW, COL);//打印给玩家的雷盘
			}
		}
		else
		{
			printf("坐标非法,请重新输入:\n");
		}
	}
	if (win == (row * col - num))
	{
		printf("恭喜你排雷成功\n");
	}
}
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值