C语言扫雷

宏定义的一些常量

// 未翻开地图
#define UNOPENED_MAP '#'
// 地雷
#define MINE '@'
// 标记
#define MARKE '$'

// 初级地图
#define MAX_ROW_LEVEL0 9
#define MAX_COL_LEVEL0 9
#define NUMBER_OF_MINES0 10
// 中级地图
#define MAX_ROW_LEVEL1 16
#define MAX_COL_LEVEL1 16
#define NUMBER_OF_MINES1 40
// 高级地图
#define MAX_ROW_LEVEL2 16
#define MAX_COL_LEVEL2 30
#define NUMBER_OF_MINES2 99

游戏主体

// 玩家看到的地图, 保存有地雷位置的地图, 地图数组的行边界, 地图数组的列边界, 该局生成的地雷数
void Game(char* show_map, char* mine_map, int max_row, int max_col, int number_of_mines) {
	InitMap(show_map, max_row, max_col);					// 初始化显示地图
	InitMap(mine_map, max_row, max_col);					// 初始化地雷图
	Lay_Mines(mine_map, max_row, max_col, number_of_mines);	// 布雷

	int result;
	time_t start = time();	// 计算用时起
	while (1) {
		int row, col;		// 玩家输入的位置行,列
		// 打印地图
		system("cls");		// 清空屏幕
		PrintMap(show_map, max_row, max_col, number_of_mines);
		// 计算剩余雷数
		NumberOfMines(show_map, mine_map, max_row, max_col, &number_of_mines);
		// 玩家排雷
		PlayerAction(show_map, max_row, max_col, &row, &col);
		// 更新地图	
		UpdateMap(show_map, mine_map, max_row, max_col, row, col);
		// 获取当前游戏状态
		result = ResultJudge(mine_map, max_row, max_col, row, col);
		if (!result) {									// 踩到雷
			*(mine_map + row * max_col + col) = 'X';	// 标记踩到的雷
			break;
		}
		else if (result == 2) {							// 游戏胜利
			number_of_mines = 0;						// 清空剩余地雷数
			break;
		}		
	}
	time_t end = time();	// 计算用时结束

	// 打印游戏结束时的地图
	system("cls");
	PrintMap(mine_map, max_row, max_col, number_of_mines);
	printf("\n游戏结束\n");
	if (result == 2) {
		printf("恭喜您获得胜利!\n");
	}
	else {
		printf("您失败了!\n");
	}
	int ret =  end - start;
	printf("用时: %d:%d\n", ret / 60, ret % 60);
}

初始化地图

两个地图都赋值为未翻开地图

// 地图,行边界,列边界
void InitMap(char* map, int max_row, int max_col) {
	int sum = max_row * max_col;	// 循环次数
	for (int curr = 0; curr < sum; ++curr) {
		*(map + curr) = UNOPENED_MAP;
	}
}

布雷

// 地雷图,行边界,列边界,布雷数
void Lay_Mines(char* mine_map, int max_row, int max_col, int number_of_mines) {
	srand((unsigned int)time(NULL));
	while (number_of_mines > 0) {		// 随机生成地雷位置
		int row = rand() % max_row;
		int col = rand() % max_col;
		char* mine_position = mine_map + row * max_col + col;
		if (*mine_position == MINE) {	// 当前位置存在雷,重新生成地雷位置
			continue;
		}
		*mine_position = MINE;			// 当前位置设为地雷
		--number_of_mines;
	}
}

打印地图

// 地图,行边界,列边界,地雷数
void PrintMap(char* map, int max_row, int max_col, int number_of_mines) {
	// 打印剩余地雷
	printf("剩余地雷: %d\n\n", number_of_mines);

	// 打印列标号
	printf("   |");
	for (int col = 0; col < max_col; ++col) {
		if (col < 10) {			// 单个数直接输出
			printf(" %d |", col);
		}
		else {					// 两位以上的数减少一个空格以对齐
			printf("%d |", col);
		}
	}
	printf("\n");

	// 打印每行
	for (int row = 0; row < max_row;++row) {
		// 打印行分割线
		for (int col = 0; col <= max_col; ++col) {
			printf("---|");
		}
		printf("-\n");
		// 打印行标号
		if (row < 10) {			// 单个数直接输出
			printf(" %d", row);
		}
		else {					// 两位以上的数减少一个空格以对齐
			printf("%d", row);
		}
		// 打印每行的字符数组
		for (int col = 0; col < max_col;++col) {
			printf(" | %c", *(map + row * max_col + col));
		}
		printf(" |\n");
	}
	// 打印最后一行的结束分割线
	for (int col = 0; col <= max_col; ++col) {
		printf("---|");
	}
	printf("-\n");
}

