C语言版扫雷游戏

原文地址:https://zouchanglin.github.io/2018/05/03/2018050302/

前言

之前在CSDN写了一个三子棋的小游戏,主要是考察数组的运用功底,接下来说说这个C语言版的扫雷小游戏,基于VisualStudio2013环境,在Github上的地址为:https://github.com/zouchanglin/FindMine !

  • 首先我们需要两个数组,一个是开发者数组,一个是玩家数组。由于我们需要判断每一个数组元素周围的8个元素的状态,所以开发者数组肯定要比玩家看到的数组要大,至少大两行且两列
  • 开发者数组存储那些是雷,哪些不是雷只是存储状态,而玩家数组存储那些已经被排过的坐标和周围雷的数量
  • 这个小Demo分为3个文件,test.c文件是整个程序的主体框架,它包括了玩家菜单选择,排雷的开始和结束控制都在test.c中,game.c和与之对应的game.h中全是扫雷的具体逻辑实现,其中注释也比较详细

注意事项

  • 把握好数组的边界以及站在玩家的角度确定数组的下标,避免越界访问
  • 首次排雷不能被炸死,所以第一次排雷的时候要判断坐标是否正好落在雷上,如果刚好落在雷上则重新分布雷
  • 游戏胜利的条件的判断,这个判断方式是多样的,我选择的是玩家数组中只有当 * 的数量等于雷的数量的时候就算玩家胜利

源码

game.h

#ifndef _GAME_H__
#define _GAME_H__

#define ROW 8
#define COL 8
#define ROWS ROW+2
#define COLS COL+2

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

//初始化
void InitBoard(char board[ROWS][COLS], int rows, int clos,char set);

//打印数组
void PrintBoard(char board[ROWS][COLS], int row, int col);

//设置雷的坐标
void SetMine(char board[ROWS][COLS], int row, int col, int count);

//排雷
int FindMine(char mine[ROWS][COLS], char show[ROWS][COLS],int x,int y);

//返回周围雷数目
int GetMineCount(char mine[ROWS][COLS], int x, int y);

//展开的方法
void Spread(char show[ROWS][COLS], char mine[ROWS][COLS], int x, int y);

//判断是否排完
int iswin(char show[ROWS][COLS], int row, int col,int mine_count);

#endif

game.c

#include "game.h"

//初始化通过传的参数分贝初始化两个数组
void InitBoard(char board[ROWS][COLS], int rows, int clos,char set){
	int i = 0;
	int j = 0;
	for (i = 0; i < rows; i++){
		for (j = 0; j < clos; j++){
			board[i][j] = set;
		}
	}
}
//设置雷(开发者数组)
void SetMine(char board[ROWS][COLS], int row, int col, int count){
	int i = 0;
	for (i = 0; i < count; i++){
		//设置count次雷
		int x = rand() %(ROW);
		int y = rand() % (COL);
		while (board[x+1][y+1] == '0'){
			board[x+1][y+1] = '1';//设置1的地方就是雷
		}
	}
}

//打印show(玩家)数组
void PrintBoard(char board[ROWS][COLS], int row, int col){
	int i = 0;
	int j = 0;
	for (i = 0; i < ROWS-1; i++){
		for (j = 0; j < COLS-1; j++){
			if (i == 0){
				printf("%d ", j);
			}else if(j == 0){
				printf("%d ",i);
			}
			else{
				printf("%c ", board[i][j]);
			}
		}
		printf("\n");
	}
}

//排雷函数
int FindMine(char mine[ROWS][COLS], char show[ROWS][COLS],int x,int y){
	if (mine[x][y] == '1'){
		return -1;//return-1表示排雷失败
	}
	int mine_count = GetMineCount(mine, x, y);
	show[x][y] = mine_count + '0';
	return mine_count;
}


//返回坐标周围雷的数量
int GetMineCount(char mine[ROWS][COLS], int x, int y){

	return (mine[x - 1][y - 1] + mine[x - 1][y] + mine[x - 1][y + 1]
		+ mine[x][y - 1] + mine[x][y + 1]
		+ mine[x + 1][y - 1] + mine[x + 1][y] + mine[x + 1][y + 1] - 8 * '0');
}

