扫雷C语言详解

目录

1.模块化与思路

2.各文件和函数具体实现


1.模块化与思路

可以采用模块化的方式来制作,这里我们创建两个源文件,一个头文件。

 game.h的头文件里存放头文件,函数定义和自定义信息。

test.c 实现大体逻辑和游戏的主体功能。

game.c里面实现所有具体功能的函数。

 test.c   main函数思路:

主要封装两个函数

-menu()打印菜单

-minesweeper()扫雷游戏

minesweeper()扫雷游戏思路:

棋盘实现思路:

假如用于实现初级的扫雷: 需要9 * 9的格子来展示,所以需要使用二维数组来构建棋盘。

因为打印出来给玩家看的数组不能暴露雷的位置,还要时时打印排雷的位置上周围雷的位置。我们可以创建两个棋盘mine,show。一个是用于放雷的(玩家不可见),拿来记录雷的位置便于统计周围的雷的数字。另一个是用于排查显示的,需要初始化为全*,随时更新和打印给玩家看。

为了可以较方便改变雷的数目和棋盘的大小,在game.h里定义棋盘的行数列数和雷的个数。

#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define MINE_COUNT 10

//因为计算坐标周围雷的个数时,要计算周围八个坐标中雷的个数之和。为了防止当坐标在边角时,计算周围雷的个数时发生数组越界,mine数组和show数组大小都应在扫雷盘面的大小基础上各增加两行或两列。

minesweeper()扫雷游戏封装函数和功能

主要封装五个函数

 -init_show(show,ROWS,COLS);  //初始化show数组全为*


 -init_mine(mine, ROWS, COLS, MINE_COUNT); //初始化mine数组全为0,随机数布置雷(记1) 


 -print(arr, ROW, COL);//打印show或者mine棋盘,根据arr传进来啥就打印啥

  -dispose(show, mine, ROWS, COLS, i, j);
 //对玩家要排雷的坐标进行处理。 如果是雷返回1,如果不是,尽可能把所有的非雷数字放进show数组,返回0 

//像下面两种都是非雷的情况。对于坐标来说,如果周围一圈都是非雷,需要类似再处理周围八个坐标。

-numof(show, ROW, COL)//计算当前棋盘的空位并返回,用于判断是否成功排完所有雷了

2.各文件和函数具体实现

注释都在daim!

test.c文件

        -主要是main函数实现循环逻辑

        -menu 和minesweepr 在game.c具体实现

#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
int main()
{
	srand((unsigned int)time(NULL));
	int flag = 0;
	do {
		menu();
		scanf("%d", &flag);
		if (1 == flag)
		{
			system("cls");
			minesweeper();
		}
		else if (0 == flag)
			printf("退出游戏!");
		else
			printf("输入的数字无效,请重新输入!");
	} while (flag);
	

	
	return 0;
}

game.c文件

menu和minesweepr函数:

​
​
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"  //包含头文件

void menu()
{
	printf("--------welcom!--------\n");
	printf("--------1.play --------\n");
	printf("--------0.exit --------\n");
	printf("-----请输入选择:>------\n");

}

void minesweeper()
{
	
	char show[ROWS][COLS] = { 0 };
	char mine[ROWS][COLS] = { 0 };

	init_show(show,ROWS,COLS);
	init_mine(mine, ROWS, COLS, MINE_COUNT);
	print(show, ROW, COL);


	int i = 0;
	int j = 0;
	do {
		if (numof(show, ROW, COL) > MINE_COUNT)
		{
            //有空位
			printf("请输入您要排雷的坐标:>");
			scanf("%d %d", &i, &j);
            
			    if (i >= 1 && i <= 9 && j >= 1 && j <= 9)
			{
                //坐标没超出范围
				
                int flag = dispose(show, mine, ROWS, COLS, i, j);
				 //如果是雷返回1,否则把所有的非雷数字放进show数组,返回0
				if (flag)
				{
					print(mine, ROW, COL);
					printf("很遗憾,您扫雷失败。\n");
					break;
				}
				else
				{
					print(show, ROW, COL);

				}
			}

			else
			{
                //坐标超范围
				printf("您输入的坐标有误!请重新输入!\n");
			}



		}
		else
		{
            //没空位
			printf("恭喜你,扫雷成功!\n");
				break;
		}

	} while (1);


}



​

​

 init_show和init_mine函数

