C语言怎样写扫雷

这篇具有很好参考价值的文章主要介绍了C语言怎样写扫雷。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.自己写的扫雷要有什么功能与机制(主要的)

1.生成基础雷盘

在游戏开始时,基础雷盘就生成完毕。在基础雷盘上,地雷已经随机分布,每一格周围有多少地雷也已经计算完成并显示在这一格上。可以理解为,透视版的扫雷。下图就是基础雷盘的展现(现实中并不会展现基础雷盘)
C语言怎样写扫雷,扫雷,c语言,c语言,游戏

2.生成表面雷盘

现实中当然没有透视版的扫雷,基础雷盘并不是我们想让玩家看到的。这时候就需要表面雷盘了。表面雷盘的每一格都是未知,当玩家选中了某一格,那就会将基础雷盘中相应格的内容投射到表面雷盘,这个内容可能是数字,也可能是地雷,那得要看玩家怎么选了。下图就是表面雷盘。(表面雷盘才是真正给玩家看到的)
C语言怎样写扫雷,扫雷,c语言,c语言,游戏

读到此处,相信你已经明白我们要写的扫雷的核心原理了。也就是当玩家选中了表面雷盘的某一格,就会将基础雷盘的内容投射到表面雷盘的对应格上。显然,随着游戏的逐步进行,表面雷盘的内容将不断接近基础雷盘。当然,现实中的基础雷盘与表面雷盘只是抽象的两个二维数组,并非就是上面的两张图。只是表面雷盘是我们想让玩家看到的,因此包装成上图的样子,而基础雷盘无需包装。

3.零的扩散机制

如何减少玩家操作次数,原版扫雷很聪明的利用了零的扩散机制。当玩家选中的点是零,那么就会往四周扩散,直到遇到不为零的点,具体请看功能与机制的实现第三点。(下图是经过一次操作后,扩散出来的一片数字)
C语言怎样写扫雷,扫雷,c语言,c语言,游戏

2.功能与机制的实现(主要的)

1.基础雷盘随机布雷机制

为了方便存储及调用每一格的内容,作者采用了两个二维数组分别储存基础雷盘表面雷盘的内容。提到随机布雷,大家可能第一反应会想到用随机数生成一个随机坐标,若该坐标对应的格中没有地雷,那么就在这一格放一个地雷,若该坐标对应的格中已有地雷,就跳过该点,重复以上步骤直到地雷数量达到设定值。但是这种布雷方式有一个致命问题:当重复的次数不断增加时,所剩的空格也就越来越少,此时随机坐标找到空格的几率也就越来越小。因此布雷效率低下。作者采用了另一种布雷方式——遍历法。如下图。(图片来自知乎作者eee555,请忽视图片右下角水印)
C语言怎样写扫雷,扫雷,c语言,c语言,游戏
运用这种方法,只需要将每一格都遍历一次,就完成了布雷,十分高效。如何让每一格的布雷概率是未布的雷数/未访问的雷位置数?作者用了一种方法:生成一个随机数a(范围:0——未访问的位置数-1),如果a的范围又正好在(0——未布的雷数-1)之间,那么就在这一格布雷。这样,每一格的布雷概率恰好是未布的雷数/未访问的雷位置数。以下是代码的实现。

void resetboard_1(char board_1[X][Y], int choosex, int choosey)//resetboard_1即重置基础雷盘,重新布雷
{
	int cx, cy, bombnum = num, boardnum = x * y - 1, tmp;//cx,cy
	//bombnum是剩余的未放置的地雷数,boardnum是剩余的未访问的点数
	for (cx = 0; cx < x; cx++)
	{
		for (cy = 0; cy < y; cy++)
		{
			if (cx != choosex || cy != choosey)
                //choosex,choosey的作用是为了不在玩家的第一个选中格中防雷,避免开局即结局
			{
				tmp = rand() % boardnum;//生成0~boardnum-1的随机数tmp
				if (tmp < bombnum)//如果tmp在0~bombnum-1内,那么就在该点布雷
				{
					board_1[cx][cy] = '*';//在board_1[cx][cy]处放置地雷,*代表地雷
					bombnum--;//放置一个地雷,bumbnum-1
				}
				boardnum--;//访问一个点,boardnum-1
			}
		}
	}
}

