C语言实现扫雷游戏代码

扫雷游戏

设计思路:

1.设计两个数组,设计者数组和玩家数组。
设计者数组比玩家数组大两行两列。
用来装布置的地雷数据,但只用1-(row-2)来存储,0和(row-1)什么也不放,只是为了方便扫雷时对周围8个数据的便利

2.设置生成地雷函数,采用生成随机数的方式。

3.设计两个显示函数:一个用来显示玩家下棋过程中的结果,另一个在踩到地雷后用来显示布置的所有地雷

4.难度等级:两个。简单和困难。
简单:设置(2倍数组行)个地雷;
困难:设置(5倍数组行)个地雷。

(本来还可以设置行数的多少来提升难度,但因为我的行列数用的宏定义,暂时没找到一个很好的方法通过命令行改变数组行列数)

5.设计玩家函数。玩家在屏幕上输出坐标,开始排雷。

6.设计判断是否踩雷函数。

注意:bug:用生成随机数布置地雷,可能因为生成的随机数相同,即地雷重复布置,而导致显示出的地雷数量比实际统计的地雷数量要少。

代码展示:
头文件:
game.h

#define ROW 11        //设计者数组行与列
#define COL 11
#define ROW_p (ROW - 2)  //玩家数组行与列
#define COL_p (COL - 2)

#define easy_Mine 2*ROW_p   //简单:地雷数量=ROW_p 通过mine可调整生成地雷数量
#define hard_Mine 5*ROW_p  //困难:地雷数量=5*ROW_p

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

void menu();
void game(int input);
void test();

//初始化棋盘
void IniGame(char board[ROW][COL],char board_p[ROW_p][COL_p],int row,int col);  
//生成地雷
void MineGenerate(char board[ROW][COL],int row,int col,int mine_Num);
 //玩家
void Player(char board[ROW][COL],char board_p[ROW_p][COL_p],int mine_Num); 
//显示下棋后的结果(x y 设为空时显示空棋盘,即游戏初始界面)
void DisPlayRst(char board_p[ROW_p][COL_p],int row_p,int col_p,int x,int y);
//显示所有炸弹(游戏结束后显示)
void DisPlayerAll(char board[ROW][COL],int row,int col);  
//判断是否踩雷
void JudgeMine(char board[ROW][COL],char board_p[ROW_p][COL_p],int x,int y,int mine_Num);	


源文件1:用来定义各个函数
game.c

#include "game.h"


