扫雷小游戏(扩展板)-c语言

本文介绍了一个使用C语言实现的扫雷小游戏,包括设置游戏难度、避免首次踩雷失败、自动扩展无雷区域、标记和取消标记等功能。通过二维字符数组存储和展示游戏状态,并利用递归计算雷数。详细代码分别在test.c和game.h、game.c文件中给出。
摘要由CSDN通过智能技术生成

实现的拓展功能如下:

1.设置游戏难度等级
2.保证玩家在第一把踩雷后不被炸死
3.若排雷的地方无雷,自动扩展到有雷的周围,并给出雷数
4.标记(相当于扫雷游戏中的插旗子)
5.取消标记

分析:

1.用二维字符数组mine[ROWS][COLS]来存储雷,现在我们用字符1来表示有雷,字符0表示无雷。用二维字符数组show[ROWS][COLS]将所有的元素初始化为*,并打印作为展现给玩家的。同时用show数组来表示对应的mine数组中周围雷即字符0的个数。
对于边缘的格子无法计算雷的个数,因此需再增加2行2列,防止数组越界。
2.游戏难度等级的设置即就是雷的个数和棋盘大小不同,即就是Putmine中传的COUNT(雷数)不同,棋盘大小不同也就是在初始化、埋雷、扫雷、打印棋盘等函数中传的行、列数不同,由于是控制台程序,没有将一般模式和困难模式的棋盘打印的过大(因为会丑,也容易眼花),正常情况下扫雷的中级模式是40个雷,16*16格,高级模式是99个雷,16*30格.
3.为了保证玩家体验,保证玩家在第一把踩雷后不被炸死,此时只需要判断玩家第一次排查的坐标是否等于雷的坐标,如果是,将雷悄悄移走(重新生成随机数)
4.若排雷的地方无雷,自动扩展到有雷的周围,并给出雷数,此时需要用到递归,直至递归到周围有雷停止,并计算雷数,显示在棋盘上。
5.标记与取消标记这个是很容易实现的,将标记位置改为P(也可以为其他),取消标记改回*即可。

实现效果:

详细代码如下:

test.c

/*
date:2018/12/27
author:Better Me1
program:Mine Clearance
compiler:Visual Studio 2013
拓展功能:
1.设置游戏难度等级
2.保证玩家在第一把踩雷后不被炸死
3.若排雷的地方无雷,自动扩展到有雷的周围,并给出雷数
4.标记(相当于扫雷游戏中的插旗子)
5.取消标记
*/

/*测试部分*/
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
#include <stdio.h>
#include <stdlib.h>

void menu(){
	printf("************  扫雷小游戏  ************\n");
	printf("******  1.进入游戏  2.退出游戏  ******\n");
	printf("**************************************\n");
}
void menu2(){
	printf("********  请选择要挑战的模式  ********\n");
	printf("********  1.简单模式(10个雷)********\n");
	printf("********  2.一般模式(15个雷)********\n");
	printf("********  3.困难模式(20个雷)********\n");
}
void game(int COUNT ){
	if (COUNT == 10){
		char mine[ROWS][COLS] = { 0 };
		char show[ROWS][COLS] = { 0 };//显示雷,给玩家看
		InitBoard(mine, ROWS, COLS, '0');
		InitBoard(show, ROWS, COLS, '*');//初始化棋盘
		Putmine(mine, ROW-6, COL-6, COUNT);//埋雷
		//DisplayBoard(mine, ROW - 6, COL - 6);
		DisplayBoard(show, ROW-6, COL-6);//打印棋盘
		Findmine(mine, show, ROW-6, COL-6, COUNT);//扫雷
	}
	else if (COUNT == 15){
		char mine[ROWS][COLS] = { 0 };
		char show[ROWS][COLS] = { 0 };//显示雷,给玩家看
		InitBoard(mine, ROWS, COLS, '0');
		InitBoard(show, ROWS, COLS, '*');//初始化棋盘
		Putmine(mine, ROW - 2, COL - 2, COUNT);//埋雷
		//DisplayBoard(mine, ROW - 2, COL - 2);
		DisplayBoard(show, ROW - 2, COL - 2);//打印棋盘
		Findmine(mine, show, ROW - 2, COL - 2, COUNT);//扫雷
	}
	else{
		char mine[ROWS][COLS] = { 0 };
		char show[ROWS][COLS] = { 0 };//显示雷,给玩家看
		InitBoard(mine, ROWS, COLS, '0');
		InitBoard(show, ROWS, COLS, '*');//初始化棋盘
		Putmine(mine, ROW, COL, COUNT);//埋雷
		//DisplayBoard(mine, ROW, COL);
		DisplayBoard(show, ROW, COL);//打印棋盘
		Findmine(mine, show, ROW , COL, COUNT);//扫雷
	}
}
void test(){
	srand((unsigned int)time(0));//随机种子
	int input = 0;
	int input2 = 0;
	int COUNT = 0;
	do{
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		system("cls");
		switch (input){
		case 1:
			while (1){
				menu2();
				printf("请选择:>");
				scanf("%d", &input2);
				switch (input2){
				case 1:
					COUNT = EASY_COUNT;
					break;
				case 2:
					COUNT = USUAL_COUNT;
					break;
				case 3:
					COUNT = HARD_COUNT;
					break;
				default:
					printf("输入有误,请重新选择!\n");
					break;
				}
				if (input2 >= 1 && input2 <= 3){
					break;
				}
			}
			system("cls");
			game(COUNT);
			break;
		case 2:
			printf("退出游戏!\n");
			break;
		default:
			printf("输入有误,请重新选择!\n");
			break;
		}
	} while ((input - 2));
}
void main(){
	test();
	system("pause");
}