2.基础雷盘的计数方法

基础雷盘的每一个非地雷的格,都有一个数字,数字代表其周围的地雷数量。那么要如何计算得到这些数字呢?前面说到,我们用二维数组存放了基础雷盘的内容,那么答案显然是从数组入手,只要通过数组找出周围的格内容,并累计地雷数,就可以实现计数。但是要注意,当我们使用数组查找内容时,应避免出现数组越界访问。以下是代码的实现。

void scoreboard_1(char board_1[X][Y])//用于计算每一个格周围有多少地雷
{
	int dx, dy, score;//dx,dy遍历整个数组
	for (dx = 0; dx < x; dx++)
	{
		for (dy = 0; dy < y; dy++)
		{
			if (board_1[dx][dy] != '*')//非地雷格才需要计数,地雷格不用计数
			{
				score = 0;
				//向上判断 1
				if (dx > 0)//避免数组越界访问
				{
					if (board_1[dx - 1][dy] == '*')
					{
						score++;
					}
				}
				//向右上判断 2
				if (dx > 0 && dy < y - 1)//避免数组越界访问
				{
					if (board_1[dx - 1][dy + 1] == '*')
					{
						score++;
					}
				}
				//向右判断 3
				if (dy < y - 1)//避免数组越界访问
				{
					if (board_1[dx][dy + 1] == '*')
					{
						score++;
					}
				}
				//向右下判断 4
				if (dx < x - 1 && dy < y - 1)//避免数组越界访问
				{
					if (board_1[dx + 1][dy + 1] == '*')
					{
						score++;
					}
				}
				//向下判断 5
				if (dx < x - 1)//避免数组越界访问
				{
					if (board_1[dx + 1][dy] == '*')
					{
						score++;
					}
				}
				//向左下判断 6
				if (dx < x - 1 && dy>0)//避免数组越界访问
				{
					if (board_1[dx + 1][dy - 1] == '*')
					{
						score++;
					}
				}
				//向左判断 7
				if (dy > 0)//避免数组越界访问
				{
					if (board_1[dx][dy - 1] == '*')
					{
						score++;
					}
				}
				//向左上判断 8
				if (dx > 0 && dy > 0)//避免数组越界访问
				{
					if (board_1[dx - 1][dy - 1] == '*')
					{
						score++;
					}
				}
				board_1[dx][dy] = score + 48;//加48,请查询asc码表
                //score即为周围的雷数,加48转化为字符的数字
			}
		}
	}
}

3.投射及零的扩散机制

当玩家选中了表面雷盘的某一格时,将会把基础雷盘中相应的内容投射表面雷盘中(包括地雷),对应的代码实现就是board_2[x][y]=board_1[x][y];(board_2是表面雷盘的数组,board_1是基础雷盘的数组)。在投射中有一种特殊情况,那就是投射的内容为零,也就是选中格周围没有地雷,那将其四周的格再次投射,若其周围的格还是零,就将其周围的格的周围的格投射……这就是零的扩散。以下是代码的实现。

void chooseboard_2(char board_1[X][Y], char board_2[X][Y], int choosex, int choosey)//选择投射该点
{//board_1是基础雷盘的数组,board_2是表面雷盘的数组
	if (board_2[choosex][choosey] == ' ' || board_2[choosex][choosey] == '?')//若board_2该点未被占用
	{
		if (board_1[choosex][choosey] != 48)//board_1该点不等于'0',不扩散
		{
			board_2[choosex][choosey] = board_1[choosex][choosey];
		}
		else if (board_1[choosex][choosey] == 48)//若该点等于'0',往四个方向扩散			
		{//后来作者查了一下原版扫雷机制,好像是往周围八格扩散,而不是周围四格,如果想要改的话,将chooseboard_2函数多嵌套几次就行,如果不太清楚原理的话还是不要改了doge
			board_2[choosex][choosey] = board_1[choosex][choosey];
			if (choosex < x - 1)//往下
			{
				chooseboard_2(board_1, board_2, choosex + 1, choosey);
			}
			if (choosex > 0)//往上
			{
				chooseboard_2(board_1, board_2, choosex - 1, choosey);
			}
			if (choosey < y - 1)//往右
			{
				chooseboard_2(board_1, board_2, choosex, choosey + 1);
			}
			if (choosey > 0)//往左
			{
				chooseboard_2(board_1, board_2, choosex, choosey - 1);
			}
		}
	}
}