//初始化
void IniGame(char board[ROW][COL],char board_p[ROW_p][COL_p],int row,int col)
{
	int i = 0,j = 0;
	int row_p = row - 2,col_p = col - 2;
	//程序设计者数组初始化   设计者数组比玩家数组多两行两列,
	//方便结果的输出,防止地址访问溢出,同时简化算法
	for(i = 0;i < row;i++)
	{
		for(j = 0;j < col;j++)
		{
			board[i][j] = ' ';  
		}
	}
	//玩家数组初始化
	for(i = 0;i < row_p;i++)
	{
		for(j = 0;j < col_p;j++)
		{
			board_p[i][j] = '*';
			//printf("玩家数组%d:%c\n",(i+1)*(j+1),board_p[i][j]);
		}
	}
}
//生成地雷
void MineGenerate(char board[ROW][COL],int row,int col,int mine_Num)
{
	int x = 0,y = 0;
	int i = 0,j = 0;
	int count = 0;//地雷数量
	srand((unsigned int)time(NULL));

	do
	{
		x = rand()%(row-2) + 1;//row - 2 = 8,rand()%8范围是0-7,再加一范围为1—8
		y = rand()%(col-2) + 1;
		//printf("x,y值为:%d%d\n",x,y);  //生成地雷的坐标,测试时使用,
		//但是生成的地雷数可能有重复,不知道该怎么改
		for(i = 1;i < (row-1);i++)  //1-8
		{
			for(j = 1;j < (col-1);j++)  //1-8
			{
				
				if(x == i && j == y)
				{
					board[i][j] = '+'; 
					//棋盘的(1,1)对应的是设计者数组的(1,1),而对应玩家数组的(0,0)
					count ++;
				}
			}
		}	
	}while(count < mine_Num);//
	printf("生成%d颗地雷\n",mine_Num);  //这里有bug,如果生成地雷有重复的,这个地雷数就不准确了
	//比如在(1,1)处生成三次雷,总共生成十颗雷,但实际上只能显示出8颗,因为有重复
}
//显示玩家下棋后的结果
void DisPlayRst(char board_p[ROW_p][COL_p],int row_p,int col_p,int x,int y)
{
	int i = 0,j = 0;
	//打印列号
	printf("   ");//先空出一格来
	for(i = 1;i < col_p + 1;i++)
	{
		printf(" %d  ",i);

	}
	printf("\n");
	for(i = 1;i < row_p + 1 ;i++)
	{
		//打印行号
		printf(" %d ",i);
		//输出第一行数据
		for(j = 1;j < col_p + 1;j++)
		{
			if( x == i && y == j)  //被改变的元素输出
			{
				printf(" %c ",board_p[x - 1][y -1 ]); //输出时要按玩家数组输出,所以-1	
				if(j < col_p)
				{
					printf("|");
				}
			}
			else   //未被改变的元素输出
			{
				printf(" %c ",board_p[i - 1][j - 1]);//note::ij循环时从1-8,但数组时0-7
				if(j < col_p)
				{
					printf("|");
				}
			}
			
	
								
		}
		printf("\n");
		//输出第二行分隔符
		printf("   ");//行号所占一个,所以先吧行号位置空出来
		for(j = 1;j < col_p + 1;j++)
		{
			printf("---");
			if(j < col_p)
			{
				printf("|");
			}
			
		}
		printf("\n");

	}
}
//显示棋盘所有炸弹
void DisPlayerAll(char board[ROW][COL],int row,int col)
{
	int i = 0,j = 0;
	//打印列号
	printf("   ");//先空出一格来
	for(i = 1;i < col - 1;i++)
	{
		printf(" %d  ",i);

	}
	printf("\n");
	for(i = 1;i < row - 1;i++) //1-8
	{
		//打印行号
		printf(" %d ",i);
		//输出第一行数据
		for(j = 1;j < col - 1;j++)  //1-8
		{
			printf(" %c ",board[i][j]);
			if(j < col - 2)
			{
				printf("|");
			}
			
		}
		printf("\n");
		//输出第二行分隔符
		printf("   ");
		for(j = 1;j < col - 1;j++)
		{
			printf("---");
			if(j < col - 2)
			{
				printf("|");
			}
			
		}
		printf("\n");

	}
}
//玩家
void Player(char board[ROW][COL],char board_p[ROW_p][COL_p],int mine_Num)
{
	
	int x = 0,y = 0; 
	while(1)
	{
		printf("请输入要下坐标:>   (输入格式:x 空格 y)\n");
		scanf_s("%d%d",&x,&y);	
		if(x > 0 && x < ROW -1 && y > 0 && y < COL - 1)
		{
			printf("输入坐标成功\n");
		}
		else
		{
			printf("输入坐标非法,请重新输入:\n");
		}
		JudgeMine(board,board_p,x,y,mine_Num);
		if(board[x][y] == '+')  //
		{
			//printf("炸弹引爆,游戏结束\n");
			//DisPlayerAll(board,ROW,COL);
			break;
		}
	}
	
	
}
//判断是否踩雷 或者周围有几颗雷
void JudgeMine(char board[ROW][COL],char board_p[ROW_p][COL_p],int x,int y,int mine_Num)	
{
	int i = 0,j = 0;
	int count = 0;
	//没踩中雷
	if (board[x][y] != '+')
	//设计者数组和玩家输入坐标刚好对应,玩家输入(1,1)就对应board[1][1]
	{
		int num = 0;
		for(i = x - 1;i < x + 2;i++)//判断周围的炸弹数量,并显示 (x-1)--(x+1)
		{
			//printf("炸弹判断开始\n");
			for(j = y-1;j < y + 2;j++)
			{
				
				if(board[i][j] == '+')
				{
					num ++;
					//printf("num:%d\n",num);
					//itoa(num,num_c, 10);
					board_p[x - 1][y - 1] = num + '0'; //玩家输入(1,1)对应玩家数组(0,0)
					//printf("%d",board_p[x - 1][y - 1]);	
				}
			}			
		}
		num = 0;//循环结束后将num置零
		DisPlayRst(board_p,ROW_p,COL_p,x,y);
		
		count++;
		printf("%d",count);
		printf("结果显示成功\n");
		if(num == ROW_p*COL_p - mine_Num)  
		//如果扫雷次数达到总数减去布置雷的数量,剩下的全是雷,游戏胜利
		//但是这里有bug就是如果生成雷有重复的,显示出的雷数就比mine_Num这个数要小,
		//这个判断胜利的功能实现就不太好实现,但还不知道该怎么改
		{
			printf("雷已扫清,游戏胜利!!");

		}
	}
	//踩雷了
	else if(board[x][y] == '+')  //
	{
		printf("炸弹引爆,游戏结束\n");
		DisPlayerAll(board,ROW,COL);
	}
	
}