地图的标记及剩余地雷数计算

// 是否要标记地雷,返回剩余雷数
// 显示地图,地雷图,行边界,列边界,地雷数
void NumberOfMines(char* show_map, char* mine_map, int max_row, int max_col, int* number_of_mines_out) {
	// 遍历数组
	for (int row = 0; row < max_row; ++row) {
		for (int col = 0; col < max_col; ++col) {
			// 找到雷的位置并判断周围除了地雷是否还有未翻开的地图
			if (*(mine_map + row * max_col + col) == MINE && IsOpeded(mine_map, max_row, max_col, row, col)) {
				int choice;
				printf("是否要将(%d,%d)位置标记为地雷!是 1, 否 0\n", row, col);
				scanf("%d", &choice);
				while (choice != 0 && choice != 1) {
					printf("输入有误!请重输: ");
					scanf("%d", &choice);
				}
				if (choice) {
					// 两张地图以找到地雷位置进行标记
					*(show_map + row * max_col + col) = MARKE;
					*(mine_map + row * max_col + col) = MARKE;
					--*number_of_mines_out;		// 地雷总数减少
					// 更新地图
					system("cls");
					PrintMap(show_map, max_row, max_col, *number_of_mines_out);		// 打印地图
				}
			}
		}
	}
}

判断周围是否还有位置是未翻开地图

// 地雷图,行边界,列边界,位置行,位置列
// 地雷位置周边一圈是否还有未翻开的地图,0表示有,1表示没有
int IsOpeded(char* mine_map, int max_row, int max_col, int row, int col) {
	if (row > 0 && col > 0 && *(mine_map + (row - 1) * max_col + (col - 1)) == UNOPENED_MAP) {
		return 0;
	}
	// mine_map[row - 1][col]是否是雷
	if (row > 0 && *(mine_map + (row - 1) * max_col + col) == UNOPENED_MAP) {
		return 0;
	}
	// mine_map[row - 1][col + 1]是否是雷
	if (row > 0 && col < (max_col - 1) && *(mine_map + (row - 1) * max_col + (col + 1)) == UNOPENED_MAP) {
		return 0;
	}
	// mine_map[row][col - 1]是否是雷
	if (col > 0 && *(mine_map + row * max_col + (col - 1)) == UNOPENED_MAP) {
		return 0;
	}
	// mine_map[row][col + 1]是否是雷
	if (col < (max_col - 1) && *(mine_map + row * max_col + (col + 1)) == UNOPENED_MAP) {
		return 0;
	}
	// mine_map[row + 1][col - 1]是否是雷
	if (row < (max_row - 1) && col > 0 && *(mine_map + (row + 1) * max_col + (col - 1)) == UNOPENED_MAP) {
		return 0;
	}
	// mine_map[row + 1][col]是否是雷
	if (row < (max_row - 1) && *(mine_map + (row + 1) * max_col + col) == UNOPENED_MAP) {
		return 0;
	}
	// mine_map[row + 1][col + 1]是否是雷
	if (row < (max_row - 1) && col < (max_col - 1) && *(mine_map + (row + 1) * max_col + (col + 1)) == UNOPENED_MAP) {
		return 0;
	}
	return 1;
}

玩家排雷

// 显示地图,行边界,列边界,输出位置行和位置列
void PlayerAction(char* show_map, int max_row, int max_col, int* row_out, int* col_out) {
	printf("请输入排雷位置的行,列: ");
	while (1) {
		scanf("%d,%d", row_out, col_out);
		// 判断输入是否超出边界值
		if (*row_out < 0 || *row_out >= max_row || *col_out < 0 || *col_out >= max_col) {
			printf("非法位置!请重新输入: ");
			continue;
		}
		// 判断位置是否翻过
		if (*(show_map + *row_out * max_col + *col_out) != UNOPENED_MAP) {
			printf("当前位置以排除!请重新输入: ");
			continue;
		}
		break;
	}
}

更新扫雷后的地图

