扫雷游戏的代码实现

       扫雷游戏的代码大概有两百多行,这些代码全写在一个文件里看起来会很乱,所以采用一个头文件(game.h),两个源文件(game.c/test.c)的形式来写。(注:我采用的编译器的VS2022,本文主要以9*9棋盘来介绍。)

一.分析——代码的具体实现

问题分析

       扫雷游戏有两个重要元素:雷和棋盘。以这两个元素为中心,我们会产生很多疑问:雷怎么放,棋盘怎么打印,怎么排查雷,怎么存储排查雷后得到的信息等等,接下来我们一一解决。

二.代码的主体——代码整体逻辑的体现

(我把这部分代码放在test.c文件里)

1. 主体用do while 语句

       游戏是多次进行的,因此采用循环语句。根据玩游戏的顺序,首先是玩家进入界面,选择“玩”亦或“不玩”。逻辑体现到代码里就是循环体的执行要比判断语句多一次,所以采用do while语句比较合适。接下来的大部分代码就写在循环体里。那么判断语句是什么呢?怎么保证玩家选择“退出”循环就立刻终止?

       C语言里0为假,非0为真,因此,我们将“exit”设置成0,“play”设置成1,玩家的选择存储到变量input里,再把它作为判断条件,这样问题就可以得到解决

2.菜单栏函数

命名为menu,函数形式为void(因为不需要返回值)

内容包含两部分:选项play和exit,提示语

1).switch语句

       根据玩家的选择,会产生三种情况:play,exit和error(即输错了)。据此,我们进入不同的分支语句。相比于if语句,switch语句更合适。

2).game函数

主要构思

首先,打印全显示为“*”的棋盘和坐标

其次,弹出提示:请输入排查的坐标

然后,打印出排查的坐标下的信息,不是雷就继续,是雷就被炸死,游戏结束

具体内容

棋盘是二维的,所以采用二维数组来表示。

       为了方便改变数组的大小,我们用宏常量“ROWS”和“COLS”来表示数组的行和列,并在头文件里将这两个变量规定为9。棋盘要有两个:一个用来储存雷;另一个用来储存玩家扫雷的信息。接着对棋盘进行初始化,并打印出来。打印棋盘时要将坐标也一并打印出来。(打印函数放在后面)

    char  mine[ROWS][COLS];
	char  show[ROWS][COLS];
	Initboard(mine, ROWS, COLS, '0');//这个棋盘存放雷
	Initboard(show, ROWS, COLS, '*');//这个棋盘存放排查雷的信息

void Initboard(char board[ROWS][COLS], int rows, int cols,char set)//set表示棋盘初始化的内容,这样就可以同时初始化两个棋盘
{
	int i = 0;
	int j = 0;
	for (i = 0; i < rows; i++)
	{
		for (j = 0; j < cols; j++)
		{
			 board[i][j] = set;//棋盘初始化
		}
	}
}

布置雷

      雷的布置肯定是随意的,于是采用rand函数(具体内容可以看我的前一篇博客“猜数字游戏”),在随机的某行某列放置雷(用‘1’来表示)。注意,雷在放置的时候可能会重复,所以要用if语句进行判断。

#define COUNT 10
void Setmine(char board[ROWS][COLS], int rows, int cols)
{
	srand((unsigned int)time(NULL));//NULL 是C语⾔中定义的⼀个标识符常量,值是0
	int count = COUNT;//布置10个雷
	while (count)//雷布置完,循环结束
	{
	 int x = rand() % rows + 1;//会产生0~rows-1的余数,再加1就是行数
	 int y = rand() % cols + 1;//会产生0~rows-1的余数,再加1就是列数
	 if (board[x][y] == '0')
	 {
		 board[x][y] = '1';//用'1'来代表雷
		 count--;
	 }
	}
}

具体效果:

(右边是打印出的棋盘,左边是棋盘下布置的雷) 

玩家排查坐标

       排查坐标后,会显示两种结果:雷和周围有几个雷。是雷,游戏就结束,不是雷,就要检查周围一圈有几个雷,并把这个数字放到被排查后的坐标上,再打印出来。所以,要写一个函数实现这个功能。进行排查的时候我们会发现一个问题,棋盘边缘那一圈怎么排查?根据我们写的这个函数,在排查棋盘边缘一圈的时候,坐标会越界,所以我们在初始化数组的时候,整体给数组扩大一圈,大小设置成11*11,这也用宏常量表示。在打印棋盘,放置雷,排查坐标的时候,只需改变数组的1~9行和1~9列就行了。

