扫雷小游戏的编写,新手入门

目录

——模块组成

——编写思路

1. test.c内主函数及menu函数

2 游戏框架中game函数

2.1 test.c内

2.2 game.h内

 3 game函数的进一步扩充

3.1 定义棋盘

3.1.1 test.c内

3.1.2 game.c内

3.1.3 game.h内

3.2 初始化棋盘

3.2.1 game.h

3.2.2 game.c

3.2.3 test.c内

3.3 打印棋盘

3.3.1 game.h内

3.3.2 game.c内

3.3.3 test.c内

3.3.4 进一步修改完善

4 布置雷

4.1 test.c内

4.2 game.h内

4.3 game.c内

5 排查雷

5.1 test.c内

5.2 game.h内

5.3 game.c内

5.3.1 框架

5.3.2 get_mine_count函数的详细编写设计

5.3.3 游戏结束的编写

6 附完整代码

6.1 test.c内

6.2 game.h内

6.3 game.c内


——模块组成

test.c 扫雷游戏的测试逻辑

game.h 游戏函数的声明

game.c 游戏函数的实现

扫雷小游戏的编写,新手入门_第1张图片

显而易见,9*9的棋盘——>9*9的二维数组

考虑雷的情况:

扫雷小游戏的编写,新手入门_第2张图片扫雷小游戏的编写,新手入门_第3张图片

 如果是右图情况,要考虑最外围的数的周边存在越界判断的情况,为了避免繁复的判断是否越界,我们可以考虑将棋盘改变为11*11的棋盘,这样排除越界的可能,简化代码。

扫雷小游戏的编写,新手入门_第4张图片

       雷的布置,置1,非雷,置0;假如一个位置的周边有一个雷,其也显示为1;为了避免混淆1的概念究竟是置雷还是指周围置一个雷,我们可以弄两个棋盘,一个放置专门布置好的雷的信息(mine),另一个显示排查出的雷的信息(show)。

        mine数组初始化为“0”,布置雷时改成“1”;(这样布置的好处在5.3.2处有详细阐述

        show数组初始化为“*”,排查雷后,改为数字,例如“3”

扫雷小游戏的编写,新手入门_第5张图片扫雷小游戏的编写,新手入门_第6张图片

                                            放置好的雷                            雷的显示情况

——编写思路

1. test.c内主函数及menu函数

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

}

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

	return 0;
}

2 游戏框架中game函数

2.1 test.c内

#include "game.h"

void game()
{
	printf("扫雷\n");
}

2.2 game.h内

#include

运行结果为

扫雷小游戏的编写,新手入门_第7张图片

游戏框架已经搭建完成

 3 game函数的进一步扩充

3.1 定义棋盘

       由开始的思路梳理知,我们需要设置两个棋盘,一个放置专门布置好的雷的信息(mine),另一个显示排查出的雷的信息(show)。

        mine数组初始化为“0”,布置雷时改成“1”;

        show数组初始化为“*”,排查雷后,改为数字,例如“3”

为了便于以后修改棋盘大小(例如高阶棋盘不是 9*9),我们可以使用宏定义

3.1.1 test.c内

void game()
{
	//设置两个数组
	char mine[ROWS][COLS] = { 0 };
	char show[ROWS][COLS] = { 0 };

}

3.1.2 game.c内

#include"game.h"

3.1.3 game.h内

#define ROW 9
#define COL 9

#define ROWS ROW+2
#define COLS COL+2

3.2 初始化棋盘

3.2.1 game.h

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

3.2.2 game.c

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;
		}
	}
}

3.2.3 test.c内

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,'*');
}

3.3 打印棋盘

3.3.1 game.h内

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

3.3.2 game.c内

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

		}
		printf("\n");
	}
}

3.3.3 test.c内

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,'*');

	//打印棋盘
	display_board(mine, ROW, COL);
	display_board(show, ROW, COL);

}

扫雷小游戏的编写,新手入门_第8张图片

3.3.4 进一步修改完善

          以上代码运行结果为此,为了使其更加美观,我们添上行列序号

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

		}
		printf("\n");
	}
}

     

扫雷小游戏的编写,新手入门_第9张图片

       行1与列1的打印使棋盘的列与列序不对应,我们可以选择在列1前打印一个空格,使其位置对应,我们也可以打印0的方式,使列序对应。只需将列号j的打印从0开始即可。

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

		}
		printf("\n");
	}
}

        

扫雷小游戏的编写,新手入门_第10张图片

         两个棋盘中,show棋盘是我们所能看得到的棋盘,并且是我们要排雷操作后的show棋盘,所以test.c内修改为:


	//打印棋盘
	//display_board(mine, ROW, COL);
	//display_board(show, ROW, COL);

4 布置雷

4.1 test.c内

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,'*');

	//打印棋盘
	//display_board(mine, ROW, COL);
	display_board(show, ROW, COL);

	//布置雷
	set_mine(mine,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");
			break;
		default:
			printf("选择错误,重新选择\n");
			break;
		}
	} while (input);

	return 0;
}

main函数内使用srand函数,并引入相关头文件

4.2 game.h内

