C语言扫雷小游戏(优化)

相信大家都有玩过扫雷游戏吧,今天我们来用C语言程序来实现这样一个小游戏!

目录

一、游戏规则

二、基本思路

三、代码实现

1.菜单目录和玩家进入游戏提示

2. 编写游戏

3.初始化棋盘

4.布置雷

5.打印棋盘:

6.排查雷:

(1)统计雷的个数:

(2)判断周围是否为0

(3)打印最后的棋盘:

7.建立game.h

四、源代码

test.c

game.h

game.c

运行结果:

一、游戏规则

在给定的棋盘中,随机生成雷,玩家随机点击一个格子,格子中显示数字,该数字就是周围雷的个数的总数。玩家需要通过此方法排查出雷,直到所有雷排查完毕或者踩雷,游戏结束!

在这个程序中,我们暂定棋盘为9×9宫格,随机生成10个雷(后期如果想改变可以直接改)。

布置雷时,我们可以用‘ 0 ’来表示这个位置没有雷,用‘ 1 ’来表示这个位置是有雷的(用“1”来表示雷是为了更好的统计雷的个数)

二、基本思路

1.棋盘的设置:此游戏应该有两个棋盘:一个是玩家可见的,一个是玩家不可见的。雷应该放在不可见的棋盘上。

2.棋盘的初始化:可见的棋盘用“ * ”初始化打印,而不可见的棋盘用“ 0 ”初始化。

3.雷的布置:随机生成一个数,将该位置给成“ 1 ”

4.统计雷的个数:计算周围元素并相加

5.进行排雷:直到碰到雷或者排完雷为止,游戏结束!

三、代码实现

1.菜单目录和玩家进入游戏提示

main函数中,因为游戏不只可以玩一次,玩家可以控制玩多少次。这里我们设置 “ 1 ” 为进入游戏,而“ 0 ”为退出游戏。因此这里应该运用到do-while语句和switch-case语句。

void menu()//菜单实现
{
	printf("***********************\n");
	printf("*****   1.play   ******\n");
	printf("*****   0.exit   ******\n");
	printf("***********************\n");
}
int main() {
	srand((unsigned int)time(NULL));
	int input = 0;
	do
	{
		menu();//游戏菜单
		printf("请输入:");
		scanf("%d", &input);//玩家输入是否进行游戏
		switch (input)
		{
		case 1:
			game();//输入“1”则进入游戏
			break;
		case 0:
			printf("游戏结束!");//输入“0”则退出游戏
			break;
		default:
			printf("输入有误!请重新输入.");//输入1 0之外的提示输入错误
			break;

		}

	} while (input);
2. 编写游戏

这里我们用game()函数来封装。game()函数中应该包含:棋盘的初始化、雷的布置、排雷判断、打印棋盘。

void game()
{
	char mine[ROWS][COLS] = { 0 };//定义二维数组隐藏棋盘
	char show[ROWS][COLS] = { 0 };//定义二维数组隐藏棋盘
	Initboard(mine, ROWS, COLS,'0');//初始化隐藏棋盘
	Initboard(show, ROWS, COLS, '*');//初始化可视棋盘
	Setmine(mine, ROW, COL);//布置雷
	Displayboard(show, ROW, COL);//打印可视棋盘
	Findmine(mine, show, ROW, COL);//排查雷,判断,最后出结果
}
3.初始化棋盘

定义char set可以不用创建两个函数来初始化两个棋盘,只需要传入 “ * ” ,“ 0 ”。

void Initboard(char board[ROWS][COLS], int rows, int cols, char set)
{
	int i;
	int j;
	for (i = 0; i < rows; i++)
	{
		for (j = 0; j < cols; j++)
		{
			board[i][j] = set;
		}
	}
}
4.布置雷

定义两个随机数,并将其坐标变成 “ 1 ”

void Setmine(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--;
		}

	}
}
5.打印棋盘:
void Displayboard(char board[ROWS][COLS], int row, int col)
{
	int i;
	int j;
	for (i = 0; i <= row; i++)//打印坐标,第一个坐标为空格
	{
		if (i == 0)
			printf("  ");
		else
			printf("%d ", i);
	}
	printf("\n");
	for (i = 1; i <= row; i++)
	{
		printf("%d ", i);
		for (j = 1; j <= col; j++)
		{
			printf("%c ", board[i][j]);
		}
		printf("\n");
	}
}