3.次要功能的实现

1.雷盘大小设置

众所周知,经典的扫雷有三种规格(长,宽,雷数):1.小(9,9,9);2.中(16,16,40);3.大(30,16,99);作者同样设计了三种规格。如下图。
C语言怎样写扫雷,扫雷,c语言,c语言,游戏
C语言怎样写扫雷,扫雷,c语言,c语言,游戏
C语言怎样写扫雷,扫雷,c语言,c语言,游戏
已知创建数组char board[X][Y]={0};时,X和Y必须为常量,如果想要创建多个不同元素数量的数组来实现不同规格的转换,显然十分复杂。要如何实现规格的转换而不需要调整代码呢?不妨直接创建元素数量为30*16(最大规格)的数组,但打印表面雷盘以及基础雷盘的内容存储只使用相应规格的元素数量,这样问题就以迎刃而解了。

2.表面雷盘的格的标记与取消标记

实现起来也很简单,若表面雷盘的选中格为空(当然也不包括数字),则使这一格的内容为’ ? ‘,实现标记;若选中格为’ ? ',则使这一格的内容为空,实现取消标记。以下为代码的实现。

				if (board_2[choosex][choosey] == ' ')
				{
					board_2[choosex][choosey] = '?';//标记该点
					hudnum--;
				}
				else if (board_2[choosex][choosey] == '?')
				{
					board_2[choosex][choosey] = ' ';//取消标记该点
					hudnum++;
				}
			}

3.输赢判断机制

  1. :很简单,当表面雷盘被投射了地雷,也就相当于玩家选中了有地雷的格,判断为输;
  2. :即表面雷盘的所有格已被探明,且没有点开地雷格;
  3. 未结束:即表面雷盘仍有格未被探明,且没有点开地雷格。

输的判断十分简单,这里作者想讨论一下赢和未结束的判断。首先我们定义一个概念重合度:表面雷盘与基础雷盘内容相同的格数。当玩家选择某一格,那么基础雷盘的相应内容就会被投射到表面雷盘,当游戏不断进行,越来越多的内容从基础雷盘投射到表面雷盘,这样他俩的重合度显然会逐步升高。假设雷盘的规格为小(9*9),假若基础雷盘与表面雷盘有1格相同,那么重合度为1;假若基础雷盘与表面雷盘有10格相同,那么重合度为10……假若基础雷盘与表面雷盘有81格相同,那么重合度为81?错误,因为地雷格的内容不会被投射,否则就是输。

至此,判断赢和未结束的方法已经出现。假如重合度=雷盘总格数-地雷总数,那么判断为赢,也就是除了地雷格,其余格子完全相同;假如重合度<雷盘总格数-地雷总数,那么判断为未结束。当然,赢和未结束的判断都要建立在没有输的基础上。以下为代码的实现。

int testboard_2(char board_1[X][Y], char board_2[X][Y], int choosex, int choosey)
{//board_1是基础雷盘的数组,board_2是表面雷盘的数组,choosex和choosey并没有什么用,不过也不影响
	int ex, ey, score = 0;//ex,ey遍历整个数组
	for (ex = 0; ex < x; ex++)
	{
		for (ey = 0; ey < y; ey++)
		{
			if (board_2[ex][ey] == '*')//踩到地雷啦
			{
				return 0;//判断为输
			}
			if (board_1[ex][ey] == board_2[ex][ey])//计算board_1和board_2的重合度
			{
				score++;//累计重合度
			}
		}
	}
	if (score == x * y - num)//重合度=x*y-num,即所偶有点位已被探明,胜利
	{//x*y即雷盘总格数,num即总地雷数
		return 1;//判断为赢
	}
	else
	{
		return 2;//重合度<x*y-num,判断为未结束,其实连返回值都不用,没有结束,程序不需要作出任何反应
	}
}

4.全部代码

1.说明

作者使用的编译器是visual studio 2022。除了以上提到的内容以为,作者还增加了不同数字的配色、设置界面、主界面、游戏界面、剩余未标记地雷数HUD显示等内容。具体请看运行程序或全部代码。各位记得一键三联哦!!!

2.game.h

