C语言实现扫雷--含棋盘扩展

这篇博客介绍了如何使用C语言设计一个扫雷游戏。作者首先定义了棋盘的大小和难度,然后通过递归实现了扫雷的逻辑,包括设置雷、显示棋盘和排雷功能。用户可以选择不同模式进行游戏,当所有非雷格子被正确标记后,游戏结束。博客还展示了代码实现的详细过程和功能演示。
摘要由CSDN通过智能技术生成

设计思路

  1. 利用字符串和终端模拟扫雷游戏.
  2. 组成棋盘的数组比实际棋盘大两个单位, 用于显示坐标轴
  3. 递归模拟扫雷棋盘成片显示
  4. 利用C语言的特性分割各个功能
  5. 棋盘大小, 难度均可扩展

效果演示

gif录制工具: LICEcap

为了方便演示, 在一开始先输出了雷的坐标(1有, 0无). 可以在整体逻辑里去掉这一段.

第一次输入: 演示棋盘的拓展功能, 模拟扫雷点一下如果周围没雷则出一片的效果
第二次输入: 演示正常周围有雷的效果
第三次输入: 演示碰到雷的效果.
在这里插入图片描述

代码

Main

整体逻辑, 循环play, 想拓展可以在头文件加上不同的mode参数, 再在main里让用户每次选择.

#include "game.h"

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

//mine为隐式棋盘, 作为一开始设置雷的标识, 1为有雷, 0为无雷
//show是显式棋盘,输出给用户, *代表没被探索过的位置点位, 数字代表输入点位周围的雷的数量
//第一行和第一列为坐标
void game() {
	//创建棋盘对应的数组
	char mine[ROWS][COLS]; //存放布置好的雷的信息
	char show[ROWS][COLS]; //存放展示的棋盘
	

	initBoard(mine,'0');
	initBoard(show, '*');


	//打印棋盘
	DisplayBoard(show);
	SetMine(mine, EASY_MODE);
	DisplayBoard(mine);
	

	//排查雷
	FindMine(mine, show, EASY_MODE);
}

int main() {

	int input = 0;
	srand((unsigned)time(NULL));

	do {
		menu();
		printf("请选择: ");
		scanf("%d", &input);

		switch (input) {
		case 1:
			game();
			break;
		case 0:
			printf("Game end\n");
			break;
		default:
			printf("Wrong input\n");
			break;
		}

	} while (input);
	
	return 0;
}

头文件

可以通过define不同的模式来让用户在开始时选择难度
这里只define了简单模式, 也就是10个雷

#define ROW 9
#define COL 9
#define ROWS ROW + 2
#define COLS COL + 2
#define EASY_MODE 10 //雷的数量

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


//初始化棋盘
void initBoard(char board[ROWS][COLS], char ch);
void DisplayBoard(char board[ROWS][COLS]);

//布置雷
void SetMine(char board[ROWS][COLS], int count);

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

函数实现

#include "game.h"

//初始化棋盘
void initBoard(char board[ROWS][COLS], char ch) {
	for (int i = 0; i < ROWS; i++) {
		for (int j = 0; j < COLS; j++) {
			board[i][j] = ch;
		}
	}
}

//输出棋盘, 注意第一行和第一列要输出的是坐标
void DisplayBoard(char board[ROWS][COLS]) {
	for (int i = 0; i <= COL; i++) {
		printf("%d ", i);
	}
	putchar('\n');
	
	for (int i = 1; i <= ROW; i++) {
		printf("%d ",i);
		for (int j = 1; j <= COL; j++) {
			printf("%c ", board[i][j]);
		}
		putchar('\n');
	}
	
}

//利用随机数布置棋盘, ROW COL是实际上棋盘的大小
void SetMine(char board[ROWS][COLS], int count) {

	//有雷为1, 无雷为0, 这里用char的1和0 为了后面更方便的排查
	while (count) {
		int x = rand() % ROW + 1;
		int y = rand() % COL + 1;
		if (board[x][y] == '0') {
			board[x][y] = '1';
			count--;
		}
	}
}

