C语言-------------扫雷游戏的实现

一,扫雷游戏规则与实现思路

1,游戏概述

扫雷的玩法十分简单,通过点格上的数字判断周边是否有雷格并在最短的时间内点开所有的无雷格即可胜利,扫雷诞生之初,本意是为了训练和培养用户的鼠标左右键操作能力以及移动鼠标的的速度和精准性,让用户可以更加自然使用鼠标。

发展到今天,扫雷已经发展出一项兼具竞速和锻炼脑力的双重属性的游戏,且因为其在电脑上搭载的广泛性和玩游戏时的隐蔽性,堪称办公室时间第一杀手。

我们下面以基础的9*9的版本进行讲解,也就是说在这个9*9的网格里找出所有没有雷的格子,而不踩雷,当然了还有更高级的模式,比如满屏的,棋盘格子数我们可以随便设置

在线扫雷游戏:http://www.minesweeper.cn/

2,游戏规则描述

我们打卡游戏,任意点开一个方格,会出现三种情况

第一种是有数字(1,2...),这种情况说明以他为中心的周围八个格子里有相应个数的雷,最小为1,最大为8。

第二种是空格,说明周围八个没有一个雷,即为0。

第三种是保持不变,等待下一次点击。

二,功能的实现

1,打印一个游戏菜单

首先我们设置一个菜单函数

void menu()
{
	printf("---------------------------------");
	printf("-----------1.play----------------");
	printf("-----------0.exit----------------");
	printf("---------------------------------");
}

我们可以在主函数(text.c)中调用这个函数来打印菜单。

2,构建游戏基本逻辑结构

(1),我们可以通过输入1或者0来实现游戏开始或者结束。

(2),如果一把玩完还想玩一把,那我们需要设置再玩一次的选项

我们可以使用一个switch语句,通过定义整型来存放输入的数字,如果输入的数字是1就提示开始游戏,如果输入的数字0就提示结束游戏,如果输入非1/0那么就提示输入错误,请重新输入。

int main()
{
	int input;
	do
    {
	 menu();
	 printf("请选择:>");
	 scanf("%d", &input);

		 switch (input)
		 {
		 case 1:
			 printf("开始游戏:\n");
			 game()
			 break;
		 case 0:
			 printf("结束游戏\n");

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

	 } while (input);
}

运行结果

基本满足我们的需要

三,游戏的制作

1,定义二个一样的数组

假设我们排插一个方格后,这个方格不是雷,但这个方格的周围有一个雷,我们需要将排查出雷的信息记录储存,并且打印出来,作为排雷的重要产靠信息,那这个信息存放在哪里呢?如果存放在布置雷的数组中,但是雷的信息和布置雷的信息就会产生混淆和打印上的困难。

我们可以专门给一个棋盘(对应一个数组mine)存放布置好雷的信息,再给另外一个棋盘,(对应另一种数组show)存放排查出雷的信息。这样就互不干扰了,吧雷布置到mine数组中,在mine数组中排查雷,排查出的信息放在show数组中,并且打印show数组的信息给后期参考排查,同时为了保持神秘性,show数组初始化为字符‘*’,为了保持两个数组的类型一致,可以使用同一套函数处理,mine函数也初始化为’0‘,布雷后改成‘1’,

char  mine[11][11]={0};//用于存放布置雷的信息
char  show[11][11]={0};//用于存放排查出雷的信息

2,文件结构设计

为了处理方便,我们采用多文件形式对函数进行定义和声明。

1 test.c//文件中游戏的测试逻辑

2 game.c//w文件中写游戏中函数的实现

3 game。h//文件中写游戏需要的数据类型和函数声明等

为了后期存放方便,我们可以将数组使用#define标识符列表中的参数。

#define ROW 9     //实际使用的运行行
#define COL 9      //实际使用的列

#define ROWS ROW+2  //数组使用的行
#define COLS COL+2   //数组使用的列

3 初始化数组,

game.h

void InitBoard(char board[ROWS][COLS], int rows, int cols, int ret);

game.c

​
void InitBoard(char board[ROWS][COLS], int rows, int cols, int ret)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < rows; i++)
	{
		for (j = 0; j < cols; j++)
		{
			board[i][j] = ret;
		}
	}
}

​

3,打印棋盘

game.h

void DisplayBoard(char board[ROWS][COLS], int row, int col)

game.c

void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
	int i = 0;
	for (i = 0; i <=row; i++)
	{
		printf("%d ", i);
	}
	printf("\n");
	for (i = 1; i <= row; i++)
	{
		printf("%d ", i);
		int j = 0;
		for (j = 0; j < col; j++)
		{
			printf("%c ", board[i][j]);
		}
		printf("\n");
	}

}

在text.c中建立一个game()函数,来实现棋盘的打印

oid game()
{
	char mine[ROWS][COLS] = { 0 };//存放布置好的雷
	char show[ROWS][COLS] = { 0 };//存放排查出雷的信息
	//初始化棋盘
	//1,mine数组最开始全是‘0’
	//2,show数组最开始全是‘*’
	InitBoard(mine, ROWS, COLS, '0');
	InitBoard(show, ROWS, COLS, '*');
	//打印棋盘
	DisplayBoard(show, ROW, COL);
}

打印结果

4,布置雷

采用srand和rand函数生成0-9的随机数赋值给x,y;然后在对应的位置布置雷

game.h

void SetMine(char board[ROWS][COLS], int row, int col)

game.c

void SetMine(char board[ROWS][COLS], int row, int col)
{
	int count = EASY_COUNT;
		while (count)
		{
			srand((unsigned int)time(NULL));
			int x = rand() % row + 1;
			int y = rand() % col + 1;
			if (board[x][y] =='0')
			{
				board[x][y] = '1';
				count--;
			}
		}
}