6.排查雷:

这一函数中包含雷个数的统计,判断玩家的坐标与雷是否相同,判断周围是否为0,若为0,自动变成空格(避免了9个格子都是0但要一个一个的排)。

void Findmine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int count = row * col - EASY_COUNT;
	while (1)
	{
		printf("请输入一个坐标(排查雷):");
		scanf("%d%d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (mine[x][y] == '1')
			{
				printf("很遗憾你被炸死了!\n");
				DisplayEnd(mine, show, ROW, COL);//打印最后的棋盘,包含雷和玩家选的坐标
				break;
			}
			else
			{
				Judgemine(mine, show, x, y,&count);//判断周围是否为0
				Displayboard(show, ROW, COL);
			}
		}
		else
		{
			printf("坐标输入有误!请重新输入!");
		}
		if (count == 0)//雷排完了
		{
			printf("恭喜你!排雷成功!\n");
			DisplayEnd(mine, show, ROW, COL);
			break;
		}
	}
}
(1)统计雷的个数:

统计上下左右坐标的数字(由于当初布置雷的时候雷是字符“1”,所以结果需要减去8×字符“0”)。

int Total(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 来累加)

int Total(char mine[ROWS][COLS], int x, int y)
{
	int sum = 0;
	for (int i = -1; i <= 1; i++)
	{
		for (int j = -1; j <= 1; j++)
		{
			if (mine[x + i][y + j] == '1')
			{
				sum++;
			}
		}
	}
	return sum;
}
(2)判断周围是否为0

(这个是优化游戏的一个函数)

void Judgemine(char mine[ROWS][COLS],char show[ROWS][COLS],int x,int y,int *count)
{
	int i;
	int j;
	if (x >= 1 && x <= 9 && y >= 1 && y <= 9 && mine[x][y] == '0' && show[x][y] == '*')
	{
		if (Total(mine, x, y))
		{
			show[x][y] = Total(mine, x, y) + '0';
			(*count)--;
		}
		else
		{
			show[x][y] = ' ';
			(*count)--;
			for (i = -1; i <= 1; i++)
			{
				for (j = -1; j <= 1; j++)
				{
					Judgemine(mine, show, x + i, y + j, count);
				}
			}
		}
	}

}
(3)打印最后的棋盘:

游戏结束后,打印玩家坐标和雷的位置

void DisplayEnd(char mine[ROWS][COLS], char show[ROWS][COLS], int rows, int cols)
{
	{
		int i = 0;
		int j = 0;
		for (i = 0; i <= rows; i++)
		{
			printf("%d ", i);
		}
		printf("\n");
		for (i = 1; i <= rows; i++)
		{
			printf("%d ", i);
			for (j = 1; j <= cols; j++)
			{
				if (mine[i][j] == '1')//如果是雷就打印出来
				{
					mine[i][j] = '@';
					printf("%c ", mine[i][j]);//与打印棋盘唯一不同之处
				}
				else
				{
					printf("%c ", show[i][j]);
				}
			}
			printf("\n");
		}
		printf("\n");
	}
}
7.建立game.h

由于要用到众多函数,所以建立一个头文件game.h来定义函数

#pragma once
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <windows.h>
#define ROW 9
#define COL 9
#define ROWS ROW+2 //判断边界值时需要用到额外的格子
#define COLS COL+2 //判断边界值时需要用到额外的格子
#define EASY_COUNT 10
void Initboard(char board[ROWS][COLS], int rows, int cols, char set);
void Displayboard(char board[ROWS][COLS], int row, int col);
void Setmine(char mine[ROWS][COLS], int row, int col);
void Findmine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
int Total(char mine[ROWS][COLS], int x, int y);
void DisplayEnd(char mine[ROWS][COLS], char show[ROWS][COLS], int rows, int cols);
void Judgemine(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y, int* count);

四、源代码