//判断是否排完,排完返回1
int iswin(char show[ROWS][COLS],int row,int col,int mine_count){
	int i = 0;
	int j = 0;
	int count = 0;
	//逐个扫描统计*个数
	for (i = 0; i < row; i++){
		for (j = 0; j < col; j++){
			if (show[i][j] == '*'){
				count++;
			}
		}
	}
	//如果剩下的*和雷的数量相等,那就说明排雷成功
	if (mine_count == count){
		return 1;
	}
	return 0;
}

//坐标展开的方法(但是只是展开周围8个坐标)
void Spread(char show[ROWS][COLS], char mine[ROWS][COLS], int x, int y){
	if (mine[x - 1][y - 1] == '0'){
		show[x - 1][y - 1] = GetMineCount(mine,x - 1, y - 1) + '0';//显示该坐标周围雷数
	}
	if (mine[x - 1][y] == '0'){
		show[x - 1][y] = GetMineCount(mine,x - 1, y) + '0';
	}
	if (mine[x - 1][y + 1] == '0')
	{
		show[x - 1][y + 1] = GetMineCount(mine,x - 1, y + 1) + '0';
	}
	if (mine[x][y - 1] == '0')
	{
		show[x][y - 1] = GetMineCount(mine,x, y - 1) + '0';
	}
	if (mine[x][y + 1] == '0')
	{
		show[x][y + 1] = GetMineCount(mine,x, y + 1) + '0';
	}
	if (mine[x + 1][y - 1] == '0')
	{
		show[x + 1][y - 1] = GetMineCount(mine, x + 1, y - 1) + '0';
	}
	if (mine[x + 1][y] == '0')
	{
		show[x + 1][y] = GetMineCount(mine, x + 1, y) + '0';
	}
	if (mine[x + 1][y + 1] == '0')
	{
		show[x + 1][y + 1] = GetMineCount(mine, x + 1, y + 1) + '0';
	}

}

test.c

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include "game.h"

#define TRUE 1
#define FALSE 0

void game(){
	//定义二维数组
	char show[ROWS][COLS] = { 0 };
	char mine[ROWS][COLS] = { 0 };

	//初始化显示界面数组
	InitBoard(show, ROWS, COLS,'*');
	InitBoard(mine, ROWS, COLS, '0');

	//布雷
	SetMine(mine,ROWS,COLS,3);

	//打印数组
	PrintBoard(show, ROWS, COLS);
	printf("------------------------------\n");
	PrintBoard(mine, ROWS, COLS);

	int isFirstInput = TRUE;
	while (1){
		if (iswin(show,ROWS,COLS,3)){
			printf("恭喜你,排雷完毕!\n");
			break;
		}
		int x = 0;
		int y = 0;
		printf("请输入要排除的坐标>\n");
	TRY_AGRGIN:
		fflush(stdin);
		scanf("%d%d", &x, &y);
		if (isFirstInput){
			if (mine[x][y] == '1'){
				//重新布雷
				InitBoard(mine, ROWS, COLS, '0');
				SetMine(mine, ROWS, COLS, 3);
			}
			isFirstInput = FALSE;
		}

		//排查雷
		if ((x >= 1 && x <= ROW) && (y >= 1 && y <= COL)){
			int ret = FindMine(mine, show, x , y);
			if (ret == -1){
				printf("排雷失败!!!\n");
				break;
			}
			//排雷成功则展开
			Spread(show, mine, x, y);

			PrintBoard(show, ROWS, COLS);
      //这里是开发者看的开发者数组
			printf("------------------------------\n");
			PrintBoard(mine, ROWS, COLS);

		}
		else{
			printf("输入有误,请重新输入>\n");
			goto TRY_AGRGIN;
		}
	}
}
void menu(){
	printf("--------------扫雷------------\n");
	printf("-------1、play    0、exit-----\n");
	printf("------------------------------\n");
}
int main(void){
	//设置随机种子
	srand((unsigned)time(NULL));

	while (1){
		int your_chosr = 0;
		menu();
		printf("请选择>");
		fflush(stdin); //在输入之前先刷空缓冲区
		scanf("%c", &your_chosr);
		switch (your_chosr){
			case '1':
				game();
				break;
			case '0':
				return 0;
			default:
				printf("输入有误,请重新输入>\n");
				break;
		}
	}
	system("pause");
	return 0;
}

猜你喜欢

转载自blog.csdn.net/m0_38032942/article/details/81109352