void init_show(char show[ROWS][COLS], int rows, int cols)
{
	int i = 0;
	for (i = 0; i < rows; i++)
	{
		int j = 0;
		for (j = 0; j < cols; j++)
		{
			show[i][j] = '*';
		}
	}
}
void init_mine(char mine[ROWS][COLS], int rows, int cols,int mine_count)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < rows; i++)
	{
		
		for (j = 0; j < cols; j++)
		{
			mine[i][j] = '0';
		}
	}
	//布雷

	while (mine_count > 0)
	{
		i = rand() % 9 + 1;
		j = rand() % 9 + 1;
		if (mine[i][j] == '0')
		{
			mine[i][j] = '1';
			mine_count--;
		}

	}
}

 print函数

void print(char arr[ROWS][COLS], int row, int col)
{
	int i = 0;
	int j = 0;

    //美化打印出来的棋盘,加上列数坐标
	for (i = 0; i <= row; i++)
	{
		printf("%d ", i);
	}


	printf("\n  - - - - - - - - -\n");
	for (i = 1; i <= row; i++)
	{

		printf("%d|", i);//美化打印出来的棋盘,加行数坐标

		for (j = 1; j <= col; j++)
		{
			printf("%c ", arr[i][j]);
		}
		printf("\n");
	}
}

numof函数

int numof(char show[ROWS][COLS], int row, int col)
{
	int i = 0;
	int j = 0;
	int num = 0;
	for (i = 1; i <= row; i++)
	{
		for (j = 1; j <= col; j++)
		{
			if (show[i][j] == '*')
				num++;
		}
	}
	return num;
}

dispose函数

int dispose(char show[ROWS][COLS], char mine[ROWS][COLS], int rows, int cols, int i, int j)
{
	//判断是不是雷
	if (mine[i][j] == '1')
	{
		return 1;
	}
	else
	{
		int flag = mine[i - 1][j - 1] + mine[i][j - 1] + mine[i + 1][j - 1] 
					+ mine[i - 1][j] + mine[i + 1][j] 
					+ mine[i - 1][j + 1] + mine[i][j + 1] + mine[i + 1][j + 1];
		if (flag == '0' * 8)
		{
			//周围都是0,没有雷,递归
			show[i][j] = ' ';
			

			if(show[i - 1][j - 1]=='*') //说明没有处理过,递归处理
				dispose( show,mine, ROWS, COLS, i-1, j-1);
			if (show[i][j - 1] == '*')
				dispose(show, mine, ROWS, COLS, i , j - 1);
			if (show[i + 1][j - 1] == '*')
				dispose(show, mine, ROWS, COLS, i + 1, j - 1);
			if (show[i - 1][j ] == '*')
				dispose(show, mine, ROWS, COLS, i - 1, j );
			if (show[i + 1][j ] == '*')
				dispose(show, mine, ROWS, COLS, i + 1, j );
			if (show[i - 1][j + 1] == '*')
				dispose(show, mine, ROWS, COLS, i - 1, j + 1);
			if (show[i ][j + 1] == '*')
				dispose(show, mine, ROWS, COLS, i , j + 1);
			if (show[i + 1][j + 1] == '*')
				dispose(show, mine, ROWS, COLS, i + 1, j + 1);
			return 0;
		}
		else 
		{
			//周围有雷,记录周围雷的个数并打印
			show[i][j] = flag - '0' * 8+'0';
			return 0;

		}
	}
}

game.h

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

#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define MINE_COUNT 10


void menu();
void minesweeper();
void init_show(char show[ROWS][COLS],int rows, int cols);
void init_mine(char mine[ROWS][COLS], int rows, int cols,int mine_count);
void print(char arr[ROWS][COLS], int row, int col);
int dispose(char show[ROWS][COLS], char mine[ROWS][COLS], int rows,int cols, int i,int j);
int numof(char show[ROWS][COLS], int row, int col);

  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