5,排查雷

在排查中出现这三种情况

1,这个坐标不是雷,提示周围有几个雷

2,这个地方是雷,游戏结束

3 ,所以非雷的坐标都找到了,游戏胜利

如果找到的坐标是非雷,我们还需要继续进行排查,所以我们需要设置循环排查,排查到雷或者排查结束才能跳出循环

int GetMineCount(char mine[ROWS][COLS], int x, int y)
{
	return(mine[x - 1][y] + mine[x - 1][y - 1] + mine[x][y - 1] + mine[x + 1][y1] + mine[x + 1][y] + mine[x + 1][y + 1] + mine[x][y + 1] + mine[x - 1][y + 1] - 8 * '0');
	//字符'1'的ASCII码是49‘0’的ASCII码是48

然后在game()中调用就可以统计出附近雷的个数

4,我们可以设置一个整形变量,其大小为非雷的个数,如果成功排除雷就将他减一,将他设置为循环的条件,当他减为0时就跳出循环,并且打印出,排雷成功。

void FindMine(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 - EASY_COUNT)
	{
		printf("请输入你要排查的坐标:>");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (mine[x][y] == '1')
			{
				printf("很遗憾,你被炸死了\n");
				DisplayBoard(mine, ROW, COL);
				break;
			}
			else
			{
				int count = GetMineCount(mine, x, y);
				show[x][y] = count + '0';
				DisplayBoard(show, ROW, COL);
				win++;
			}
		}
		else
		{
			printf("坐标非法,重新输入\n");
		}
		if (win == row * col - EASY_COUNT)
		{
			printf("恭喜你,排雷成功\n");
			DisplayBoard(mine, ROW, COL);
		}

	}
}

game函数

void game()
{
	char mine[ROWS][COLS] = { 0 };//存放布置好的雷
	char show[ROWS][COLS] = { 0 };//存放排查出雷的信息
	//初始化棋盘
	//1,mine数组最开始全是‘0’
	//2,show数组最开始全是‘*’
	InitBoard(mine, ROWS, COLS, '0');
	InitBoard(show, ROWS, COLS, '*');
	//打印棋盘

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

六,扫雷游戏的实现

game.h

#pragma once
#include<stdio.h>
#include<stdlib.h>  //srand函数的头文件
#include<time.h>    //time函数的头文件


#define EASY_COUNT 10
#define ROW 9     //实际使用的运行行
#define COL 9      //实际使用的列

#define ROWS ROW+2  //数组使用的行
#define COLS COL+2   //数组使用的列

void InitBoard(char board[ROWS][COLS], int rows, int cols, int ret);
void DisplayBoard(char board[ROWS][COLS], int row, int col);
void SetMine(char board[ROWS][COLS], int row, int col);
void FindMine(char mine[ROWS][COLS],char show[ROWS][COLS], int row, int col);



game.c

#define _CRT_SECURE_NO_WARNINGS  1
#include"game.h"

void InitBoard(char board[ROWS][COLS], int rows, int cols, int ret)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < rows; i++)
	{
		for (j = 0; j < cols; j++)
		{
			board[i][j] = ret;
		}
	}
}
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
	int i = 0;
	printf("-----------扫雷-----------\n");
	for (i = 0; i <=col; i++)
	{
		printf("%d ", i);
	}
	printf("\n");
	for (i = 1; i <= row; i++)
	{
		printf("%d ", i);
		int j = 0;
		for (j = 1; j <= col; j++)
		{
			printf("%c ", board[i][j]);
		}
		printf("\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--;
			}
		}
}

int GetMineCount(char mine[ROWS][COLS], int x, int y)
{
	return(mine[x - 1][y] + mine[x - 1][y - 1] + mine[x][y - 1] + mine[x + 1][y] + mine[x + 1][y] + mine[x + 1][y + 1] + mine[x][y + 1] + mine[x - 1][y + 1] - 8 * '0');
	//字符'1'的ASCII码是49‘0’的ASCII码是48
}
void FindMine(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 - EASY_COUNT)
	{
		printf("请输入你要排查的坐标:>");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (mine[x][y] == '1')
			{
				printf("很遗憾,你被炸死了\n");
				DisplayBoard(mine, ROW, COL);
				break;
			}
			else
			{
				int count = GetMineCount(mine, x, y);
				show[x][y] = count+'0';
				DisplayBoard(show, ROW, COL);
				win++;
			}
		}
		else
		{
			printf("坐标非法,重新输入\n");
		}
		if (win == row * col - EASY_COUNT)
		{
			printf("恭喜你,排雷成功\n");
			DisplayBoard(mine, ROW, COL);
		}

	}
}

text.c

#define _CRT_SECURE_NO_WARNINGS  1
#include<stdio.h>
#include"game.h"
void menu()
{
	printf("---------------------------------\n");
	printf("-----------1.play----------------\n");
	printf("-----------0.exit----------------\n");
	printf("---------------------------------\n");
}
void game()
{
	char mine[ROWS][COLS] = { 0 };//存放布置好的雷
	char show[ROWS][COLS] = { 0 };//存放排查出雷的信息
	//初始化棋盘
	//1,mine数组最开始全是‘0’
	//2,show数组最开始全是‘*’
	InitBoard(mine, ROWS, COLS, '0');
	InitBoard(show, ROWS, COLS, '*');
	//打印棋盘

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

int main()
{
	int input=0;
	srand((unsigned int)time(NULL));
	 do
	 {
	 menu();
	 printf("请选择:>");
	 scanf("%d", &input);
	
		 switch (input)
		 {
		 case 1:
			 game();
			 break;
		 case 0:
			 printf("结束游戏\n");

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

	 } while (input);
	 return 0;
}

  • 25
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值