怀旧经典扫雷(简易版)

67 阅读3分钟

小游戏流程概述

(三子棋) 完成扫雷游戏,我们要考虑的就和前面写的三子棋流程差不多.那我们就从流程开始入手,我们同样使用game();函数来实现基本流程.

  1. 首先要完成游戏菜单.我们同样使用menu()函数来展示基本菜单功能.
  2. 第二呢我们就需要创建我们的页面并初始化.
  3. 棋盘初始化之后我们将页面打印出来.并在每次扫雷之后重新打印页面.
  4. 拥有基本条件后,我们还需要在玩家每一步之后判定游戏是否结束.
  5. 当游戏结束后,我们就需要重新展示菜单.询问玩家下一步流程.

模块介绍

我们创建两个源文件和一个头文件.

名称使用
test.c使用test.c来实现游戏的基本流程
game.h使用game.h来声明我们需要的函数和头文件
game.c使用game.c来书写游戏具体实现

test.c

接下来我们就在test.c中写入main()函数.

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("exit!");
			break;
		default:
			printf("输入有误,请重新输入\n");
			break;
		}
	} while (input);
	return 0;
}

main()函数的流程千篇一律,我们也不用过多介绍.需要注意的就是我们后面会使用到随机数,srand((unsigned int)time(NULL)); 必不可少.当然,后面发现了再回来添加也不是不可以.

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

用menu()函数打印菜单让玩家选择游戏下一步.

void game()
{
	
	char mine[ROWS][COLS] = { 0 };
	char show[ROWS][COLS] = { 0 };

	init_board(mine, ROWS, COLS, '0');
	init_board(show, ROWS, COLS, '*');

	dispaly_board(show, ROW, COL);

	set_mine(mine,ROW,COL);
	find_mine(mine, show, ROW, COL);
}

当玩家选择了进行游戏模块,就进入了游戏模块.这里我们使用了两个二维数组来充当我们的雷区.为什么是两个呢.因为经过多方考虑,我发现用两个数组,一个用来存放雷区,另一个用来展示给玩家.应用起来更方便.

函数名函数作用
init_board()用来初始化两个数组
dispaly_board()用来展示数组给玩家
set_mine()用来初始化雷区
find_mine()用来进行扫雷

以上就是test.c的全部模块.下来我们展示test.c的完整代码.(VS2019)

//#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void menu()
{
	printf("          1.play\n");
	printf("          0.exit\n");
}

void game()
{
	
	char mine[ROWS][COLS] = { 0 };
	char show[ROWS][COLS] = { 0 };

	init_board(mine, ROWS, COLS, '0');
	init_board(show, ROWS, COLS, '*');

	//dispaly_board(mine, ROW, COL);
	dispaly_board(show, ROW, COL);

	set_mine(mine,ROW,COL);
	//dispaly_board(mine, ROW, COL);
	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:
			game();
			break;
		case 0:
			printf("exit!");
			break;
		default:
			printf("输入有误,请重新输入\n");
			break;
		}
	} while (input);
	return 0;
}

因为我们game.h中包含了所需的头文件和函数,所以引入game.h就足够.

game.c

首先我们要完成的是初始化函数

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

参数介绍:

参数名参数作用
char board[ROWS][COLS]接受需要初始化的数组
int rows数组的行数
int cols数组的列数
char set用来指定初始化数组的字符

这里需要注意的是rows和cols是比实际雷区的row和col大两个范围,因此实际数组比雷区大了一圈.这里主要有两个原因.

  1. 第一个原因就是因为数组的下标是从0开始的,而我们空过了行列为0的数组范围,就可以直接使用玩家输入的行和列来进行游戏.
  2. 另一个原因就是给雷区多了一圈的位置赋值为0,可以更好的进行是否有雷,有几个雷的函数判断.

打印函数.

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

参数介绍:

参数名参数作用
int row雷区实际的行数
int col雷区实际的列数

布雷函数

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

		if(mine[x][y] == '0')
		{
			mine[x][y] = '1';
			count--;
		}
	}
}

参数介绍:

参数名参数作用
char mine[ROWS][COLS]接受实际雷区的数组
EASY_COUNT雷区中雷的个数

因为这里布雷需要使用随机数函数rand(),所以test.c中.main()需要添加配套代码.(前面我们已经提到了.)

进行游戏.

void find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int z = 0;
	for (z = 0; z < row*col- EASY_COUNT; z++) {
		printf("请输入要排查的雷的坐标:>");
		scanf("%d%d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (show[x][y] == '*')
			{
				if (mine[x][y] == '1')
				{
					printf("很遗憾,你被炸死了\n");
					dispaly_board(mine, ROW, COL);
					break;
				}
				else
				{
					int count = get_mine_count(mine, x, y);
					show[x][y] = count + '0';
					dispaly_board(show, ROW, COL);
				}
			}
			else
			{
				printf("该位置已经排查过\n");
				z--;
			}
		}
		else
		{
			printf("输入坐标有误,请重新输入\n");
		}
	}
	if (z == row * col - EASY_COUNT)
	{
		printf("恭喜你\n");
	}
}

参数介绍:

参数名参数作用
char show[ROWS][COLS]接受展示给玩家的数组

上述函数中还包含了get_mine_count();函数,用来计算不是雷是此块地周围的雷的个数.

int get_mine_count(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-1] +
		mine[x + 1][y] +
		mine[x + 1][y+1] +
		mine[x][y+1] +
		mine[x - 1][y+1] - );
}

这里减去(8 * '0')是因为雷区中存放的是字符'1',要计算个数就要减去字符'0'.

以上就是game.c的全部模块.下来我们展示game.c的完整代码.(VS2019)

#pragma once
#include "game.h"

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

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

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

		if(mine[x][y] == '0')
		{
			mine[x][y] = '1';
			count--;
		}
	}
}

int get_mine_count(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-1] +
		mine[x + 1][y] +
		mine[x + 1][y+1] +
		mine[x][y+1] +
		mine[x - 1][y+1] - 8 * '0');
}

void find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int z = 0;
	for (z = 0; z < row*col- EASY_COUNT; z++) {
		printf("请输入要排查的雷的坐标:>");
		scanf("%d%d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (show[x][y] == '*')
			{
				if (mine[x][y] == '1')
				{
					printf("很遗憾,你被炸死了\n");
					dispaly_board(mine, ROW, COL);
					break;
				}
				else
				{
					int count = get_mine_count(mine, x, y);
					show[x][y] = count + '0';
					dispaly_board(show, ROW, COL);
				}
			}
			else
			{
				printf("该位置已经排查过\n");
				z--;
			}
		}
		else
		{
			printf("输入坐标有误,请重新输入\n");
		}
	}
	if (z == row * col - EASY_COUNT)
	{
		printf("恭喜你\n");
	}
}

同test.c相同,只需引入game.h即可.

game.h

最后我们展示game.h所需的的完整代码.(VS2019)

#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

#define EASY_COUNT 10

void init_board(char board[ROWS][COLS],int rows,int cols,char set);
void dispaly_board(char board[ROWS][COLS], int row, int col);
void set_mine(char mine[ROWS][COLS], int row, int col);
void find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);

完结

以上就是简易版扫雷的全部实现.如果有意向,可以尝试递归产生扫雷的代码,这样会更接近经典.