C语言-扫雷

思路

  • 玩家输入地图规格和埋雷数
  • 随机生成玩家要求的个数的雷
  • 游戏循环
  • 退出游戏循环,游戏结束

游戏循环

  • 清屏

  • 打印地图

    • 未被翻开
    • 被标记
    • 被翻开就显示周围的地雷数,没有就不显示
  • 如果地雷 都被标记就退出游戏循环

  • 读取玩家输入

  • 如果是打开

    • 打开是雷游戏结束
    • 不是雷就递归展开
  • 如果是标记

    • 没标记过就标记
    • 标记过就取消标记
  • 如果是退出就退出游戏循环

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

#define MaxRow	100
#define MaxCol	100
#define NOTHING 0		//没有雷
#define MINE	1	//有雷
#define InMap(x , y , r ,c)	(x >= 0 && x < r && y >= 0 && y < c)	//判断一个坐标是否在范围内
#define SELECT	"\033[7m" 	//选中的取反色
#define HIDE_CURSOR	"\033[?25l"	//隐藏光标
#define SHOW_CURSOR	"\033[?25h"	//显示光标
#define CANCEL	"\033[0m"	//取消反色
#define INITX 3
#define INITY 3
typedef enum Status
{
	OPENED,
	CLOSED,
	MARKED
} STAT;

typedef struct Element
{
	STAT stat;
	int mine;
	int number;
} ELEM;	//地图元素

ELEM map [MaxRow][MaxCol];

void InitMap(int number , int row , int col)
{
	int i , j , randx , randy;
	for(i = 0; i < row; i++)
		for(j = 0; j < col; j++)
	 	{
			map [i][j].stat = CLOSED;
			map [i][j].mine = NOTHING;
			map [i][j].number = 0; 
		}

	for(i = 0; i < number; i++)
	{
		srand(time(NULL));
		do
		{
			randx = rand() % row;
			randy = rand() % col;
		}while(map [randx][randy].mine == MINE);	//如果有雷,就继续循环,直到无雷
		map [randx][randy].mine = MINE;
	}
}

void DrawMap(int x , int y , int row , int col , int over)
{
	int i , j;
	STAT s;
	printf(HIDE_CURSOR);	//隐藏光标
	for(i = 0; i < row; i++)
	{
		for(j = 0; j < col; j++)
		{
			if(i == x && j == y)
				printf(SELECT);	//如果被选中
			s = map [i][j].stat;
			if(s == CLOSED)
			{	if(over == 0)
					putchar('#');
				else
				{
					if(map [i][j].mine == MINE)
						putchar('!');
					else
						putchar(' ');
				}	//如果游戏结束就将未翻开都显示

			}
			if(s == MARKED)
				putchar('*');
			if(s == OPENED)	//如果不是0就显示数字
			{
				if(map [i][j].number == 0)
					putchar(' ');
				else
					printf("%d" , map [i][j].number);
			}
			printf(CANCEL);
		}
		putchar('\n');
	}
	printf("key wsad to move,key o to open,key m to mark,key q to quit.\n");
}
int AroundMines(int x , int y , int row , int col)	//求一个位置周围的雷数
{
	int offsetx , offsety , around = 0;
	for(offsetx = -1; offsetx <= 1; offsetx++)
		for(offsety = -1 ; offsety <= 1; offsety++)
		{
			if(offsetx == 0 && offsety == 0)
				continue;
			if(InMap(x + offsetx , y + offsety , row , col))
			{
				if(map [x + offsetx][y + offsety].mine == MINE)
					around++;		
			}
		}
	return around;
}

void Expand(int x , int y , int row , int col)	//递归展开
{
	STAT s;
	int around;
	s = map [x][y].stat;
	if(s == MARKED || s == OPENED || map [x][y].mine == MINE)	//如果打开过了或者标记过了或者是雷,就退出本次递归
		return;
	around = AroundMines(x , y , row , col);
	map [x][y].stat = OPENED;
	map [x][y].number = around;
	if(around != 0)
		return;

	if(InMap(x - 1 , y , row , col))
		Expand(x - 1 , y , row , col);	//向上递归
	if(InMap(x + 1 , y , row , col))
		Expand(x + 1 , y , row , col);	//向下递归
	if(InMap(x , y - 1 , row , col))
		Expand(x , y - 1 , row , col);	//向左递归
	if(InMap(x , y + 1 , row , col))
		Expand(x , y + 1 , row , col);	//向右递归
}

int Open(int x , int y , int row , int col)
{
	int over = 0;
	if(map [x][y].stat == CLOSED)
	{
		if(map [x][y].mine == NOTHING)
			Expand(x , y , row , col);
		else
			over = 1;
	}
	return over;
}
void Mark(int x , int y)
{
	if(map [x][y].stat == CLOSED)
		map [x][y].stat = MARKED;
	else
	{
		if(map [x][y].stat == MARKED)	//如果标记两次就取消标记
			map [x][y].stat = CLOSED;
	}
}
int Win(int row, int col)
{
	int win = 1 ,  i ,  j;
	for(i = 0; i < row; i++)
		for(j = 0; j < col; j++)
		{
			if(map [i][j].mine == MINE && map [i][j].stat != MARKED)	//如果有没标记的雷就不结束
				win = 0;
		}	
	return win;
}
int main()
{
	int x , y , over = 0 , quit = 0 , row , col , mines;
	char input;
	x = INITX;
	y = INITY;
	printf("please enter some data:\n");
	printf("row column mines\n");
	scanf("%d%d%d" , &row , &col , &mines);
	InitMap(mines , row , col);
	while(!quit)
	{
		system("clear");
		DrawMap(x , y , row , col ,over);
		if(Win(row , col))
		{
			printf("----GAME WIN----\n");
			break;
		}
		if(over)
		{
			printf("----GAMEOVER----\n");
			break;
		}
		input = getchar();
		switch(input)
		{
			case 'w':
			case 'W':
				if(x > 0)
					x--;
				break;
			case 's':
			case 'S':
				if(x < row - 1)
					x++;
				break;
			case 'a':
			case 'A':
				if(y > 0)
					y--;
				break;
			case 'd':
			case 'D':
				if(y < col -1)
					y++;
				break;
			case 'o':
			case 'O':
				over = Open(x , y , row , col);
				break;
			case 'm':
			case 'M':
				Mark(x , y);
				break;
			case 'q':
			case 'Q':
				quit = 1;
				break;	
		}
	}
	printf(SHOW_CURSOR);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值