#pragma once

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<windows.h>
#include<time.h>
#include<stdlib.h>

#define X 16
#define Y 30//雷盘的二维数组行列数(最大规格)

int x, y, z, num, hudnum;
//行数,列数,雷盘大小标号,雷数
char board_1[X][Y], board_2[X][Y];


void initboard(char board[X][Y]);//基础雷盘与表面雷盘数组的初始化函数
void printboard_2(char board_2[X][Y]);//打印表面雷盘的函数
void resetboard_1(char board_1[X][Y], int choosex, int choosey);//基础雷盘的布雷函数
void scoreboard_1(char board_1[X][Y]);//基础雷盘的计数函数
void chooseboard_2(char board_1[X][Y], char board_2[X][Y], int choosex, int choosey);//表面雷盘格的选择与零的扩散函数
void printnum(char board_2[X][Y], int bx, int by);//给表面雷盘每一格的内容上色
void alldisplay(char board_1[X][Y], char board_2[X][Y]);//玩家输的时候所有地雷显现的函数
int testboard_2(char board_1[X][Y], char board_2[X][Y], int choosex, int choosey);//输赢或未结束的判断函数

3.game.c

#include"game.h"

void initboard(char board[X][Y])
{
	for (int ax = 0; ax < X; ax++)
	{
		for (int ay = 0; ay < Y; ay++)
		{
			board[ax][ay] = ' ';
		}
	}
}

void printnum(char board_2[X][Y], int bx, int by)//这一个函数其实可以简化很多,但作者直接暴力复制粘贴了
{
	switch (board_2[bx][by])
	{
	case '0':
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 14 | FOREGROUND_INTENSITY | 8 | BACKGROUND_INTENSITY);//白色
		printf("0");
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7 | FOREGROUND_INTENSITY | 8 | BACKGROUND_INTENSITY);
		break;
	case '1':
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 15 | FOREGROUND_INTENSITY | 8 | BACKGROUND_INTENSITY);//亮白色
		printf("1");
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7 | FOREGROUND_INTENSITY | 8 | BACKGROUND_INTENSITY);
		break;
	case '2':
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 10 | FOREGROUND_INTENSITY | 8 | BACKGROUND_INTENSITY);//淡绿色
		printf("2");
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7 | FOREGROUND_INTENSITY | 8 | BACKGROUND_INTENSITY);
		break;
	case '3':
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 9 | FOREGROUND_INTENSITY | 8 | BACKGROUND_INTENSITY);//淡蓝色
		printf("3");
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7 | FOREGROUND_INTENSITY | 8 | BACKGROUND_INTENSITY);
		break;
	case '4':
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 12 | FOREGROUND_INTENSITY | 8 | BACKGROUND_INTENSITY);//淡红色
		printf("4");
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7 | FOREGROUND_INTENSITY | 8 | BACKGROUND_INTENSITY);
		break;
	case '5':
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 13 | FOREGROUND_INTENSITY | 8 | BACKGROUND_INTENSITY);//淡紫色
		printf("5");
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7 | FOREGROUND_INTENSITY | 8 | BACKGROUND_INTENSITY);
		break;
	case '6':
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 3 | FOREGROUND_INTENSITY | 8 | BACKGROUND_INTENSITY);//湖蓝色
		printf("6");
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7 | FOREGROUND_INTENSITY | 8 | BACKGROUND_INTENSITY);
		break;
	case '7':
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 1 | FOREGROUND_INTENSITY | 8 | BACKGROUND_INTENSITY);//蓝色
		printf("7");
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7 | FOREGROUND_INTENSITY | 8 | BACKGROUND_INTENSITY);
		break;
	case '8':
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 5 | FOREGROUND_INTENSITY | 8 | BACKGROUND_INTENSITY);//紫色
		printf("8");
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7 | FOREGROUND_INTENSITY | 8 | BACKGROUND_INTENSITY);
		break;
	case '*':
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 4 | FOREGROUND_INTENSITY | 8 | BACKGROUND_INTENSITY);//红色
		printf("*");
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7 | FOREGROUND_INTENSITY | 8 | BACKGROUND_INTENSITY);
		break;
	case '?':
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 4 | FOREGROUND_INTENSITY | 8 | BACKGROUND_INTENSITY);//红色
		printf("?");
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7 | FOREGROUND_INTENSITY | 8 | BACKGROUND_INTENSITY);
		break;
	case ' ':
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7 | FOREGROUND_INTENSITY | 8 | BACKGROUND_INTENSITY);
		printf(" ");
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7 | FOREGROUND_INTENSITY | 8 | BACKGROUND_INTENSITY);
		break;
	}
}