扫雷是一种经典的游戏,可以使用C语言来实现。以下是一个简单的扫雷程序的实现示例: ```c #include <stdio.h> #include <stdlib.h> #include <time.h> #define ROWS 10 // 行数 #define COLS 10 // 列数 #define MINES 10 // 雷的数量 void init_game(char board[][COLS], int rows, int cols); // 初始化游戏面板 void print_board(char board[][COLS], int rows, int cols); // 打印游戏面板 void set_mines(char board[][COLS], int rows, int cols, int mines); // 布雷 void get_neighbors(int row, int col, int rows, int cols, int neighbors[]); // 获取邻居格子 int count_mines(char board[][COLS], int row, int col, int rows, int cols); // 计算某个格子周围的雷数 void reveal(char board[][COLS], int row, int col, int rows, int cols); // 翻开某个格子 int game_over(char board[][COLS], int rows, int cols); // 判断游戏是否结束 int main() { char board[ROWS][COLS]; int row, col; srand((unsigned)time(NULL)); // 设置随机数种子 init_game(board, ROWS, COLS); // 初始化游戏面板 set_mines(board, ROWS, COLS, MINES); // 布雷 print_board(board, ROWS, COLS); // 打印游戏面板 while (1) { printf("请输入坐标(行 列): "); scanf("%d %d", &row, &col); if (row < 0 || row >= ROWS || col < 0 || col >= COLS) { printf("输入错误,请重新输入\n"); continue; } if (board[row][col] == '*') { // 点到雷了 printf("游戏结束!你输了\n"); board[row][col] = 'X'; // 标记点到的雷 print_board(board, ROWS, COLS); break; } else { reveal(board, row, col, ROWS, COLS); // 翻开格子 print_board(board, ROWS, COLS); } if (game_over(board, ROWS, COLS)) { // 判断游戏是否结束 printf("游戏结束!你赢了\n"); break; } } return 0; } // 初始化游戏面板 void init_game(char board[][COLS], int rows, int cols) { int i, j; for (i = 0; i < rows; i++) { for (j = 0; j < cols; j++) { board[i][j] = '-'; } } } // 打印游戏面板 void print_board(char board[][COLS], int rows, int cols) { int i, j; printf(" "); for (j = 0; j < cols; j++) { printf(" %d", j); } printf("\n"); for (i = 0; i < rows; i++) { printf("%d ", i); for (j = 0; j < cols; j++) { printf("%c ", board[i][j]); } printf("\n"); } printf("\n"); } // 布雷 void set_mines(char board[][COLS], int rows, int cols, int mines) { int count = 0, i, j; while (count < mines) { i = rand() % rows; j = rand() % cols; if (board[i][j] == '-') { board[i][j] = '*'; count++; } } } // 获取邻居格子 void get_neighbors(int row, int col, int rows, int cols, int neighbors[]) { int i, j, k = 0; for (i = row - 1; i <= row + 1; i++) { for (j = col - 1; j <= col + 1; j++) { if (i >= 0 && i < rows && j >= 0 && j < cols && (i != row || j != col)) { neighbors[k++] = i * cols + j; } } } } // 计算某个格子周围的雷数 int count_mines(char board[][COLS], int row, int col, int rows, int cols) { int neighbors[8], count = 0, i; get_neighbors(row, col, rows, cols, neighbors); for (i = 0; i < 8; i++) { if (board[neighbors[i] / cols][neighbors[i] % cols] == '*') { count++; } } return count; } // 翻开某个格子 void reveal(char board[][COLS], int row, int col, int rows, int cols) { int count; if (board[row][col] != '-') { // 已经翻开了 return; } count = count_mines(board, row, col, rows, cols); if (count > 0) { // 周围有雷 board[row][col] = '0' + count; } else { // 周围没有雷 board[row][col] = ' '; reveal(board, row - 1, col, rows, cols); reveal(board, row + 1, col, rows, cols); reveal(board, row, col - 1, rows, cols); reveal(board, row, col + 1, rows, cols); } } // 判断游戏是否结束 int game_over(char board[][COLS], int rows, int cols) { int i, j, count = 0; for (i = 0; i < rows; i++) { for (j = 0; j < cols; j++) { if (board[i][j] == '-' || board[i][j] == '*') { count++; } } } return count == MINES; } ``` 在这个示例程序中,我们使用二维字符数组来表示游戏面板。其中,'-'表示未翻开的格子,'*'表示雷,' '表示周围没有雷的格子,'1'-'8'表示周围有1-8个雷的格子,'X'表示点到的雷。我们使用了递归算法来实现翻开格子的功能,当某个格子周围没有雷时,我们会递归地翻开它周围的格子,直到所有周围有雷的格子都被标记为'1'-'8'。 这只是一个简单的示例程序,还有很多可以改进的地方。比如,可以添加计时器和计分系统,以及更加友好的界面等等。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值