源文件2:`
test.c

#include "game.h"


void menu()
{
	printf("****************************\n");
	printf("**********扫雷游戏 *********\n");
	printf("**********1 . 简单**********\n");
	printf("**********2 . 困难**********\n");
	printf("**********3 . 退出**********\n");
	printf("****************************\n");

}

void game(int input)
{
	int mine_Num;  //地雷数量
		
	char board[ROW][COL] = {0};           //设计者数组 10 10
	char board_p[ROW_p][COL_p] = {0};     //玩家数组 8 8
	
	if(input == 1)
	{
		mine_Num = easy_Mine;//难度简单
	}
	else if(input == 2)
	{
		mine_Num =  hard_Mine;//难度困难
	}
	
	//char board[ROW][COL] = {0};  
	//!!!note:定义要放在最前面,否则会报错,在数组定义前面加了if片段结果一直报错,找了老半天
	//char board_p[ROW_p][COL_p] = {0};    
	
	//初始化
	IniGame(board,board_p,ROW,COL);
	printf("游戏初始化完成\n");
	//生成地雷
	MineGenerate(board,ROW,COL,mine_Num);
	printf("生成地雷完成\n");
	//显示所有地雷
	//DisPlayerAll(board,ROW,COL);    //玩家玩游戏时,不显示地雷,设计者测试时使用
	//显示游戏棋盘(空)
	DisPlayRst(board_p,ROW_p,COL_p,0,0);
	printf("空棋盘显示完成,玩家请开始游戏\n");
	//玩家玩游戏
	Player(board,board_p,mine_Num);
	
}
void test()
{
	int input = 0;

	do
	{
		menu();
		printf("请输入您的选择:>  (格式:你的选择 回车)\n");
		scanf_s("%d",&input);
		switch(input)
		{
			case 1:
				{
					printf("扫雷游戏\n");
					printf("难度:简单\n");
					game(input);
			
					break;
				}
			case 2:
				{
					printf("扫雷游戏\n");
					printf("难度:困难\n");
					game(input);
			
					break;
				}
			case 3:
				{
					printf("退出游戏");		
					break;
				}
			default:
				{
					printf("输入有误,请重新输入\n");
					break;
				}
		}

		
	
	}while(input%3);
	

}
int main()
{
	test();
	return 0;
	system("pause");

}

运行结果展示:
在这里插入图片描述在这里插入图片描述在这里插入图片描述
[

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

铁中棠ang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值