扫雷(可展开空白可标记和取消标记)

实用工具:VS2019

一 建立文件

        创建游戏的主函数文件test.c和游戏函数文件game.c文件与头文件game.h文件。 在代码的编写过程中我们将所有要用的库函数包含在一个game.h文件中,这样就可以在.c文件中引用game.h文件。

二 主函数

1.菜单的编写:

void menu()
{
	printf("-------------\n");
	printf("----1.play---\n");
	printf("----0.exit---\n");
	printf("-------------\n");
}

 2.主函数主体选择do...while循环,在其中添加switch语句来作为菜单的内置选项。

除了1和0外我们应该考虑玩家输入其他数字的情况,switch语句很好的解决了这个问题。

创建输入变量,主函数完成编写。这里我们的变量控制了循环的进行。

int main()
{
	int input = 0;
	do
	{
		menu();
		printf("请选择->\n");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("进行游戏\n");
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("选择错误,请重新选择!\n");
		}
	} while (input);
	return 0;
}

三 游戏函数

 既然要扫雷我们就应该有展示信息和存储类坐标信息的两个不同界面。

所以在游戏函数中我们初始化两个数组,在考虑数组的大小时,应该想到如果建立一个9乘9的扫雷棋盘,在扫雷过程中,会展示所选位置周围雷的个数的信息,在数组的边缘位置,为了方便使我们展示雷的多少,在数组的上下左右多加一行,就变成了11乘11的数组。如下

void game()
{
	char mine[ROWS][COLS] = { 0 };//存放布置的雷的信息
	char show[ROWS][COLS] = { 0 };//存放排查出的雷的信息
}

1.初始化数组内容

 在game.c中建立一个用来初始化数组内容的函数,并在game.h定义该函数,方便我们在test.c中引用,此过程在后面都会用到,所以后面不在赘述。在game.h 中我,我们还定义了几个常量,分别为数组的行数和列数,ROWS为11,COLS为11,ROW为9,COL为9,还有雷的个数BOOM。

我们规定在布置雷的数组mine中,1代表雷,0代表无雷。初始化时我们把所有的都置为0。

在展示信息的show数组中,开始时都为 * ,选择扫了位置,会根据周围的雷的个数展示相应的信息,周围无雷就会变为空格,进而打开一片。 

在给函数传递参数时,分别传了,数组,数组行数,数组列数,以及字符。

game.c

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

test.c

	//mine数组在没有布置雷的时候都是字符'0'
	InitBoard(mine, ROWS, COLS, '0');
	//show数组在没排查到雷时都是字符'*'
	InitBoard(show, ROWS, COLS, '*');

2.打印数组内容

 数组初始化后,应该将其打印出来,所以建立打印数组的函数。

 game.c

void DisPlay(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");
}

3.设置雷的函数

 在这里我们想要在数组内随机的放入雷,就用到了时间戳,在主函数中要有

srand((unsigned int)time(NULL));

 game.c

void SetMine(char board[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int count = BOOM;
	while (count)
	{
		x = rand() % 9 + 1;
		y = rand() % 9 + 1;
		if (board[x][y] == '0')
		{
			board[x][y] = '1';
			count--;
		}
	}
}

4.排查雷的函数

 这是本游戏里相对最困难的函数。

首先需要输入要排查的坐标,并对坐标加以限制,符合条件才能向下进行,否则给出反馈让玩家重新输入,然后对符合条件的坐标分别处理,检验其是否重复,是否踩到炸弹,并给出反馈,显示信息。

 game.c

int get_mine_count(char board[ROWS][COLS], int x, int y)
{
	int count = 0;
	int i = 0;
	int j = 0;
	for (i = -1; i <= 1; i++)
	{
		for (j = -1; j <= 1; j++)
		{
			if (board[x + i][y + j] == '1')
			{
				count++;
			}

		}
	}
	return count;
}
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	while (1)
	{
		
		printf("请输入坐标->\n");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= 9 && y >= 1 && y <= 9)
		{
			if (show[x][y] == ' '|| show[x][y] == '1'|| show[x][y] == '2'|| 
				show[x][y] == '3'|| show[x][y] == '4'|| show[x][y] == '5'|| 
				show[x][y] == '6'|| show[x][y] == '7'|| show[x][y] == '8')
			{
				printf("重复输入,请重新输入\n");
				continue;
			}
			if (mine[x][y] == '1')
			{
				printf("对不起,你被炸了,请开始下一把\n");
				DisPlay(mine, ROW, COL);
				break;
			}
			else
			{
				int count = get_mine_count(mine,x,y);
				show[x][y] = count + '0';
			}
		}
		else
		{
			printf("输入非法,请重新输入\n");
		}
	}

}

这样我们排查函数的主体已经完成了,接下来向其中添加更多的功能

1)展开一片空白(用空格)的功能

在满足输入坐标的限制条件后,做出两种不同的展示,如果该坐标周围有雷,就显示雷的个数,如果该坐标周围没有雷,并且该坐标不是空格,那说明该坐标没被排查或没被其他坐标波及变为空格,此时我们就将改坐标改为空格,并对该坐标周围八个坐标进行检查,如果有坐标为 * ,那么重复刚刚的操作。

