【C】C语言王国之扫雷游戏

①前言

扫雷是个老幼皆宜的游戏
它的玩法是 在一个9×9(初级)、16×16(中级)、16×30(高级)或自定义大小的方块矩阵中随机布置一定量的地雷(初级为10个,中级为40个,高级为99个),再由玩家逐个翻开方块,以找出所有地雷为最终游戏目标。如果玩家翻开的方块有地雷,则游戏结束。
了解了它的玩法后,让我们想想如何用C语言实现它呢?(以9*9为例)

在这里插入图片描述

②游戏实现步骤

1.制作menu菜单
2.定义2个char类型的数组mine[ ] 和show[ ],
mine数组用来存储雷的位置信息,show数组用来存储非雷位置周围雷的个数的信息
3.对mine和show数组进行初始化
mine数组全部初始化为字符0,show数组全部初始化为字符*,
4.布置雷并将信息存储在mine数组中,雷的位置由字符0改为字符1
5.排雷
6.打印数组

1.制作menu菜单

菜单界面就像餐厅里服务员递给你的菜单,根据菜单里的内容进行选择
选择1,开始游戏;选择0,结束游戏

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

2.实现多行多列扫雷

首先,我们会创建2个char类型的数组mine[ ] 和show[ ],
mine数组用来存储雷的位置信息,show数组用来存储非雷位置周围雷的个数的信息

    char mine[9][9] = {
    
     0 };
	char show[9][9] = {
    
     0 };

但由于我们想实现多行多列扫雷,也为了以后修改行数、列数和雷的个数的方便,
不妨使用#define宏定义

#define ROW 9//行
#define COL 9//列
#define LANDMINE 10//雷的个数

又为了后面搜索非雷位置周围的信息的方便(如9*9数组的最外边的两行两列因四周不足8个位置,所以在后面搜索非雷位置周围的信息同时,还要判断周围位置是否越界),不妨在原有数组的基础上,再加两行两列,它们在mine数组中全部初始化为字符0(这样就不用判断某个位置的周围位置是否越界)

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

效果:
在这里插入图片描述

3.初始化

定义两个数组后,接着将它们初始化
mine数组全初始化为字符0,show数组全部初始化为字符*,用set接收字符0和 *

    Initiate_board(mine, ROWS, COLS, '0');
	Initiate_board(show, ROWS, COLS, '*');
void Initiate_board(char mine[ROWS][COLS], int rows, int cols, char set)
{
    
    
	int i, j;
	for (i = 0; i < rows; i++)
		for (j = 0; j < cols; j++)
			mine[i][j] = set;
}

4.布置雷

	Set_mine(mine, ROW, COL);

1.注意,布置雷只用在上图浅蓝色的9*9区域,深蓝色的区域不用使用,所以传参时传的是原本的行和列rowcol,而非是加了两行两列的rows和cols

2.布置n个雷即要生成n个不同的符合要求的随机坐标,所以要使用rand()函数,而使用的前提是使用了srand()函数,所以为了实现能生成n个随机坐标,则要在主函数里调用一次srand((unsigned int)time(NULL));

void Set_mine(char mine[ROWS][COLS], int row, int col)
{
    
    
	int i = 0;
	while (i < LANDMINE)
	{
    
    
		int x = rand() % row + 1;//使得x的范围在1--row
		int y = rand() % col + 1;//使得y的范围在1--col
		if (mine[x][y] == '0')
		{
    
    
			mine[x][y] = '1';
			i++;
		}
	}
}

5.打印数组

	Display_board(mine, ROW, COL);

打印数组时,只用打印上图的浅蓝色区域,深蓝色区域不用打印,所以传参时传的是原本的行和列rowcol,而非是加了两行两列的rows和cols

为了使我们能快速知道某个位置是第几行第几列,可以采用如下代码

void Display_board(char mine[ROWS][COLS], int row, int col)
{
    
    
	int i, j;
	printf("\n----------扫雷----------\n");
	for (i = 0; i <= row; i++)//提示这是第几列
		printf("%d ", i);
	printf("\n");
	for (i = 1; i <= row; i++)
	{
    
    
		printf("%d ", i);//提示这是第几行
		for (j = 1; j <= col; j++)
			printf("%c ", mine[i][j]);//打印数组
		printf("\n");
	}
	printf("----------扫雷----------\n");
	printf("\n");
}

效果图:
在这里插入图片描述

6.开始排雷

先输入一个坐标,在mine数组里判断该位置是否是雷(即该位置是否为字符1),如果是,则提示“很遗憾,您被炸死了”;若不是,则查找周围位置有几个雷,并将雷的个数传到show数组的对应位置

	Search_mine(mine, show, ROW, COL);