#define ROW 9
#define COL 9
#define ROWS  ROW+2
#define COLS  COL+2
void Displayboard(char board[ROWS][COLS], int rows ,int cols)
{
	int i = 0;
	int j = 0;
	for (i = 0; i <=cols ; i++)
	{
		printf("%d ", i);//打印纵坐标
	}
	printf("\n");
	for (i = 1; i <=rows; i++)//打印数组的1~9行
	{
		
		printf("%d ", i);//在每一行的前面打印这是第几行,当作横坐标
		for (j = 1; j <= cols; j++)//打印数组的1~9列
		{
			printf("%c ", board[i][j]);
		}
		printf("\n");
	}
}

int  Getminecount(char board[ROWS][COLS], int rows, int cols)
{
	int sum = 0;
	for(int x = rows - 1; x <= rows + 1; x++)
	{
		for (int y = cols - 1; y <= cols + 1; y++)
		{
			if (board[x][y] == '1')
			{
				sum++;//sum 表示周围雷的数量
			}
		}
	}
	return sum;
}

       由于这个函数的返回值是int类型,而我们的数组是char类型,所以,在把返回值放到数组里面之前,要加上字符‘0’的ASCII码值

	Getminecount(mine, a,b);
	int count = Getminecount;
	show[a][b] =count+'0';
	Displayboard(show, ROWS, COLS);
游戏胜利的条件

        当玩家将所有未放置雷的地方都排查完时,就胜利,但这个如何写到代码里去呢?雷一共有10个,棋盘的大小是9*9,也就是说棋盘上有9*9-10个坐标没有雷。只要玩家的排查次数达到这么多,游戏就肯定胜利了。因此,我们定义一个变量win,玩家每排查一次坐标,win就+1,达到9*9-10时,游戏结束。

void Findmine(char mine[ROWS][COLS],char show[ROWS][COLS], int rows, int cols)
{
	int win = 0;
	while (win<ROWS*COLS-COUNT)
	{
		printf("请输入要排查的坐标:");
		int a, b;
		scanf("%d %d", &a, &b);
		if (a > 0 && a <= rows && b > 0 && b <= cols)
		{


			if (mine[a][b] == '1')
			{
				printf("很遗憾,你被炸死了\n");
				Displayboard(mine, ROW, COL);//打印出所有雷的信息
				break;
			}
			else
			{
				int count = Getminecount(mine, a, b);;
				show[a][b] =  count + '0';
				Displayboard(show, ROW, COL);
				win++;
			}
		}
		else
		{
			printf("坐标错误,请重新输入:");
		}
	}
	if (win == ROWS * COLS - COUNT)
	{
		printf("恭喜你,游戏胜利!");
	}
}

具体效果:

 

这样,整个扫雷游戏代码就写完了。

附:

test文件里的代码:
#include"game.h"
void menu()
{
	printf("************************\n");
	printf("********1.paly**********\n");
	printf("********0.oxit**********\n");
	printf("************************\n");
	printf("请选择:");
}

void game()
{
	char  mine[ROWS][COLS];
	char  show[ROWS][COLS];
	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;
	do
	{
		menu();//打印菜单栏
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();//进入游戏
			break;
		case 0:
			printf("游戏结束,感谢参与");
			break;
		default:
			printf("输错了,请重新输一次");
			break;
		}

	} while (input);
	return 0;
}
头文件里的代码:
#pragma once

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

#define ROW 9
#define COL 9
#define ROWS  ROW+2
#define COLS  COL+2
#define COUNT 10
void Initboard(char board[ROWS][COLS], int rows, int cols, char set);
void Displayboard(char board[ROWS][COLS], int rows, int cols);
void Setmine(char board[ROWS][COLS], int rows, int cols);
int  Getminecount(char board[ROWS][COLS], int rows, int cols);
void Findmine(char mine[ROWS][COLS], char show[ROWS][COLS], int rows, int cols);

(注:前面写的片段代码都集中放到“game.c”这个文件里去。)

.扫雷游戏的扩展:

1.  是否可以选择游戏难度
例如:
    简单 9*9 棋盘,10个雷
    中等 16*16棋盘,40个雷
    困难 30*16棋盘,99个雷
2. 如果排查位置不是雷,周围也没有雷,可以展开周围的⼀⽚
3. 是否可以标记雷
4. 是否可以加上排雷的时间显示
....
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值