game.c

void Blank(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
	if (x >= 1 && x <= 9 && y >= 1 && y <= 9)
	{
		int count = get_mine_count(mine, x, y);
		if (count == 0 && show[x][y] != ' ')
		{
			show[x][y] = ' ';

			int i = 0;
			int j = 0;
			for (i = x - 1; i <= x + 1; i++)
			{
				for (j = y - 1; j <= y + 1; j++)
				{
					if (show[i][j] == '*')
					{
						Blank(mine, show, i, j);
					}
				}
			}
		}
		else
		{
			show[x][y] = count + '0';

		}

	}

}

2)标记与取消标记功能

 在做标记功能时,首先让玩家选择是否要标记,对应1和0,如果想要标记就要输入坐标,如果输入坐标满足限制条件,就分情况进行不同的处理,我们将标记设置为“!”。

game.c 

void MarkBOOM(char show[ROWS][COLS])
{
	int a = 0;	
	while (1)
	{
		printf("是否想要标记雷,是请输入1,否请输入0\n");
		scanf("%d", &a);
		if (a == 1)
		{
			int x;
			int y;
			printf("请输入想标记的坐标->\n");
			scanf("%d %d", &x, &y);
			if (x >= 1 && x <= ROW && y >= 1 && y <= COL)
			{
				if (show[x][y] == '!')
				{
					printf("已被标记,请重新选择\n");
					continue;
				}
				else 
				{
					show[x][y] = '!';
					break;
				}
				
			}
			else
			{
				printf("坐标不合法,请重新选择\n");
				continue;
			}
			break;
		}
		else if (a == 0)
		{
			break;
		}
		else
		{
			printf("输入非法,请重新输入\n");
		}		
	}
}

取消标记功能同理

game.c

void CancelMark(char show[ROWS][COLS])
{
	int a = 0;
	while (1)
	{
		printf("是否想要取消标记,是请输入1,否请输入0\n");
		scanf("%d", &a);
		if (a == 1)
		{
			int x;
			int y;
			printf("请输入想取消标记的坐标->\n");
			scanf("%d %d", &x, &y);
			if (x >= 1 && x <= ROW && y >= 1 && y <= COL)
			{
				if (show[x][y] == '!')
				{
					//printf("已被标记,请重新输入\n");
					show[x][y] = '*';
					break;
				}
				else
				{
					printf("该位置没有标记,请重新选择\n");
					continue;
				}

			}
			else
			{
				printf("坐标不合法,请重新选择\n");
				continue;
			}
			break;
		}
		else if (a == 0)
		{
			break;
		}
		else
		{
			printf("输入非法,请重新输入\n");
		}
	}
}

 3)输赢判定

此功能比较简单,直接上代码

int Win(char show[ROWS][COLS], int win)
{
	int i = 0;
	int j = 0;
	for (i = 1; i <= ROW; i++)
	{
		for (j = 1; j <= COL; j++)
		{
			if (show[i][j] == ' ' || show[i][j] == '1' || show[i][j] == '2' ||
				show[i][j] == '3' || show[i][j] == '4' || show[i][j] == '5' ||
				show[i][j] == '6' || show[i][j] == '7' || show[i][j] == '8')
			{
				win++;
			}

		}
	}
	return win;
}
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	while (1)
	{
		
		printf("请输入坐标->\n");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= 9 && y >= 1 && y <= 9)
		{
			if (show[x][y] == ' '|| show[x][y] == '1'|| show[x][y] == '2'|| 
				show[x][y] == '3'|| show[x][y] == '4'|| show[x][y] == '5'|| 
				show[x][y] == '6'|| show[x][y] == '7'|| show[x][y] == '8')
			{
				printf("重复输入,请重新输入\n");
				continue;
			}
			if (mine[x][y] == '1')
			{
				printf("对不起,你被炸了,请开始下一把\n");
				DisPlay(mine, ROW, COL);
				break;
			}
			else
			{
				//int count = get_mine_count(mine,x,y);
				//show[x][y] = count + '0';

				Blank(mine, show, x, y);
				DisPlay(show, ROW, COL);
			}
		}
		else
		{
			printf("输入非法,请重新输入\n");
		}
		MarkBOOM(show);
		DisPlay(show, ROW, COL);
		CancelMark(show);
		DisPlay(show, ROW, COL);
		int win = 0;
		int ret = Win(show, win);
		if (ret == ROW * COL - BOOM)
		{
			printf("你赢了\n");
			break;
		}
	}

}

四 完整代码

 test.c

#define _CRT_SECURE_NO_WARNINGS
#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 };//存放排查出的雷的信息
	//初始化数组内容为指定的内容
	//mine数组在没有布置雷的时候都是字符'0'
	InitBoard(mine, ROWS, COLS, '0');
	//show数组在没排查到雷时都是字符'*'
	InitBoard(show, ROWS, COLS, '*');
	//打印数组
	DisPlay(show, ROW, COL);
	//设置雷
	SetMine(mine, ROW, COL);
	//排查雷
	FindMine(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");
		}
	} while (input);
	return 0;
}