int Search_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
    
    
	int x, y;
	int i = 0;
	while (i < ROW * COL - LANDMINE)//ROW * COL - LANDMINE表示非雷的个数
	{
    
    
		printf("请输入想要查找的位置:");
		scanf("%d%d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
    
    
			if (mine[x][y] == '1')//踩到炸弹后,直接退出循环
			{
    
    
				printf("\n很遗憾,您被炸死了\n");
				Display_board(mine, ROW, COL);
				break;
			}
			else if (show[x][y] != '*')
			{
    
    
				printf("该位置已排雷,请重新输入:\n");
			}
			else
			{
    
    
				int count = landmine_count(mine, x, y);//landmine_count()函数在下面介绍
				show[x][y] = count + '0';//使得该位置的数字几变成字符几
				Display_board(show, ROW, COL);
				i++;
			}
		}
		else
		{
    
    
			printf("输入错误,请重新输入\n");
		}
	}
	if (i == ROW * COL - LANDMINE)//当数组中的非雷位置全都排出,即为排雷成功
	{
    
    
		printf("\n恭喜你,扫雷成功\n");
		Display_board(mine, ROW, COL);
	}
}

7. landmine_count()函数

因为mine数组中全为字符0或1,又字符n减去字符0=数字n,所以雷的个数为该位置周围8个位置的字符之和减去8*字符0

int landmine_count(char mine[ROWS][COLS], int x,int y)
{
    
    
	return mine[x - 1][y - 1] + mine[x - 1][y] + mine[x - 1][y + 1]
		+ mine[x][y - 1] + mine[x][y + 1]
		+ mine[x + 1][y - 1] + mine[x + 1][y] + mine[x + 1][y + 1] - 8 * '0';
}

③模块化代码实现

1.text.c

#define _CRT_SECURE_NO_WARNINGS 1

#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 };
	//初始化
	Initiate_board(mine, ROWS, COLS, '0');
	Initiate_board(show, ROWS, COLS, '*');
	//Display_board(mine, ROW, COL);
	Display_board(show, ROW, COL);
	//布置雷
	Set_mine(mine, ROW, COL);
	Display_board(mine, ROW, COL);
	//扫雷
	Search_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;
}

2.game.h

#pragma once

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

#define LANDMINE 10

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

//初始化
void Initiate_board(char mine[ROWS][COLS], int rows, int cols, char set);
//打印
void Display_board(char mine[ROWS][COLS], int row, int col);
//布置雷
void Set_mine(char mine[ROWS][COLS], int row, int col);
//扫雷
int Search_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);


3.game.c

#define _CRT_SECURE_NO_WARNINGS 1

#include"game.h"

void Initiate_board(char mine[ROWS][COLS], int rows, int cols, char set)
{
    
    
	int i, j;
	for (i = 0; i < rows; i++)
		for (j = 0; j < cols; j++)
			mine[i][j] = set;
}

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

void Set_mine(char mine[ROWS][COLS], int row, int col)
{
    
    
	int i = 0;
	while (i < LANDMINE)
	{
    
    
		int x = rand() % row + 1;
		int y = rand() % col + 1;
		if (mine[x][y] == '0')
		{
    
    
			mine[x][y] = '1';
			i++;
		}
	}
}

int landmine_count(char mine[ROWS][COLS], int x,int y)
{
    
    
	return mine[x - 1][y - 1] + mine[x - 1][y] + mine[x - 1][y + 1]
		+ mine[x][y - 1] + mine[x][y + 1]
		+ mine[x + 1][y - 1] + mine[x + 1][y] + mine[x + 1][y + 1] - 8 * '0';
}

int Search_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
    
    
	int x, y;
	int i = 0;
	while (i < ROW * COL - LANDMINE)
	{
    
    
		printf("请输入想要查找的位置:");
		scanf("%d%d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
    
    
			if (mine[x][y] == '1')
			{
    
    
				printf("\n很遗憾,您被炸死了\n");
				Display_board(mine, ROW, COL);
				break;
			}
			else if (show[x][y] != '*')
			{
    
    
				printf("该位置已排雷,请重新输入:\n");
			}
			else
			{
    
    
				int count = landmine_count(mine, x, y);
				show[x][y] = count + '0';
				Display_board(show, ROW, COL);
				i++;
			}
		}
		else
		{
    
    
			printf("输入错误,请重新输入\n");
		}
	}
	if (i == ROW * COL - LANDMINE)
	{
    
    
		printf("\n恭喜你,扫雷成功\n");
		Display_board(mine, ROW, COL);
	}
}

猜你喜欢

转载自blog.csdn.net/qq_75000174/article/details/132045526