#include
#include

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

4.3 game.c内

void set_mine(char mine[ROWS][COLS], int row, int col)
{
	//布置10个雷
	int count = 10;
	while (count)
	{
		int x = rand() % row + 1;//x是1到9
		int y = rand() % col + 1;//y是1到9

		if (mine[x][y] == '0')//判断是否已经是雷
		{
			mine[x][y] = '1';//置雷
			count--;
		}
	}
}

5 排查雷

5.1 test.c内

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,'*');

	//打印棋盘
	//display_board(mine, ROW, COL);
	display_board(show, ROW, COL);

	//布置雷
	set_mine(mine, ROW, COL)

	//排查雷
	find_mine(mine,show,ROW, COL);

}

5.2 game.h内

对mine数组排查操作,其结果储存显示在show数组内,也要了解row,col的具体数值

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

5.3 game.c内

5.3.1 框架

void find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	printf("请输入要排查雷的坐标:>");
	scanf("%d %d", &x, &y);
	//排查区域在11*11棋盘中间的9*9范围内
	if (x >= 1 && x <= row && y >= 1 && y <= col)
	{

	}
	else
	{
		printf("坐标非法,请重新输入\n");
	}

}

重新输入的地方再次回到if判断,由此可知为循环结构,修改完善如下:

void find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;

	while (1)
	{
    	printf("请输入要排查雷的坐标:>");
	    scanf("%d %d", &x, &y);
	    //排查区域在11*11棋盘中间的9*9范围内
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			
		}
		else
		{
			printf("坐标非法,请重新输入\n");
		}
	}

}

判断目标坐标周围的雷的个数,在if内我们可以封装一个实现此功能的函数,对mine数组用此函数排查,并储存在show数组内:

void find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	
	while (1)
	{
        printf("请输入要排查雷的坐标:>");
    	scanf("%d %d", &x, &y);
	    //排查区域在11*11棋盘中间的9*9范围内
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			int count = get_mine_count(mine, x, y);
			show[x][y] = count + '0';
		}
		else
		{
			printf("坐标非法,请重新输入\n");
		}
	}

}

此处对该行代码作补充说明

show[x][y] = count + '0';

show数组类型为char,而count为int类型,我们需要将其类型转换再储存到show数组内,

通过ASCII表可知,‘2’-‘0’=50-48=2,‘9’-‘0’=57-48=9;

所以此处可知char-‘0’=count,所以show[x][y]=count+'0';

扫雷小游戏的编写,新手入门_第11张图片

 (上图左列为十进制数值,右列为字符)

5.3.2 get_mine_count函数的详细编写设计

扫雷小游戏的编写,新手入门_第12张图片

        在mine棋盘内,我们以字符‘1’的方式置雷类比上面单独解释的代码,我们可以通过对目标坐标的周边一圈字符进行减‘0’操作得到数值,将所有数值相加即可得到周边雷的个数,我们对此做进一步解释说明:

扫雷小游戏的编写,新手入门_第13张图片

        对黄色框内的中央位置为我们的目标x,y,对其mine数组内棋盘内雷的分布假设如图所示

以[x-1][y-1]为例,内置‘1’,即有雷分布,对其减‘0’,‘1’-‘0’=1,1可作为雷数直接储存,所以我们可以理解在文章开始时,我们对mine数组内用字符‘1’作为雷的标志的意义所在。

        周边8个坐标都作上述的处理,再相加,我们可简化为

        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';

         所以get_mine_count函数的编写如下(game.c内):

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');
}

此函数只对mine数及其【x】【y】处作处理,所以(char mine[ROWS][COLS], int x, int y),

排雷完成后打印show棋盘:

此时若想检验已编写程序的正确性,我们可以将mine数组打印出来看一看

扫雷小游戏的编写,新手入门_第14张图片

        由此检验我们的排雷是正确的。

5.3.3 游戏结束的编写

9*9=81的棋盘,若放置10个雷,找出非雷的71格即可游戏成功;

踩雷炸死也即结束;

对于刚刚我们输入排雷的坐标,我们需判断其是否为雷,才能进一步进行排雷,对其修改如下:

void find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	
	while (1)
	{
		printf("请输入要排查雷的坐标:>");
		scanf("%d %d", &x, &y);
		//排查区域在11*11棋盘中间的9*9范围内
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (mine[x][y] == '1'
			{
				printf("很遗憾,你被炸死了\n");
				//并且打印mine数组,让玩家死的瞑目
				display_board(mine, ROW, COL);
					//游戏结束
				break;
			}
			else 
			{
				int count = get_mine_count(mine, x, y);
					show[x][y] = count + '0';
					display_board(show, ROW, COL);
			}

		}
		else
		{
			printf("坐标非法,请重新输入\n");
		}
	}

}

对于另一种游戏结束的方式,我们可以设置一个win变量,当win

game.h内

#define DEFAULT_COUNT 10

game.c内