game.h

#ifndef _GAME_H_
#define _GAME_H

#define EASY_COUNT 10 //简单级,10个雷
#define USUAL_COUNT 15 //普通级,15个雷
#define HARD_COUNT 20 //单级,20个雷


#define ROW 15//行
#define COL 15 //列

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

void InitBoard(char board[ROWS][COLS], int rows, int cols, char set);//初始化棋盘
void DisplayBoard(char board[ROWS][COLS], int row, int col);//打印棋盘
void Putmine(char board[ROWS][COLS], int row, int col, int count);//埋雷
void Findmine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col,int count);//扫雷

#endif

game.c

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

void InitBoard(char board[ROWS][COLS], int rows, int cols, char set){
	memset(board, set, rows*cols*sizeof(board[0][0]));
}
void DisplayBoard(char board[ROWS][COLS], int row, int col){
	int i, j = 0;
	if (row == ROW - 6){
		printf("------------------------------\n");
	}
	if (row == ROW - 2){
		printf("-----------------------------------------\n");
	}
	if (row == ROW){
		printf("----------------------------------------------\n");
	}
	for (i = 0; i <= row; i++){
		for (j = 0; j <= col; j++){
			if (i == 0 || j == 0){
				if (j == 0){
					if (i < 10){
						printf("%d  ", i);
					}
					else{
						printf("%d ", i);
					}
				}
				else{
					if (j < 10){
						printf("%d  ", j);
					}
					else{
						printf("%d ", j);
					}
				}
			}
			else{
				printf("%c  ", board[i][j]);
			}
		}
		printf("\n");
	}
	if (row == ROW - 6){
		printf("------------------------------\n");
	}
	if (row == ROW - 2){
		printf("-----------------------------------------\n");
	}
	if (row == ROW){
		printf("----------------------------------------------\n");
	}
}
void Putmine(char board[ROWS][COLS], int row, int col, int count){
	int c = 0;//埋好的雷的个数
	int i = 0;
	int j = 0;
	do{
		i = rand() % row + 1;
		j = rand() % col + 1;
		if (board[i][j] =='0'){//保证雷的个数为 count个
			board[i][j] = '1';
			c++;
		}	
	} while (count-c);
}
/*统计雷的个数*/
int MineCount(char mine[ROWS][COLS], int i, int j){
	return (mine[i - 1][j] +
		mine[i - 1][j + 1] +
		mine[i][j + 1] +
		mine[i + 1][j + 1] +
		mine[i + 1][j] +
		mine[i + 1][j - 1] +
		mine[i][j - 1] +
		mine[i - 1][j - 1]) - 8 * '0';
}
void ExpansionMine(char mine[ROWS][COLS], char show[ROWS][COLS], int i, int j, int row, int col){
	if (MineCount(mine, i, j) == 0){
		show[i][j] = ' ';
		//再次遍历周围的雷
		if (i - 1 > 0 && show[i - 1][j] == '*'){
		//	printf("1\n");
			ExpansionMine(mine, show, i - 1, j, row, col);//递归
		}
		if (i - 1 > 0 && j + 1 <= col && show[i - 1][j + 1] == '*'){
			ExpansionMine(mine, show, i - 1, j + 1, row, col);
		}
		if (j + 1 <= col && show[i][j + 1] == '*'){
			ExpansionMine(mine, show, i, j + 1, row, col);
		}
		if (i + 1 <= row && j + 1 <= col && show[i + 1][j + 1] == '*'){
			ExpansionMine(mine, show, i + 1, j + 1, row, col);
		}
		if (i + 1 <= row && show[i + 1][j] == '*'){
			ExpansionMine(mine, show, i + 1, j, row, col);
		}
		if (i + 1 <= row && j - 1 >0 && show[i + 1][j - 1] == '*'){
			ExpansionMine(mine, show, i + 1, j - 1, row, col);
		}
		if (j - 1 > 0 && show[i][j - 1] == '*'){
			ExpansionMine(mine, show, i, j - 1, row, col);
		}
		if (i - 1 > 0 && j - 1 > 0 && show[i - 1][j + 1] == '*'){
			ExpansionMine(mine, show, i - 1, j + 1, row, col);
		}
	}
	else{//周边有雷
		show[i][j] = MineCount(mine, i, j) + '0';
	}
}
void menu3(){
	printf("********   1.标记    2.排查   ********\n");
	printf("请选择:>");
}
void Findmine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int count){
	int i, j;//行列坐标
	int playcount = 0;//玩家排雷的次数
	int remine = 0;//已标记的或没有排查的坐标;
	while (remine!=count){
		//printf("%d", remine);
		int input = 0;
		printf("***** 1.标记  2.取消标记  3.排查 *****\n");
		printf("请选择:>");
		scanf("%d", &input);
		if (input == 1){
			printf("请输入要标记的坐标(如:a b):>");
			scanf("%d %d", &i, &j);
			if (i >= 1 && i <= row && j >= 1 && j <= col){
				if (show[i][j] == '*'){
					show[i][j] = 'P';
					system("cls");
					DisplayBoard(show, row, col);
				}
				else if (show[i][j] == 'P'){
					printf("此坐标已被标记过,请重新输入!\n");
				}
				else{
					printf("此坐标已被排查过,请重新输入!\n");
				}
			}

			else{
				printf("坐标输入有误,请重新输入!\n");
			}
		}
		else if (input == 2){
			printf("请输入要取消标记的坐标(如:a b):>");
			scanf("%d %d", &i, &j);
			if (i >= 1 && i <= row && j >= 1 && j <= col){
				if (show[i][j] == 'P'){
					show[i][j] = '*';
					system("cls");
					DisplayBoard(show, row, col);
				}
				else if (show[i][j] == '*'){
					printf("此坐标还没有被标记过,请重新输入!\n");
				}
				else{
					printf("此坐标已被排查过,请重新输入!\n");
				}
			}

			else{
				printf("坐标输入有误,请重新输入!\n");
			}
		}
		else if (input == 3){
			//printf("%d", remine);
			printf("请输入要排查的坐标(如:a b):>");
			scanf("%d%d", &i, &j);
			if (i >= 1 && i <= row && j >= 1 && j <= col){
				if (show[i][j] == '*'){
					if (mine[i][j] == '1'){
						if (playcount == 0){//此时说明玩家首次排雷且踩到雷了
							mine[i][j] = '0';
							Putmine(mine, row, col, 1);//重新放雷,保证玩家在第一把不踩雷
							playcount = 1;
							ExpansionMine(mine, show, i, j, row, col);//扩展周边的雷
							DisplayBoard(show, row, col);
						}
						else{
							printf("很遗憾,你被炸死了!\n");
							printf("雷阵布局如下:\n");
							DisplayBoard(mine, row, col);
							break;
						}
					}
					else{
						ExpansionMine(mine, show, i, j, row, col);//扩展周边的雷
						system("cls");
						//DisplayBoard(mine, row, col);
						DisplayBoard(show, row, col);
						playcount = 1;
					}
				}
				else if (show[i][j] == 'P'){
					printf("此坐标已被标记过,请重新输入!\n");
				}
				else{
					printf("此坐标已被排查过,请重新输入!\n");
				}
			}
			else{
				printf("坐标输入有误,请重新输入!\n");
			}
		}
		else{
			printf("输入有误,请重新输入!\n");
		}
		remine = 0;//重新统计;
		for (int m = 1; m <= row; m++){
			for (int n = 1; n <= col; n++){
				if ((show[m][n] == '*' )||( show[m][n] == 'P')){
					remine++;
				}
			}
		}
	}
	//printf("%d", remine);
	if (remine == count){
		printf("恭喜您,排雷成功!\n");
		printf("雷阵布局如下:\n");
		DisplayBoard(mine, row, col);
	}

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值