game.c

#define _CRT_SECURE_NO_WARNINGS
#include "game.h"

void InitBoard(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 DisPlay(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 SetMine(char board[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int count = BOOM;
	while (count)
	{
		x = rand() % 9 + 1;
		y = rand() % 9 + 1;
		if (board[x][y] == '0')
		{
			board[x][y] = '1';
			count--;
		}
	}
}


int get_mine_count(char board[ROWS][COLS], int x, int y)
{
	int count = 0;
	int i = 0;
	int j = 0;
	for (i = -1; i <= 1; i++)
	{
		for (j = -1; j <= 1; j++)
		{
			if (board[x + i][y + j] == '1')
			{
				count++;
			}

		}
	}
	return count;
}

void Blank(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
	if (x >= 1 && x <= 9 && y >= 1 && y <= 9)
	{
		int count = get_mine_count(mine, x, y);
		if (count == 0 && show[x][y] != ' ')
		{
			show[x][y] = ' ';

			int i = 0;
			int j = 0;
			for (i = x - 1; i <= x + 1; i++)
			{
				for (j = y - 1; j <= y + 1; j++)
				{
					if (show[i][j] == '*')
					{
						Blank(mine, show, i, j);
					}
				}
			}
		}
		else
		{
			show[x][y] = count + '0';

		}


	}


}

int Win(char show[ROWS][COLS], int win)
{
	int i = 0;
	int j = 0;
	for (i = 1; i <= ROW; i++)
	{
		for (j = 1; j <= COL; j++)
		{
			if (show[i][j] == ' ' || show[i][j] == '1' || show[i][j] == '2' ||
				show[i][j] == '3' || show[i][j] == '4' || show[i][j] == '5' ||
				show[i][j] == '6' || show[i][j] == '7' || show[i][j] == '8')
			{
				win++;
			}

		}
	}
	return win;
}

void MarkBOOM(char show[ROWS][COLS])
{
	int a = 0;	
	while (1)
	{
		printf("是否想要标记雷,是请输入1,否请输入0\n");
		scanf("%d", &a);
		if (a == 1)
		{
			int x;
			int y;
			printf("请输入想标记的坐标->\n");
			scanf("%d %d", &x, &y);
			if (x >= 1 && x <= ROW && y >= 1 && y <= COL)
			{
				if (show[x][y] == '!')
				{
					printf("已被标记,请重新选择\n");
					continue;
				}
				else 
				{
					show[x][y] = '!';
					break;
				}
				
			}
			else
			{
				printf("坐标不合法,请重新选择\n");
				continue;
			}
			break;
		}
		else if (a == 0)
		{
			break;
		}
		else
		{
			printf("输入非法,请重新输入\n");
		}		
	}
}
void CancelMark(char show[ROWS][COLS])
{
	int a = 0;
	while (1)
	{
		printf("是否想要取消标记,是请输入1,否请输入0\n");
		scanf("%d", &a);
		if (a == 1)
		{
			int x;
			int y;
			printf("请输入想取消标记的坐标->\n");
			scanf("%d %d", &x, &y);
			if (x >= 1 && x <= ROW && y >= 1 && y <= COL)
			{
				if (show[x][y] == '!')
				{
					//printf("已被标记,请重新输入\n");
					show[x][y] = '*';
					break;
				}
				else
				{
					printf("该位置没有标记,请重新选择\n");
					continue;
				}

			}
			else
			{
				printf("坐标不合法,请重新选择\n");
				continue;
			}
			break;
		}
		else if (a == 0)
		{
			break;
		}
		else
		{
			printf("输入非法,请重新输入\n");
		}
	}
}
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	while (1)
	{
		
		printf("请输入坐标->\n");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= 9 && y >= 1 && y <= 9)
		{
			if (show[x][y] == ' '|| show[x][y] == '1'|| show[x][y] == '2'|| 
				show[x][y] == '3'|| show[x][y] == '4'|| show[x][y] == '5'|| 
				show[x][y] == '6'|| show[x][y] == '7'|| show[x][y] == '8')
			{
				printf("重复输入,请重新输入\n");
				continue;
			}
			if (mine[x][y] == '1')
			{
				printf("对不起,你被炸了,请开始下一把\n");
				DisPlay(mine, ROW, COL);
				break;
			}
			else
			{
				Blank(mine, show, x, y);
				DisPlay(show, ROW, COL);
			}
		}
		else
		{
			printf("输入非法,请重新输入\n");
		}
		MarkBOOM(show);
		DisPlay(show, ROW, COL);
		CancelMark(show);
		DisPlay(show, ROW, COL);
		int win = 0;
		int ret = Win(show, win);
		if (ret == ROW * COL - BOOM)
		{
			printf("你赢了\n");
			break;
		}
	}

}

game.h

#pragma once

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


#define ROWS 11
#define COLS 11

#define ROW 9
#define COL 9

#define BOOM 10


void InitBoard(char board[ROWS][COLS], int rows, int cols, char set);

void DisPlay(char board[ROWS][COLS], int row, int col);

void SetMine(char board[ROWS][COLS], int row, int col);

void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值