扫 雷(比较详细 ~ )

文章介绍了如何使用C语言分文件编写扫雷程序,包括代码思路、头文件、函数实现和测试程序的结构。关键点包括使用宏定义简化行列修改,埋雷策略,以及ASCII码在打印数字时的处理。在test.c中的Game()函数用于整合游戏流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前前后后因为一些原因扫雷程序已经写了不下5遍了,在此分享一下自己发现的一些问题,希望对你有所帮助

代码思路

对于这样的程序,分文件编写能更加有条理且美观,因此我们分了三个文件,分别用来声明所用函数(game.h),实现所用函数(game.c),进行汇总、执行(test.c)
实现扫雷的大体思路:
1.向玩家展示菜单,询问游玩或否
2.扫雷棋盘分为 显示给玩家看的棋盘 和 埋雷用的隐藏的棋盘,也就是说要定义2个二维数组
3.在玩家进入游戏后,系统需要进行 埋雷、打印棋盘给玩家参考、让玩家进行扫雷

剩下的就是各种细节和优化~
1.利用宏定义define 使得之后在修改行列数量时不用挨个修改
2.可以让埋雷的棋盘比显示用的棋盘多2行2列,控制雷埋在非边缘行列,可以对扫雷时周边雷数量的统计进行优化
3.srand((unsigned int)time(NULL))用时间控制随机数生成

扫雷代码

game.h 头文件

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define ROW 10 //排
#define COL 10 //列
//菜单
void Menu();
//初始化棋盘(显示给玩家的数组)
void InitChart(char arr[ROW][COL]);
//埋雷的数组似乎不用专门写个函数 直接 ={ 0 }就好
//打印棋盘
void Print(char arr[ROW][COL]);
//(测试用)打印埋雷棋盘
void Print_Mine(char arr[ROW + 2][ROW + 2]);
//埋雷
void SetMine(char arr[ROW + 2][ROW + 2],int num);
//扫雷
void Play(char arr[ROW][COL], char mine[ROW + 2][COL + 2]);

game.c 函数实现文件

#define _CRT_SECURE_NO_WARNINGS
#include"game.h"
//菜单
void Menu() {
	printf("**************************\n");
	printf("**** 0.退出 ** 1.开始 ****\n");
	printf("**************************\n");
}
//初始化棋盘(显示给玩家的数组)
void InitChart(char arr[ROW][COL]) {
	for (int i = 0; i < ROW; i++) for (int j = 0; j < COL; j++) arr[i][j] = '*';
}
//打印棋盘
void Print(char arr[ROW][COL]) {
	printf("  "); for (int k = 1; k <= COL; k++) printf("%2d", k); printf("\n");
	for (int i = 0; i < ROW; i++) {
		printf("%-2d", i + 1);
		for (int j = 0; j < COL; j++) {
			printf(" %c", arr[i][j]);//查查ACSII码表就知道1如果用%c打印出来是个笑脸(打印不出来),所以不能让这里的值是1
		}
		printf("\n");
	}
}
//(测试用)打印埋雷棋盘
void Print_Mine(char arr[ROW + 2][ROW + 2]) {
	printf("  "); for (int k = 1; k <= COL + 2; k++) printf("%2d", k); printf("\n");
	for (int i = 0; i < ROW + 2; i++) {
		printf("%-2d", i + 1);
		for (int j = 0; j < COL + 2; j++) {
			printf(" %d", arr[i][j]);
		}
		printf("\n");
	}
}
//埋雷——不可重复,不可设置在边缘
void SetMine(char arr[ROW + 2][ROW + 2],int num) {
	while (num != 0) {
		int row = rand() % ROW + 1; int col = rand() % ROW + 1;//随机出来的坐标必然在数组内且不在边缘(1~10)
		if (arr[row][col] != 1) {//可千万注意写 =1时,ASCII码值为1--写='1'时ASCII值为31
			arr[row][col] = 1;	 
			num--;
		}
	}
}

//扫雷
void Play(char chart[ROW][COL], char mine[ROW + 2][COL + 2]) {
	int x = 0, y = 0, i = 0, j = 0, num = 0;
	while (1) {
		x = 0; y = 0; i = 0; j = 0; num = 0;
		//给玩家展示当前棋盘 以及测试用的埋雷棋盘
		system("cls");
		Print(chart);
		Print_Mine(mine);

		printf("请输入坐标:");
		scanf("%d %d", &x, &y);
		//判断坐标是否合理(不能重复,不可越界)
		if (chart[x - 1][y - 1] != '*' || x < 1 || x > ROW || y < 1 || y > COL) {
			printf("请重新输入\n");
			continue;
		}
		//判断是否踩雷(游戏结束)
		if (mine[x][y] == 1) {
			//记得把棋盘展示出来(把所有雷所处的位置也展示出来)***有什么更好的方法吗
			for (i = 0; i < ROW; i++) for (j = 0; j < COL; j++) if (mine[i + 1][j + 1] == 1) chart[i][j] = '#';
			system("cls");
			Print(chart);
			printf("游戏结束!\n");
			break;
		}
		//————已确认可以正常进行————
		//检查周围雷的数量
		for (i = x - 1; i < x + 2; i++) for (j = y - 1; j < y + 2; j++) num += mine[i][j];
		chart[x - 1][y - 1] = num + 48;//让ASCII码值对应相应的数组
		//展示棋盘就交给下一次循环开始做了
	}
}

test.c 总程序

#define _CRT_SECURE_NO_WARNINGS
#include"game.h"
void Game(int num) {
	char chart[ROW][COL];//显示棋盘用数组
	char mine[ROW+2][COL+2] = { 0 };//埋雷数组
	InitChart(chart);
	SetMine(mine, num);
	Play(chart, mine);
	return;
}
int main() {
	srand((unsigned int)time(NULL));//设置随机数
	int input = 0, num = 0;
	while (1) {
		Menu();
		scanf("%d", &input);
		if (input == 0) {
			printf("退出游戏"); break;
		}
		printf("请设置雷的数量:");
		scanf("%d", &num);
		Game(num);
	}
	return 0;
}

一些问题

扫雷作为一个新手入门编写的程序,在不加任何逻辑的情况下,其实只要有了大体的思路,剩下的就是处理各种细节了——主打一个熟能生巧(

char arr[1][1] = 1; 和 char arr[1][1] = ‘1’;

char arr[1][1] = 1; ASCII值为1,用%c打印是个笑脸,打印不出来
char arr[1][1] = ‘1’;ASCII值为49(十六进制31),用%c打印是1
通过 +48 的方式使得char arr[1][1] = 1; 用 %c 能够打印出’1’

关于在test.c里写的Game()函数

可能各位已经习惯于在此写一个函数对所有的步骤进行汇总——是个好习惯
之前写其他程序时将类似于Game()函数的函数写在了game.c里,产生了不少麻烦,所以我想应该有所注意

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值