C语言扫雷实现

基本框架

三个文件

game.h ===头文件,函数声明

game.c===函数实现

test.c===游戏主体逻辑

game.h

#pragma once
#define	ROWS 11
#define COLS 11
#define ROW 9
#define COL 9
#define easy_count 10 //雷的个数
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

void init(char board[ROWS][COLS], int rows, int cols, char set);
void print_board(char board[ROWS][COLS], int row, int col);
void set_bomb(char mine[ROWS][COLS], int row, int col);
void find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row,int col);

game.c

判断输赢姑且先用 计算show数组里面的*的个数来算,如果等于雷数就赢了。

#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void init(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 print_board(char board[ROWS][COLS], int row, int col)
{
	int i = 0;
	int j = 0;
	printf("----------扫雷---------\n");
	for (i = 0; i <= 9; i++)
	{
		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");
	}
	printf("----------扫雷---------\n");
}

void set_bomb(char mine[ROWS][COLS], int row, int col)
{
	
	int count = 0;
	while (1)
	{
		int x = rand() % row + 1;
		int y = rand() % col + 1;
		if (mine[x][y] == '0')
		{
			mine[x][y] = '1';
			count++;
		}
		if (count == easy_count)
		{
			break;
		}
	}
}
int search_around(char mine[ROWS][COLS], int x,int y) //返回的是周围雷的个数   //也可以用循环,转一圈看有多少个1
{
	return ( mine[x - 1][y] + mine[x + 1][y] + mine[x][y - 1] + mine[x][y + 1] +
		mine[x - 1][y - 1] + mine[x + 1][y + 1] + mine[x + 1][y - 1] +
		mine[x - 1][y + 1] - 8 * '0'); //数组保存的是字符,-‘0’是等于‘2’-‘0’(50-48=2),变回了整数2
}

void open_board(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y,int* p)
{
	int n = search_around(mine, x, y);
	if (show[x][y] == '*')  //如果显示数组里还是*,则没被排查过,如果不设置这个条件,递归会递归排查过的坐标,有可能死递归
	{                       //也就是递归条件要求: 1.x,y这个位置没被排查过
		if (mine[x][y] != '1' && n == 0)    //2.x,y位置不能是雷 并且 它周围8个位置也不是雷
		{
			show[x][y] = ' ';
			(*p)++;
													//因为下边涉及x,y的变化,所以设立条件是必要的 
			if (x >= 1 && x <= 9 && y >= 1 && y <= 9)//满足条件进入周围坐标的递归,如果不设置这个条件,限制行列坐标在1~9,
			{										//那么递归会进入11x11-9x9之间的坐标,就会导致不能将展开限制在周围都有雷的情况							
				int i = 0;							//也就是点左边展开,右边也展开,还有可能全都展开了。
				int j = 0;
				for (i = x - 1; i <= x + 1; i++)   //循环下列8个递归函数,加上本身x,y一共9个,本身x,y被排查过不进入递归。
				{
					
					for (j = y - 1; j <= y + 1; j++)
					{
						open_board(mine, show, i, j, p);
					}
				}
				//open_board(mine, show, x - 1, y,p);
				//open_board(mine, show, x + 1, y,p); 和上边一样,就是少了个原本的x,y(也就是输入的中心坐标)
				//open_board(mine, show, x, y - 1,p);
				//open_board(mine, show, x, y + 1,p);

				//open_board(mine, show, x - 1, y - 1,p);
				//open_board(mine, show, x + 1, y + 1,p);
				//open_board(mine, show, x + 1, y - 1,p);
				//open_board(mine, show, x - 1, y + 1,p);
			}
				
		}
		if (n != 0)    //如果x,y这个坐标周围有雷,那么就不进入递归,把周围雷数放到show里就行了。
		{
			show[x][y] = n + '0';    //2+'0'=2+48=50='2'(理解) 我认为它整形提升了,结果仍然加的是0的asci码值
			(*p)++;
			
		}
			
	}
}


void find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int win = 0;
	
	int x = 0;
	int y = 0;
	while (1)    //win< (row * col - easy_count)
	{
		printf("请输入坐标\n");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (show[x][y] != '*')
			{
				printf("该坐标已经被排查过了\n");
				continue;
			}
			if (mine[x][y] == '1')
			{
				printf("这是雷,游戏结束\n");
				print_board(mine, ROW, COL);
				break;
			}
			else 
			{
			open_board(mine, show, x, y,&win);
			print_board(mine, ROW, COL);
			print_board(show, ROW, COL);
			
			
			}
		}
		else
		{
			printf("输入错误,重新输入\n");
		}

		int count = 0;
		for (int j = 1; j <= 9; j++)
		{
			for (int i = 1; i <= 9; i++)
			{
				if (show[j][i] == '*')//用了数show里面的*来判断
					count++;
			}
		}
		if (count == easy_count)
		{
			printf("扫雷成功!\n");
			print_board(mine, ROW, COL);
			break;
		}
	}
	





	//if (win == (row * col - easy_count))  //在雷数少的时候比如说5,就得
	//{                                     //让win>=(row * col - easy_count)
	//	printf("扫雷成功!\n");           //不然点开延展的时候,win的指针++(调试是115次)
	//	print_board(mine, ROW, COL);     //次数会大于81 -5,这里就不输出成功
	//	                                //此时并不能win次数 来判断游戏结束
	//}								//这个判断还需要优化,我用了数show里面的*来判断
										//那么win这个判断输赢基本就没用了

}


test.c

要同时设置两个雷盘,一个初始化全为0方便后续找周围8个雷,另一个初始化全为*,打印出来就是要扫雷的雷盘。

并且排查雷还需要行列都加2,才不会越界

进行递归雷盘展开时,需要注意把坐标x,y限制在1-9,不然会导致递归进入雷盘外,导致不想展开的地方也多展开了。

递归的条件是,第一不是雷并且它周围的8个也不是雷,而且还要没被排查过,不然会死递归。

如果它周围有雷,那么就不进入递归,直接把周围的雷数显示到show就行。

要的结果就是展开后,周围一圈除了边界,就是周围都是数字,就是周边有雷的个数,就结束

#define _CRT_SECURE_NO_WARNINGS 1

#include "game.h"
void menu()
{
	printf("*********** 扫雷   **********\n");
	printf("***********1.玩游戏**********\n");
	printf("**********0.退出游戏**********\n");
}
void game()
{
	//1.需要存放布置好的雷的信息,存放排查出雷的信息,我们需要2个二维数组
	//2.排查坐标的时候,为了防止坐标越界,我们给数组的行列,同时增加2
	char mine[ROWS][COLS] = { 0 };//布置好雷的信息
	char show[ROWS][COLS] = { 0 };//排查出雷的信息
	init(mine, ROWS, COLS,'0');
	init(show, ROWS, COLS,'*');
	
	

	set_bomb(mine, ROW, COL);
	print_board(mine, ROW, COL);
	print_board(show, ROW, COL);
	find_mine(mine, show, ROW, COL);//扫雷判断输赢及周围雷的个数
	

}
int main()
{
	srand((unsigned int)time(NULL));
	int input = 0;
	do
	{
		menu();
		printf("请选择->\n");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("游戏结束\n");
			break;
		default:
			printf("选择错误,重新输入\n");
			break;
		}
	} while (input);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值