//递归扩展棋盘, 模拟扫雷的点一下出一片的情况.
//每次检查都递归当前点的周围8个点位.
//每个检查过的点位不可再检查, 否则就是无限递归下去, 所以这里show的值一直在变化
//这样不仅输出的时候棋盘有变化, 同时可以用show的值作为标记, 跳出递归.
void GetMineCount(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y) {
	if (x >= 1 && x <= ROW && y >= 1 && y <= COL) {

		int count = 
			mine[x - 1][y] +
			mine[x - 1][y - 1] +
			mine[x][y - 1] +
			mine[x + 1][y - 1] +
			mine[x + 1][y] +
			mine[x + 1][y + 1] +
			mine[x][y + 1] +
			mine[x - 1][y + 1] - 8 * '0';

		if (count == 0) {
			show[x][y] = ' ';

			if (show[x - 1][y] == '*') {
				GetMineCount(mine, show, x - 1, y);
			}
			if (show[x - 1][y - 1] == '*') {
				GetMineCount(mine, show, x - 1, y - 1);
			}
			if (show[x][y - 1] == '*') {
				GetMineCount(mine, show, x, y - 1);
			}
			if (show[x + 1][y - 1] == '*') {
				GetMineCount(mine, show, x + 1, y - 1);
			}
			if (show[x + 1][y] == '*') {
				GetMineCount(mine, show, x + 1, y);
			}
			if (show[x + 1][y + 1] == '*') {
				GetMineCount(mine, show, x + 1, y + 1);
			}
			if (show[x][y + 1] == '*') {
				GetMineCount(mine, show, x, y + 1);
			}
			if (show[x - 1][y + 1] == '*') {
				GetMineCount(mine, show, x - 1, y + 1);
			}

		}
		else {
			//棋盘里摆放字符数字
			show[x][y] = count + '0';
		}
	}
}

//排雷, 用户输入坐标, 如果没碰雷, 输出周围雷的个数, 如果周围没雷, 递归拓展寻找范围
//如果碰到雷跳出游戏循环, 回到开始界面.
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int Minecount) {
	int win = 0;


	while (win < ROW * COL - Minecount) {
		printf("请输入要排查的坐标:> ");
		int x = 0;
		int y = 0;
		scanf("%d %d", &x, &y);

		//1. 坐标的合法性
		//2. 该坐标处是不是雷, 不是雷, 统计周围的雷的数量
		if (x >= 1 && x <= ROW && y >= 1 && y <= COL) {
			if (mine[x][y] == '1') {
				printf("这有雷\n");
				DisplayBoard(mine);
				break;
			}
			else {
				GetMineCount(mine, show, x, y);
				DisplayBoard(show);
			}
		}
		else {
			printf("输入错误, 请重新输入.\n");
		}
		//检查雷是否全部排除
		if (win == ROW * COL - Minecount) {
			printf("恭喜排雷成功\n");
		}
	}
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
黑白棋,又叫反棋(Reversi)、奥赛罗棋(Othello)、苹果棋或翻转棋。黑白棋在西方和日本很流行。游戏通过相互翻转对方的棋子,最后以棋盘上谁的棋子多来判断胜负。 棋子:黑白棋棋子每颗由黑白两色组成,一面白,一面黑,共64个(包括棋盘中央的4个)。棋子呈圆饼形。    棋盘:黑白棋棋盘由64格的正方格组成,游戏进行时棋子要下在格内。棋盘可分为“角”、“边”以及黑白棋“中腹”。现今的棋盘多以8x8较为普遍。 棋钟:正式的比赛中可以使用棋钟对选手的时间进行限制。非正式的对局中一般不使用棋钟。 黑白棋的棋盘是一个有8*8方格的棋盘。下棋时将棋下在空格中间,而不是像围棋一样下在交叉点上。开始时在棋盘正中有两白两黑四个棋子交叉放置,黑棋总是先下子。    下子的方法把自己颜色的棋子放在棋盘的空格上,而当自己放下的棋子在横、竖、斜八个方向内有一个自己的棋子,则被夹在中间的全部翻转会成为自己的棋子。 并且,只有在可以翻转棋子的地方才可以下子。  如果玩家在棋盘上没有地方可以下子,则该玩家对手可以连下。双方都没有棋子可以下时棋局结束,以棋子数目来计算胜负,棋子多的一方获胜。在棋盘还没有下满时,如果一方的棋子已经被对方吃光,则棋局也结束。将对手棋子吃光的一方获胜。     每个“翻转棋”游戏开始时,棋盘上已经交叉放好了四颗棋子。其中两颗是黑棋,另两颗是白棋。黑棋总是先走。    当您的棋子在某一直线方向包围了对手的棋子时,就可以翻转这些棋子的颜色,使它们成为您方的颜色。例如,如果您执黑棋,并且看到在一排白棋的某一端是一颗黑棋,那么当您将一颗黑棋放在这一排的另一端时,所有的白棋都将翻转并变为黑棋!   所有的直线方向均有效:水平、垂直和斜线方向。    走棋的唯一规则是只能走包围并翻转对手的棋子。每一回合都必须至少翻转一颗对手的棋子。    按规则不能再走棋时,这一回合弃权。计算机会自动将控制权交给对方。 得分 “翻转棋”的计分方法非常简单。游戏过程中随时都显示黑棋数与白棋数。结束时棋数最多的一方就是赢家。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值