test.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 };
	Initboard(mine, ROWS, COLS,'0');//初始化隐藏棋盘
	Initboard(show, ROWS, COLS, '*');//初始化可视棋盘
	Setmine(mine, ROW, COL);//布置雷
	Displayboard(show, ROW, COL);//打印可视棋盘
	Findmine(mine, show, ROW, COL);//排查雷,判断,最后出结果
}
int main() {
	srand((unsigned int)time(NULL));
	int input = 0;
	do
	{
		menu();
		printf("请输入:");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("游戏结束!");
			break;
		default:
			printf("输入有误!请重新输入.");
			break;

		}

	} while (input);

	return 0;

}
game.h
#pragma once
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <windows.h>
#define ROW 9
#define COL 9
#define ROWS ROW+2 //判断边界值时需要用到额外的格子
#define COLS COL+2 //判断边界值时需要用到额外的格子
#define EASY_COUNT 10
void Initboard(char board[ROWS][COLS], int rows, int cols, char set);
void Displayboard(char board[ROWS][COLS], int row, int col);
void Setmine(char mine[ROWS][COLS], int row, int col);
void Findmine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
int Total(char mine[ROWS][COLS], int x, int y);
void DisplayEnd(char mine[ROWS][COLS], char show[ROWS][COLS], int rows, int cols);
void Judgemine(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y, int* count);
game.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
//初始化棋盘
void Initboard(char board[ROWS][COLS], int rows, int cols, char set)
{
	int i;
	int j;
	for (i = 0; i < rows; i++)
	{
		for (j = 0; j < cols; j++)
		{
			board[i][j] = set;
		}
	}
}
//打印棋盘
void Displayboard(char board[ROWS][COLS], int row, int col)
{
	int i;
	int j;
	for (i = 0; i <= row; i++)
	{
		if (i == 0)
			printf("  ");
		else
			printf("%d ", i);
	}
	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 Setmine(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 Total(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 Total(char mine[ROWS][COLS], int x, int y)
{
	int sum = 0;
	for (int i = -1; i <= 1; i++)
	{
		for (int j = -1; j <= 1; j++)
		{
			if (mine[x + i][y + j] == '1')
			{
				sum++;
			}
		}
	}
	return sum;
}
//排查雷
void Findmine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int count = row * col - EASY_COUNT;
	while (1)
	{
		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);
				DisplayEnd(mine, show, ROW, COL);
				break;
			}
			else
			{
				//int total = Total(mine, x, y);
				//show[x][y] = total + '0';
				//count--;
				Judgemine(mine, show, x, y,&count);
				Displayboard(show, ROW, COL);
			}
		}
		else
		{
			printf("坐标输入有误!请重新输入!");
		}
		if (count == 0)
		{
			printf("恭喜你!排雷成功!\n");
			DisplayEnd(mine, show, ROW, COL);
			break;
		}
	}
}

//判断周围是否为0
void Judgemine(char mine[ROWS][COLS],char show[ROWS][COLS],int x,int y,int *count)
{
	int i;
	int j;
	if (x >= 1 && x <= 9 && y >= 1 && y <= 9 && mine[x][y] == '0' && show[x][y] == '*')
	{
		//mine[x][y] = '2';
		if (Total(mine, x, y))
		{
			show[x][y] = Total(mine, x, y) + '0';
			(*count)--;
		}
		else
		{
			show[x][y] = ' ';
			(*count)--;
			for (i = -1; i <= 1; i++)
			{
				for (j = -1; j <= 1; j++)
				{
					Judgemine(mine, show, x + i, y + j, count);
				}
			}
		}
	}

}
//打印结局
void DisplayEnd(char mine[ROWS][COLS], char show[ROWS][COLS], int rows, int cols)
{
	{
		int i = 0;
		int j = 0;
		for (i = 0; i <= rows; i++)
		{
			printf("%d ", i);
		}
		printf("\n");
		for (i = 1; i <= rows; i++)
		{
			printf("%d ", i);
			for (j = 1; j <= cols; j++)
			{
				if (mine[i][j] == '1')//如果是雷就打印出来
				{
					mine[i][j] = '@';
					printf("%c ", mine[i][j]);//与打印棋盘唯一不同之处
				}
				else
				{
					printf("%c ", show[i][j]);
				}
			}
			printf("\n");
		}
		printf("\n");
	}
}
运行结果:

评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值