void printboard_2(char board_2[X][Y])
{
	int bx, by, i = 0;
	for (bx = 0; bx < x - 1; bx++)
	{
		for (by = 0; by < y - 1; by++)
		{
			printf(" ");
			printnum(board_2, bx, by);//???
			printf(" |");
		}
		printf(" ");
		printnum(board_2, bx, by);//???
		printf("  %d", bx);
		if (i == 0)
		{
			printf("    剩余未标记地雷数:%d", hudnum);//显示未被标记的雷数
			i++;
		}
		printf(" \n");
		for (by = 0; by < y - 1; by++)
		{
			printf("---|");
		}
		printf("---\n");
	}
	for (by = 0; by < y - 1; by++)
	{
		printf(" ");
		printnum(board_2, bx, by);//???
		printf(" |");
	}
	printf(" ");
	printnum(board_2, bx, by);//???
	printf("  %d", bx);
	printf(" \n\n");
	for (by = 0; by < y; by++)
	{
		if (by < 10)
		{
			printf(" %d  ", by);
		}
		else
		{
			printf(" %d ", by);
		}
	}
	printf("\n");
}

void resetboard_1(char board_1[X][Y], int choosex, int choosey)
{
	int cx, cy, bombnum = num, boardnum = x * y - 1, tmp;
	//cx,cy,剩余的未放置的地雷数,剩余的未访问的点数
	for (cx = 0; cx < x; cx++)
	{
		for (cy = 0; cy < y; cy++)
		{
			if (cx != choosex || cy != choosey)
			{
				tmp = rand() % boardnum;//生成0~boardnum-1的随机数tmp
				if (tmp < bombnum)//如果tmp在0~bombnum-1内,那么就在该点布雷
				{
					board_1[cx][cy] = '*';//在board_1[cx][cy]处放置地雷
					bombnum--;//放置一个地雷,bumbnum-1
				}
				boardnum--;//访问一个点,boardnum-1
			}
		}
	}
}

void scoreboard_1(char board_1[X][Y])//用于计算每一个点周围有多少地雷
{
	int dx, dy, score;
	for (dx = 0; dx < x; dx++)
	{
		for (dy = 0; dy < y; dy++)
		{
			if (board_1[dx][dy] != '*')
			{
				score = 0;
				//向上判断 1
				if (dx > 0)
				{
					if (board_1[dx - 1][dy] == '*')
					{
						score++;
					}
				}
				//向右上判断 2
				if (dx > 0 && dy < y - 1)
				{
					if (board_1[dx - 1][dy + 1] == '*')
					{
						score++;
					}
				}
				//向右判断 3
				if (dy < y - 1)
				{
					if (board_1[dx][dy + 1] == '*')
					{
						score++;
					}
				}
				//向右下判断 4
				if (dx < x - 1 && dy < y - 1)
				{
					if (board_1[dx + 1][dy + 1] == '*')
					{
						score++;
					}
				}
				//向下判断 5
				if (dx < x - 1)
				{
					if (board_1[dx + 1][dy] == '*')
					{
						score++;
					}
				}
				//向左下判断 6
				if (dx < x - 1 && dy>0)
				{
					if (board_1[dx + 1][dy - 1] == '*')
					{
						score++;
					}
				}
				//向左判断 7
				if (dy > 0)
				{
					if (board_1[dx][dy - 1] == '*')
					{
						score++;
					}
				}
				//向左上判断 8
				if (dx > 0 && dy > 0)
				{
					if (board_1[dx - 1][dy - 1] == '*')
					{
						score++;
					}
				}
				board_1[dx][dy] = score + 48;//加48,请查询asc码表
			}
		}
	}
	//printboard_2(board_1);//测试用,请忽视
	//Sleep(20000000);
}