void set_mine(char mine[ROWS][COLS], int row, int col)
{
	//布置10个雷
	int count = DEFAULT_COUNT;(修改一下)
	while (count)
	{
		int x = rand() % row + 1;//x是1到9
		int y = rand() % col + 1;//y是1到9

		if (mine[x][y] == '0')//判断是否已经是雷
		{
			mine[x][y] = '1';//置雷
			count--;
		}
	}
}
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");
		scanf("%d %d", &x, &y);
		//排查区域在11*11棋盘中间的9*9范围内
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (mine[x][y] == '1')
			{
				printf("很遗憾,你被炸死了\n");
				//并且打印mine数组,让玩家死的瞑目
				display_board(mine, ROW, COL);
					//游戏结束
				break;
			}
			else 
			{
				int count = get_mine_count(mine, x, y);
				show[x][y] = count + '0';
				display_board(show, ROW, COL);
				win++;
			}
		}
		else
		{
			printf("坐标非法,请重新输入\n");
		}
		if (win == row * col - DEFAULT_COUNT)
		{
			printf("恭喜你,排雷成功\n");
			//打印雷的真实情况
			display_board(mine, ROW, COL);
		}
	}

}

为了检验上述代码,我们可以先定义DEFAULT_COUNT=80,并且看mine棋盘的情况,进行定点排雷检验代码是否正确:

game.h内

#define DEFAULT_COUNT 80

扫雷小游戏的编写,新手入门_第15张图片

此处游戏基本完成,但是存在一个bug,如果我们每次排查的都是同一个坐标,达到一定次数之后,win++到某一个数值,也算游戏成功,我们需要再对坐标作合法判断,我们可以通过show棋盘上放置的是'*',来判断该位置未被排查过:

while (win");
		scanf("%d %d", &x, &y);
		//排查区域在11*11棋盘中间的9*9范围内
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			//坐标是否被排查过
			if (show[x][y] == '*')
			{
				if (mine[x][y] == '1')
				{
					printf("很遗憾,你被炸死了\n");
					//并且打印mine数组,让玩家死的瞑目
					display_board(mine, ROW, COL);
					//游戏结束
					break;
				}
				else
				{
					int count = get_mine_count(mine, x, y);
					show[x][y] = count + '0';
					display_board(show, ROW, COL);
					win++;
				}
			}
			else
			{
				printf("该坐标已经被排查过了\n");
			}
		}
		else
		{
			printf("坐标非法,请重新输入\n");
		}
		if (win == row * col - DEFAULT_COUNT)
		{
			printf("恭喜你,排雷成功\n");
			//打印雷的真实情况
			display_board(mine, ROW, COL);
		}
	}

}

为了符合游戏的基本设定及良好的游戏体验,我们一开始不打印mine棋盘,之前的打印为了方便代码调试,并且我们打印show棋盘,修改如下:

test.c内

	//排查雷
	//display_board(mine, ROW, COL);
	display_board(show, ROW, COL);

	find_mine(mine,show, ROW, COL);

游戏运行如下:

扫雷小游戏的编写,新手入门_第16张图片

本文结束,感谢阅览。

6 附完整代码

6.1 test.c内

#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 };
	//初始化棋盘
	//mine初始化为全"0"
	//show初始化为全"*"
	init_board(mine, ROWS, COLS,'0');
	init_board(show, ROWS, COLS,'*');

	//打印棋盘
	//display_board(mine, ROW, COL);
	//display_board(show, ROW, COL);

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

	//排查雷
	//display_board(mine, ROW, COL);
	display_board(show, 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("退出游戏:\n");
			break;
		default:
			printf("选择错误,重新选择\n");
			break;
		}
	} while (input);

	return 0;
}

6.2 game.h内

#pragma once

#include
#include
#include

#define ROW 9
#define COL 9

#define ROWS ROW+2
#define COLS COL+2

#define DEFAULT_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);

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

6.3 game.c内

#define _CRT_SECURE_NO_WARNINGS 1

#include"game.h"

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;
		}
	}
}

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

		}
		printf("\n");
	}
}

void set_mine(char mine[ROWS][COLS], int row, int col)
{
	//布置10个雷
	int count = DEFAULT_COUNT;
	while (count)
	{
		int x = rand() % row + 1;//x是1到9
		int y = rand() % col + 1;//y是1到9

		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 win = 0;
	
	while (win");
		scanf("%d %d", &x, &y);
		//排查区域在11*11棋盘中间的9*9范围内
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			//坐标是否被排查过
			if (show[x][y] == '*')
			{
				if (mine[x][y] == '1')
				{
					printf("很遗憾,你被炸死了\n");
					//并且打印mine数组,让玩家死的瞑目
					display_board(mine, ROW, COL);
					//游戏结束
					break;
				}
				else
				{
					int count = get_mine_count(mine, x, y);
					show[x][y] = count + '0';
					display_board(show, ROW, COL);
					win++;
				}
			}
			else
			{
				printf("该坐标已经被排查过了\n");
			}
		}
		else
		{
			printf("坐标非法,请重新输入\n");
		}
		if (win == row * col - DEFAULT_COUNT)
		{
			printf("恭喜你,排雷成功\n");
			//打印雷的真实情况
			display_board(mine, ROW, COL);
		}
	}

}

你可能感兴趣的:(c语言,c语言,青少年编程)