// 显示地图,地雷图,行边界,列边界,位置行,位置列
void UpdateMap(char* show_map, char* mine_map, int max_row, int max_col, int row, int col) {
	// 递归退出
	if (row < 0 || col < 0 || row >= max_row || col >= max_col
		|| *(mine_map + row * max_col + col) != UNOPENED_MAP) {
		return;
	}
	// 周围地雷数统计
	int count = 48;
	// mine_map[row - 1][col - 1]是否是雷
	if (row > 0 && col > 0 && *(mine_map + (row - 1) * max_col + (col - 1)) == MINE) {
		++count;
	}
	// mine_map[row - 1][col]是否是雷
	if (row > 0 && *(mine_map + (row - 1) * max_col + col) == MINE) {
		++count;
	}
	// mine_map[row - 1][col + 1]是否是雷
	if (row > 0 && col < (max_col - 1) && *(mine_map + (row - 1) * max_col + (col + 1)) == MINE) {
		++count;
	}
	// mine_map[row][col - 1]是否是雷
	if (col > 0 && *(mine_map + row * max_col + (col - 1)) == MINE) {
		++count;
	}
	// mine_map[row][col + 1]是否是雷
	if (col < (max_col - 1) && *(mine_map + row * max_col + (col + 1)) == MINE) {
		++count;
	}
	// mine_map[row + 1][col - 1]是否是雷
	if (row < (max_row - 1) && col > 0 && *(mine_map + (row + 1) * max_col + (col - 1)) == MINE) {
		++count;
	}
	// mine_map[row + 1][col]是否是雷
	if (row < (max_row - 1) && *(mine_map + (row + 1) * max_col + col) == MINE) {
		++count;
	}
	// mine_map[row + 1][col + 1]是否是雷
	if (row < (max_row - 1) && col < (max_col - 1) && *(mine_map + (row + 1) * max_col + (col + 1)) == MINE) {
		++count;
	}
	if (count == 48) {	// 周围没雷的赋为空格
		*(show_map + row * max_col + col) = 0;
		*(mine_map + row * max_col + col) = 0;
	}
	else {				// 有雷赋为地雷数
		*(show_map + row * max_col + col) = count;
		*(mine_map + row * max_col + col) = count;
	}
	
	// 如果点开的是空白,则将周围连接在一起的空白全部翻开直到遇到数字
	if (count == 48) {
		UpdateMap(show_map, mine_map, max_row, max_col, row - 1, col);
		UpdateMap(show_map, mine_map, max_row, max_col, row, col - 1);
		UpdateMap(show_map, mine_map, max_row, max_col, row, col + 1);
		UpdateMap(show_map, mine_map, max_row, max_col, row + 1, col);
	}
}

结果判定

// 地雷图,行边界,列边界,位置行,位置列
int ResultJudge(char* mine_map, int max_row, int max_col, int row, int col) {
	if (*(mine_map + row * max_col + col) == MINE) {
		return 0;		// 踩到雷
	}
	int sum = max_row * max_col;
	for (int curr = 0; curr < sum; ++curr) {
		// 地图上还有未翻开地图,游戏继续,否则玩家胜利
		if (*(mine_map + curr) == UNOPENED_MAP) {
			return 1;	// 继续游戏
		}
	}
	return 2;			// 游戏胜利
}

菜单

// 菜单
int Menu() {
	printf("*********************************\n");
	printf("********** MineSweeper **********\n");
	printf("*********************************\n");
	printf("***** 开始:1 ******* 退出:0 *****\n");
	printf("*********************************\n");
	printf("请输入: ");
	int choice;
	scanf("%d", &choice);
	while (choice != 1 && choice != 0) {
		printf("输入有误!请重输: ");
		scanf("%d", &choice);
	}
	return choice;
}

难度选择

int Level() {
	printf("选择难度: 0.初级  1.中级  2.高级\n");
	int choice;	
	scanf("%d", &choice);
	while (choice != 0 && choice != 1 && choice != 2) {
		printf("输入有误!请重输: ");
		scanf("%d", &choice);
	}
	return choice;
}

主函数