void chooseboard_2(char board_1[X][Y], char board_2[X][Y], int choosex, int choosey)//选择排雷该点
{
	if (board_2[choosex][choosey] == ' ' || board_2[choosex][choosey] == '?')//若board_2该点未被占用,被标记的点也不算占用,若扩散至标记点,且标记点不是地雷,则标记会被数字覆盖
	{
		if (board_1[choosex][choosey] != 48)//board_1该点不等于'0',不扩散
		{
			board_2[choosex][choosey] = board_1[choosex][choosey];
		}
		else if (board_1[choosex][choosey] == 48)//若该点等于'0',往四个方向扩散			
		{
			board_2[choosex][choosey] = board_1[choosex][choosey];
			if (choosex < x - 1)//往下
			{
				chooseboard_2(board_1, board_2, choosex + 1, choosey);
			}
			if (choosex > 0)//往上
			{
				chooseboard_2(board_1, board_2, choosex - 1, choosey);
			}
			if (choosey < y - 1)//往右
			{
				chooseboard_2(board_1, board_2, choosex, choosey + 1);
			}
			if (choosey > 0)//往左
			{
				chooseboard_2(board_1, board_2, choosex, choosey - 1);
			}
			//往四个方向扩散	
		}
	}
}

int testboard_2(char board_1[X][Y], char board_2[X][Y], int choosex, int choosey)
{
	int ex, ey, score = 0;
	for (ex = 0; ex < x; ex++)
	{
		for (ey = 0; ey < y; ey++)
		{
			if (board_2[ex][ey] == '*')//踩到地雷啦
			{
				return 0;
			}
			if (board_1[ex][ey] == board_2[ex][ey])//计算board_1和board_2的重合度
			{
				score++;
			}
		}
	}
	if (score == x * y - num)//重合度=x*y-num,即所有点位已被探明,胜利
	{
		return 1;
	}
	else
	{
		return 2;//重合度<x*y-num,未胜利
	}
}

void alldisplay(char board_1[X][Y], char board_2[X][Y])//踩中地雷时所有地雷显现
{
	int fx, fy;
	for (fx = 0; fx < x; fx++)
	{
		for (fy = 0; fy < y; fy++)
		{
			if (board_1[fx][fy] == '*')
			{
				board_2[fx][fy] = '*';
			}
		}
	}
}

4.main.c

#include"game.h"
//以下是主界面、设置界面、游戏界面等游戏{基础框架}的实现
void menu()//菜单 $$
{
	printf("输入以下数字以选择下一步:\n'0'结束游戏\n'1'开始游戏\n'2'游戏信息与设置\n请输入:");
}

int game()
{
	int a = 1, test;//a用于控制第一次选择排雷点时重置雷盘,即第一次排雷不可能遇到地雷
	int choosex, choosey, choose;
	hudnum = num;
	initboard(board_1);//$$
	initboard(board_2);//初始化底层雷区与表面雷区	$$
	printboard_2(board_2);//打印表面雷区 $$
	while (1)
	{
		while (1)
		{
			printf("输入你想要选择的点的横坐标:");
			scanf("%d", &choosey);
			printf("输入你想要选择的点的纵坐标:");
			scanf("%d", &choosex);
			printf("输入1选择排雷该点,输入2选择标记或取消标记该点:");
			scanf("%d", &choose);//选择要操作的点,并选择排雷/标记/取消标记
			if (-1 < choosex && choosex < x && -1 < choosey && choosey < y && choose == 1)//选择了雷盘内合法的点并排雷
			{
				if (a == 1)//在'第一次'选择排雷后重置雷盘并计算每个点周围的雷数 (后续将不起作用)
				{
					resetboard_1(board_1, choosex, choosey);//重新布雷底部雷区 $$
					scoreboard_1(board_1);//底部雷区计数 $$
					a++;
				}
				if (board_2[choosex][choosey] != '?')
				{
					chooseboard_2(board_1, board_2, choosex, choosey);//选择排雷点
				}
				system("cls");
				printboard_2(board_2);//$$
				break;//只有选择该点排雷,才调用break,进入检测环节
			}
			else if (-1 < choosex && choosex < x && -1 < choosey && choosey < y && choose == 2)//选择雷盘内合法的点并标记/取消标记
			{
				if (board_2[choosex][choosey] == ' ')
				{
					board_2[choosex][choosey] = '?';//标记该点
					hudnum--;
				}
				else if (board_2[choosex][choosey] == '?')
				{
					board_2[choosex][choosey] = ' ';//取消标记该点
					hudnum++;
				}
				system("cls");
				printboard_2(board_2);
			}
			else//其余一切操作皆为非法操作
			{
				printf("请输入正确的数字");
				Sleep(2000);
				system("cls");
				printboard_2(board_2);
			}
		}
		test = testboard_2(board_1, board_2, choosex, choosey);
		//test=0-->踩到地雷;test=1-->全部点位已被探明且未踩到地雷,胜利;test=2-->未踩到地雷,也没有探明所有点位,未结束
		if (test == 0)
		{
			alldisplay(board_1, board_2);
			system("cls");
			printboard_2(board_2);
			return 0;
		}
		else if (test == 1)
		{
			return 1;
		}
	}
}//return-->choose-->result:0-->输,1-->赢

void choose_menu()//菜单选择
{
	int menuchoose = 0, result = 0;//menuchoose菜单选择结果,result游戏输赢结果
	z = 1, num = 9, x = 9, y = 9;
	int set = 0, boa = 1;
	do
	{
		system("cls");
		menu();
		scanf("%d", &menuchoose);
		switch (menuchoose)
		{
		case 0://结束游戏
			system("cls");
			printf("结束游戏");
			Sleep(2000);
			break;
		case 1://开始游戏
			system("cls");
			printf("开始游戏");
			Sleep(2000);
			system("cls");
			result = game();//game()_return:0-->输,1-->赢
			if (result == 0)
			{
				SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 15 | 8 | 128 | 64);
				printf("you lost!!\n");
				SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7 | FOREGROUND_INTENSITY | 8 | BACKGROUND_INTENSITY);
				printf("按下回车键以继续");
				getchar();
				getchar();
			}
			else if (result == 1)
			{
				SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 15 | 8 | 128 | 64);
				printf("you won!!\n");
				SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7 | FOREGROUND_INTENSITY | 8 | BACKGROUND_INTENSITY);
				printf("按下回车键以继续");
				getchar();
				getchar();
			}
			break;
		case 2://信息与设置
			system("cls");
			printf("游戏信息与设置");
			Sleep(2000);
			system("cls");
			printf("游戏信息:\n\n游戏名:扫雷\n\n作者:li_zi_jin\n\n提示:\n1.游戏规则与Windows扫雷相同\n2.通过输入坐标选择相应的点,坐标原点为左上角\n3.可以调整雷盘大小,默认为小\n6.选择了你想要操作的点后,选择1排雷该点相当于原版左键,选择2标记/取消标记该点相当于原版右键\n5.每输入一次数字,按下Enter以进行下一步,不要输入数字以外的任何字符,会出bug\n\n");
			printf("信息:\n雷盘大小:");
			switch (z)
			{
			case 1:
				printf("小(9*9)\n");
				break;
			case 2:
				printf("中(16*16)\n");
				break;
			case 3:
				printf("大(16*30)\n");
				break;
			default:
				printf("出错\n");
				break;
			}
			printf("地雷数量:");
			printf("%d\n", num);
			printf("\n输入以下数字以选择下一步:\n'1'调整雷盘大小\n'其他数字'退回初始界面\n请输入:");
			scanf("%d", &set);
			if (set == 1)
			{
				printf("\n输入以下数字以选择相应雷盘大小:\n'1'小\n'2'中\n'3'大\n请输入:");
				scanf("%d", &boa);
				if (0 < boa && boa < 4)
				{
					z = boa;
					switch (z)
					{
					case 1:
						num = 9;
						//num = 1;//测试用,请忽略
						x = 9;
						y = 9;
						break;
					case 2:
						num = 40;
						x = 16;
						y = 16;
						break;
					case 3:
						num = 99;
						x = 16;
						y = 30;
						break;
					}
					printf("设置成功");
				}
				else
				{
					printf("请输入正确的数字");
				}
			}
			else
			{
				printf("退回初始界面");
			}
			Sleep(2000);
			break;
		default://非法输入
			system("cls");
			printf("请输入正确的数字\n");
			Sleep(2000);
			break;
		}
	} while (menuchoose != 0);
}

int main()
{
	srand((unsigned int)time(NULL));
	system("color 87");
	choose_menu();
	return 0;
}