int main() {
	while (1) {
		if (Menu() == 0) {	// 0退出游戏
			break;
		}

		int level = Level();
		if (level == 0) {			// 初级,9*9,10个雷,
			char show_map[MAX_ROW_LEVEL0][MAX_COL_LEVEL0],	// 显示地图
				mine_map[MAX_ROW_LEVEL0][MAX_COL_LEVEL0];	// 地雷图
			Game(show_map, mine_map, MAX_ROW_LEVEL0, MAX_COL_LEVEL0, NUMBER_OF_MINES0);
		}
		else if (level == 1) {		// 中级,16*16,40个雷
			char show_map[MAX_ROW_LEVEL1][MAX_COL_LEVEL1],	// 显示地图
				mine_map[MAX_ROW_LEVEL1][MAX_COL_LEVEL1];	// 地雷图
			Game(show_map, mine_map, MAX_ROW_LEVEL1, MAX_COL_LEVEL1, NUMBER_OF_MINES1);
		}
		else {						// 高级,16*30,99个雷
			char show_map[MAX_ROW_LEVEL2][MAX_COL_LEVEL2],	// 显示地图
				mine_map[MAX_ROW_LEVEL2][MAX_COL_LEVEL2];	// 地雷图
			Game(show_map, mine_map, MAX_ROW_LEVEL2, MAX_COL_LEVEL2, NUMBER_OF_MINES2);
		}
	}
	return 0;
}
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的 C 语言扫雷游戏的示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <time.h> #define ROW 10 // 行数 #define COL 10 // 列数 #define MINE_NUM 10 // 雷数 int board[ROW][COL]; // 扫雷棋盘 /** * 在棋盘上随机放置雷 */ void place_mines() { int count = 0; while (count < MINE_NUM) { int row = rand() % ROW; int col = rand() % COL; if (board[row][col] != -1) { board[row][col] = -1; count++; } } } /** * 输出棋盘 */ void print_board() { printf(" "); for (int j = 0; j < COL; j++) { printf(" %d", j); } printf("\n"); for (int i = 0; i < ROW; i++) { printf("%d ", i); for (int j = 0; j < COL; j++) { if (board[i][j] == -2) { printf("* "); } else if (board[i][j] >= 0) { printf("%d ", board[i][j]); } else { printf(". "); } } printf("\n"); } } /** * 计算某个格子周围的雷数 * @param row 行坐标 * @param col 列坐标 * @return 周围雷数 */ int count_mines(int row, int col) { int count = 0; for (int i = row - 1; i <= row + 1; i++) { for (int j = col - 1; j <= col + 1; j++) { if (i >= 0 && i < ROW && j >= 0 && j < COL && board[i][j] == -1) { count++; } } } return count; } /** * 打开某个格子 * @param row 行坐标 * @param col 列坐标 */ void open_cell(int row, int col) { if (board[row][col] == -1) { printf("Game Over!\n"); print_board(); exit(0); } else if (board[row][col] == -2) { board[row][col] = count_mines(row, col); if (board[row][col] == 0) { for (int i = row - 1; i <= row + 1; i++) { for (int j = col - 1; j <= col + 1; j++) { if (i >= 0 && i < ROW && j >= 0 && j < COL) { open_cell(i, j); } } } } } } int main() { srand(time(NULL)); // 初始化棋盘 for (int i = 0; i < ROW; i++) { for (int j = 0; j < COL; j++) { board[i][j] = -2; // -2 表示未打开的格子 } } // 随机放置雷 place_mines(); // 输出初始棋盘 print_board(); // 开始游戏 while (1) { int row, col; printf("Enter row and col: "); scanf("%d%d", &row, &col); if (row >= 0 && row < ROW && col >= 0 && col < COL) { open_cell(row, col); print_board(); } } return 0; } ``` 在这个示例代码中,我们使用一个二维数组 `board` 来表示扫雷棋盘,数组元素的含义如下: - `-1` 表示该格子是一颗雷; - `-2` 表示该格子还未被打开; - 非负整数表示该格子周围有多少颗雷。 游戏开始时,我们随机放置了 `MINE_NUM` 颗雷。然后,程序会要求用户输入一个格子的位置,如果该位置上是一颗雷,则游戏结束;否则,程序会计算该格子周围有多少颗雷,并在棋盘上显示出来。如果该格子周围没有雷,则程序会递归地打开周围的格子,直到不能再打开为止。游戏结束后,程序会输出完整的棋盘并退出。 当然,这只是一个简单的示例代码,实际的扫雷游戏还有很多需要完善的地方,例如计时、计分等等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值