作者:li_zi_jin
日期:2023_10_15
(未经同意禁止转载)文章来源地址https://www.toymoban.com/news/detail-739702.html

到了这里,关于C语言怎样写扫雷的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 初阶c语言:趣味扫雷游戏

    目录 前言  制作菜单 构建游戏选择框架 实现游戏功能 模块化编程:查看前节三子棋的内容 初始化雷区 ​编辑 优化棋盘 随机埋入地雷 点击后的决策  实现此功能代码 game();的安排   《扫雷》是一款大众类的益智小游戏,于1992年发行。游戏目标是在最短的时间内根据点

    2024年02月11日
    浏览(38)
  • 扫雷游戏的实现(C语言)

    对于扫雷游戏,大家应该都很熟悉吧,下面让我们来看看它是如何实现的。 目录 一、游戏规则及设计思想 二、各功能的代码实现 1.创建菜单 2、主函数的实现  3、创建棋盘并初始化 4、打印棋盘  5、布置雷的位置 (埋雷) 6、排查雷   三、代码汇总 1、game.h文件 2、game.c文

    2024年02月03日
    浏览(36)
  • C语言:扫雷小游戏

    文接上一篇博文C语言:三子棋小游戏。本篇博文是使用C语言来实现扫雷小游戏的。这里不对扫雷的规则进行赘述。玩家通过键盘输入坐标来探雷。博主在实现扫雷之前从未看过扫雷实现的相关视频,所以这里实现的扫雷完全是博主的原生思路,具有逻辑性。下面详细介绍一

    2024年02月09日
    浏览(56)
  • C语言小游戏——扫雷

            结合前边我们所学的C语言知识,本期我们将使用C语言实现一个简单的小游戏——扫雷 目录 前言 总体框架设计 多文件分装程序 各功能模块化实现 初始化棋盘  棋盘打印 埋雷  判赢与排雷 游戏逻辑安排 总结         和三子棋相同,游戏开始时不需要任何判

    2024年02月06日
    浏览(43)
  • C语言扫雷小游戏

    扫雷的玩法:在一个9×9(初级)、16×16(中级)、16×30(高级)或自定义大小的方块矩阵中随机布置一定量的地雷(初级为10个,中级为40个,高级为99个),再由玩家逐个翻开方块,翻开的地方将显示周围八个雷的个数。以找出所有地雷为最终游戏目标。如果玩家翻开的方块

    2024年02月05日
    浏览(51)
  • 扫雷小游戏【C语言】

    目录 前言 一、基本实现逻辑 二、实现步骤 1. 我们希望在进入游戏时有一个菜单让我们选择 2. 我们希望可以重复的玩(一把玩完了还可以接着玩) 3. 采用多文件形式编程  4.要扫雷先得有棋盘(创建棋盘R*N) 5.初始化棋盘  6.打印棋盘 7.设置雷 8.排查雷 三、全部源码: 上期

    2024年02月11日
    浏览(55)
  • 【C语言】扫雷游戏完整代码实现

    目录 1.game.h 2.game.c 3.progress.c 4.运行结果

    2024年02月21日
    浏览(43)
  • C语言之扫雷游戏实现篇

    目录 主函数test.c 菜单函数 选择循环 扫雷游戏实现分析 整体思路  问题1 问题2  问题3 问题4  游戏函数(函数调用)  创建游戏盘数组mine 创建游戏盘数组show 初始化游戏盘数组InitBoard 展示游戏盘DisplayBoard 游戏盘置雷SetMine 游戏盘排雷FindMine test.c总代码 头文件函数声明game

    2024年02月11日
    浏览(37)
  • C语言实现简单的扫雷游戏

    目录 1 - test.c 2 - game.c 3 - game.h 代码里的注释感觉已经很清楚啦,就不多讲解啦 感谢各位大佬的支持!!!

    2024年01月22日
    浏览(46)
  • 探秘C语言扫雷游戏实现技巧

    本篇博客会讲解,如何使用C语言实现扫雷小游戏。 使用2个二维数组mine和show,分别来存储雷的位置信息和排查出来的雷的信息,前者隐藏,后者展示给玩家。假设盘面大小是9×9,这2个二维数组都要开大一圈,也就是大小是11×11,这是为了更加方便的数边角上雷的个数,防止

    2024年02月10日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包