• C语言扫雷游戏完整实现(上)



    前言

    C语言从新建文件到游戏菜单,游戏函数,初始化棋盘,打印棋盘,布置雷函数,玩家排雷菜单,标记功能菜单及实现等的操作。

    下半部分: C语言扫雷游戏完整实现(下)

    一、新建好头文件和源文件

    • 库函数头文件常数都定义在game.h头文件中
    • 在test.c源文件和game.c源文件中通过#include "game.h"引入game.h头文件即可
      1. 在test.c源文件中实现菜单以及游戏函数的调用等功能。
      1. 在game.h头文件中主要完成游戏函数的声明等功能。
      1. 在game.c源文件中完成函数的定义/实现工程。

    在这里插入图片描述

    二、实现游戏菜单选择功能

    // game.h 头文件
    #include 
    
    • 1
    • 2

    // test.c 源文件
    #include "game.h"
    
    
    // 定义游戏菜单函数
    void menu()
    {
    	printf("**********************\n");
    	printf("*****   1. Play  *****\n");
    	printf("*****   0. Quit  *****\n");
    	printf("**********************\n");
    }
    int main()
    {
    	int input = 0; // 定义输入菜单选项的变量
    	do
    	{
    		// 游戏菜单
    		menu();
    		printf("请选择:>");
    		scanf("%d", &input);
    		// 不同选择对应不同结果
    		switch (input)
    		{
    		case 1:
    			printf("扫雷游戏开始!!!\n");
    			break;
    		case 0:
    			printf("推出游戏!!!\n");
    			break;
    		default:
    			printf("选择错误,请重新输入\n");
    			break; // 因为要重新输入所以从菜单开始循环
    		}
    	} while (input); // 输入为0退出游戏,同时停止循环
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    三、定义游戏函数

    • 以9×9为例
    • 需要首先定义 11 × 11(为了便于检测棋盘边边位置的雷) 的棋盘(二维数组)
    • 打印9×9的棋盘即可
    • -需要定义两个棋盘
    • 一个用来存放布置雷的信息
    • 一个用来存放玩家操作信息
    // game.h 头文件
    #include 
    
    #define ROW 9
    #define COL 9
    
    #define ROWS ROW + 2
    #define COLS COL + 2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    // test.c 源文件
    #include "game.h"
    // 定义游戏菜单函数
    void menu()
    {
    	printf("**********************\n");
    	printf("*****   1. Play  *****\n");
    	printf("*****   0. Quit  *****\n");
    	printf("**********************\n");
    }
    --------------------------------------------------------------
    void game()
    {
    	// 定义两个二维数组
    	char mine[ROWS][COLS] = { 0 };
    	char show[ROWS][COLS] = { 0 };
    
    	// 初始化棋盘
    }
    ---------------------------------------------------------------
    int main()
    {
    	int input = 0; // 定义输入菜单选项的变量
    	do
    	{
    		// 游戏菜单
    		menu();
    		printf("请选择:>");
    		scanf("%d", &input);
    		// 不同选择对应不同结果
    		switch (input)
    		{
    		case 1:
    			printf("扫雷游戏开始!!!\n");
    	-------------------------------------------------
    			game();
    	-------------------------------------------------
    			break;
    		case 0:
    			printf("推出游戏!!!\n");
    			break;
    		default:
    			printf("选择错误,请重新输入\n");
    			break; // 因为要重新输入所以从菜单开始循环
    		}
    	} while (input); // 输入为0退出游戏,同时停止循环
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    四、初始化棋盘

    • 将存放布置雷信息的棋盘初始化为 ‘0’。----设计 ‘0’表示没有雷,‘1’表示雷。
    • 将玩家操作信息的棋盘初始化为 ‘*’。
    // test.c --game函数
    void game()
    {
    	// 定义两个二维数组
    	char mine[ROWS][COLS] = { 0 };
    	char show[ROWS][COLS] = { 0 };
    
    	// 初始化棋盘
    	InitBoard(mine, ROWS, COLS, '0');
    	InitBoard(show, ROWS, COLS, '*');
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    // game.h 头文件
    #include 
    
    #define ROW 9
    #define COL 9
    
    #define ROWS ROW + 2
    #define COLS COL + 2
    
    // 初始化棋盘函数的声明
    void InitBoard(char board[ROWS][COLS], int rows, int cols, char sign);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    // game.c 源文件
    #include "game.h"
    
    // 初始化棋盘函数的定义
    void InitBoard(char board[ROWS][COLS], int rows, int cols, char sign)
    {
    	int i = 0;
    	for (i = 0; i < rows; i++)
    	{
    		int j = 0;
    		for (j = 0; j < cols; j++)
    		{
    			board[i][j] = sign;
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    五、 打印棋盘函数

    • 只打印9×9的棋盘,所以传入参数 ROW 和 COL。
    • 打印棋盘的同时还可以打印出每行每列的数字,方便玩家操作。
    • 同时打印出分割线例如 -----------扫雷游戏---------------
    //test.c 源文件
    void game()
    {
    	// 定义两个二维数组
    	char mine[ROWS][COLS] = { 0 };
    	char show[ROWS][COLS] = { 0 };
    
    	// 初始化棋盘
    	InitBoard(mine, ROWS, COLS, '0');
    	InitBoard(show, ROWS, COLS, '*');
    
    	// 打印棋盘
    	DisplayBoard(mine, ROW, COL);
    	DisplayBoard(show, ROW, COL);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    //game.h 头文件
    #include 
    
    #define ROW 9
    #define COL 9
    
    #define ROWS ROW + 2
    #define COLS COL + 2
    
    // 初始化函数声明
    void InitBoard(char board[ROWS][COLS], int rows, int cols, char sign);
    
    
    // 打印函数声明
    void DisplayBoard(char board[ROWS][COLS], int row, int col);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    //game.c 源文件
    // 打印棋盘函数定义
    void DisplayBoard(char board[ROWS][COLS], int row, int col)
    {
    	// 打印游戏开头分割线
    	printf("-----扫雷游戏------\n");
    	int i = 0;
    	// 打印每一列数字
    	for (i = 0; i <= row; i++)
    	{
    		printf("%d ", i); // 打印每一列数字
    	}
    	printf("\n");// 打印列数字完换行
    
    	for (i = 1; i <= row; i++)
    	{
    		// 打印每一列数字之前先打印出行号
    		printf("%d ", i);
    		int j = 0;
    		for (j = 1; j <= col; j++)
    		{
    			printf("%c ", board[i][j]);
    		}
    		printf("\n");
    	}
    	// 打印游戏结尾分割线
    	printf("-----扫雷游戏------\n");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    目前可以实现的效果如下图
    在这里插入图片描述

    六、布置雷函数

    • 在初始化棋盘和打印棋盘之间,应该先布置雷。在mine棋盘(数组)中布置。
    • 在game.h文件中定义常量 EASY_COUNT 来表示雷的数量。
    • 雷只用在9×9的范围内布置即可,所以传入参数 ROW 和 COL。
    • 通过生成9×9范围内的随机数,来布置雷。
    • 用到rand函数,引入 stdlib.h 和 time.h 头文件。
    • 为了保证随机数的随机性,需要在test.c的主函数一开始使用srand函数如下图
      在这里插入图片描述
    //test.c 源文件 -- game函数
    void game()
    {
    	// 定义两个二维数组
    	char mine[ROWS][COLS] = { 0 };
    	char show[ROWS][COLS] = { 0 };
    
    	// 初始化棋盘
    	InitBoard(mine, ROWS, COLS, '0');
    	InitBoard(show, ROWS, COLS, '*');
    
    	// 布置雷
    	SetBoard(mine, ROW, COL);
    
    	// 打印棋盘
    	DisplayBoard(mine, ROW, COL);
    	DisplayBoard(show, ROW, COL);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    //game.h 头文件
    #include 
    #include 
    #include 
    
    #define ROW 9
    #define COL 9
    
    #define ROWS ROW + 2
    #define COLS COL + 2
    
    #define EASY_COUNT 10
    
    // 初始化函数声明
    void InitBoard(char board[ROWS][COLS], int rows, int cols, char sign);
    
    
    // 打印函数声明
    void DisplayBoard(char board[ROWS][COLS], int row, int col);
    
    // 布置雷函数声明
    void SetBoard(char board[ROWS][COLS], int row, int col);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    //game.c 源文件
    // 布置雷函数定义
    void SetBoard(char board[ROWS][COLS], int row, int col)
    {
    	int count = EASY_COUNT;
    	int x = 0;
    	int y = 0;
    	while (count)
    	{
    		x = rand() % row + 1;
    		y = rand() % col + 1;
    		if (board[x][y] == '0')
    		{
    			board[x][y] = '1';
    			count--;
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    七、玩家排雷菜单

    • 玩家排雷之前要有标记,排雷,以及退出终止的菜单。
    • 菜单选择需要玩家输入,所以定义变量,如若出入错误,循环输入。
    //test.c 源文件 --- game函数
    void game()
    {
    	int choose = 0;
    	// 定义两个二维数组
    	char mine[ROWS][COLS] = { 0 };
    	char show[ROWS][COLS] = { 0 };
    
    	// 初始化棋盘
    	InitBoard(mine, ROWS, COLS, '0');
    	InitBoard(show, ROWS, COLS, '*');
    
    	// 布置雷
    	SetBoard(mine, ROW, COL);
    
    	// 打印棋盘
    	DisplayBoard(mine, ROW, COL);
    	DisplayBoard(show, ROW, COL);
    
    	// 玩家开始排雷
    	do
    	{
    		printf("****************\n");
    		printf("*** 1. 标记  ***\n");
    		printf("*** 2. 排雷  ***\n");
    		printf("*** 0. 退出  ***\n");
    		printf("****************\n");
    		printf("请选择:>");
    		scanf("%d", &choose);
    
    		if (1 == choose)
    		{
    			printf("标记功能\n");
    		}
    		else if (2 == choose)
    		{
    			printf("排雷功能\n");
    		}
    		else if (0 == choose)
    		{
    			printf("退出游戏\n");
    			break;
    		}
    		else
    		{
    			printf("输入错误,请重新输入\n");
    		}
    	} while (choose);
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    实现效果如下图:
    在这里插入图片描述

    八、标记功能的菜单

    • 标记功能是玩家操作信息,传入show棋盘(数组)。
    • 玩家只在9×9棋盘中标记,所以使用 ROW 和 COL。
    • 标记功能应该有 1. 标记位置 2. 取消标记 3. 不标记了等三个功能。
    • 标记功能实现的同时对标记的雷进行计数,方便判断胜利。
    //test.c 源文件 -- game函数
    void game()
    {
    	int choose = 0;
    	// 定义两个二维数组
    	char mine[ROWS][COLS] = { 0 };
    	char show[ROWS][COLS] = { 0 };
    
    	// 初始化棋盘
    	InitBoard(mine, ROWS, COLS, '0');
    	InitBoard(show, ROWS, COLS, '*');
    
    	// 布置雷
    	SetBoard(mine, ROW, COL);
    
    	// 打印棋盘
    	DisplayBoard(mine, ROW, COL);
    	DisplayBoard(show, ROW, COL);
    
    	// 玩家开始排雷
    	do
    	{
    		printf("****************\n");
    		printf("*** 1. 标记  ***\n");
    		printf("*** 2. 排雷  ***\n");
    		printf("*** 0. 退出  ***\n");
    		printf("****************\n");
    		printf("请选择:>");
    		scanf("%d", &choose);
    
    		if (1 == choose)
    		{
    			printf("标记功能\n");
    			SignBoard(show, mine, ROW, COL);
    		}
    		else if (2 == choose)
    		{
    			printf("排雷功能\n");
    		}
    		else if (0 == choose)
    		{
    			printf("退出游戏\n");
    			break;
    		}
    		else
    		{
    			printf("输入错误,请重新输入\n");
    		}
    	} while (choose);
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    //game.h 头文件
    #include 
    #include 
    #include 
    
    #define ROW 9
    #define COL 9
    
    #define ROWS ROW + 2
    #define COLS COL + 2
    
    #define EASY_COUNT 10
    
    // 初始化函数声明
    void InitBoard(char board[ROWS][COLS], int rows, int cols, char sign);
    
    
    // 打印函数声明
    void DisplayBoard(char board[ROWS][COLS], int row, int col);
    
    // 布置雷函数声明
    void SetBoard(char board[ROWS][COLS], int row, int col);
    
    // 标记功能函数声明
    int SignBoard(char show[ROWS][COLS],char mine[ROWS][COLS], int row, int col);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    //game.c 源文件 ---SignBoard函数
    // 标记功能函数定义
    int SignBoard(char show[ROWS][COLS], char mine[ROWS][COLS], int row, int col)
    {
    	int choose = 0;
    	do
    	{
    		printf("******************\n");
    		printf("*** 1.标记位置 ***\n");
    		printf("*** 2.取消标记 ***\n");
    		printf("*** 0.不标记了 ***\n");
    		printf("******************\n");
    		printf("请选择:>");
    		scanf("%d", &choose);
    
    		if (1 == choose)
    		{
    			printf("标记位置\n");
    		}
    		else if (2 == choose)
    		{
    			printf("取消标记\n");
    		}
    		else if (0 == choose)
    		{
    			printf("不标记了\n");
    			break;
    		}
    		else
    		{
    			printf("输入错误,请重新输入\n");
    		}
    
    	} while (choose);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    实现效果如下图:
    在这里插入图片描述

    九、标记功能菜单的实现

    • 标记位置需要玩家输入
    • 需要判断合法性
    • 需要判断是否被排查
    • 定义两个计数变量,若两变量相等,并且等于雷的个数时,判定排雷成功
    • 每次标记完成或取消标记后,打印棋盘
    //game.c 源文件---SignBoard函数完整
    // 标记功能函数定义
    int SignBoard(char show[ROWS][COLS], char mine[ROWS][COLS], int row, int col)
    {
    	int x = 0;
    	int y = 0;
    	int choose = 0;
    	static int sum = 0; // 定义标记的总数
    	static int count = 0; // 定义标记的雷的总数
    	do
    	{
    		printf("******************\n");
    		printf("*** 1.标记位置 ***\n");
    		printf("*** 2.取消标记 ***\n");
    		printf("*** 0.不标记了 ***\n");
    		printf("******************\n");
    		printf("请选择:>");
    		scanf("%d", &choose);
    
    		if (1 == choose)
    		{
    			printf("请输入标记坐标(空格隔开):>");
    			scanf("%d %d", &x, &y);
    
    			if (x >= 1 && x <= row && y >= 1 && y <= col) // 判断坐标合法性
    			{
    				if (show[x][y] == '*') // 判断坐标是否排查过
    				{
    					show[x][y] = '$';
    					sum++; // 没标记一个加1
    					if (mine[x][y] == '1')
    					{
    						count++; // 标记的位置如果是雷 加1
    					}
    				}
    				else
    				{
    					printf("坐标已经被排查过了,请勿重复排查\n");
    				}
    			}
    			else
    			{
    				printf("超出棋盘范围,请重新输入\n");
    			}
    			DisplayBoard(show, ROW, COL);
    		}
    		else if (2 == choose)
    		{
    			printf("请输入标记坐标(空格隔开):>");
    			scanf("%d %d", &x, &y);
    
    			if (x >= 1 && x <= row && y >= 1 && y <= col) // 判断坐标合法性
    			{
    				if (show[x][y] == '$') // 判断坐标是否标记过
    				{
    					show[x][y] = '*';
    					sum--; // 没标记一个加1
    					if (mine[x][y] == '1')
    					{
    						count--; // 标记的位置如果是雷 加1
    					}
    				}
    				else
    				{
    					printf("坐标未被标记,请重新选择\n");
    				}
    			}
    			else
    			{
    				printf("超出棋盘范围,请重新输入\n");
    			}
    			DisplayBoard(show, ROW, COL);
    		}
    		else if (0 == choose)
    		{
    			// 不标记直接跳转
    			break;
    		}
    		else
    		{
    			printf("输入错误,请重新输入\n");
    		}
    	if (sum == count && count == EASY_COUNT)
    	{
    		sum = 0;
    		count = 0;
    		return EASY_COUNT;
    	}
    	else
    	{
    		return 0;
    	}
    
    	} while (choose);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 把雷的个数设置为1进行测试
    • 主要过程是
      1. 先标记一个不是雷的位置。
      1. 再标记雷的位置。
      1. 最后取消标记不是雷的位置。
      1. 测试是否判定成功。
    • 效果如下图:
      在这里插入图片描述

    总结

    C语言从新建文件到游戏菜单,游戏函数,初始化棋盘,打印棋盘,布置雷函数,玩家排雷菜单,标记功能菜单及实现等的操作及实现效果。

  • 相关阅读:
    「学习笔记」tarjan 求最近公共祖先
    ubuntu默认关联程序
    Llama3 中文通用 Agent 微调模型来啦!(附手把手微调实战教程)
    专用/独享代理与共享代理有何区别?如何选择?
    Docker的数据管理
    Django之同时新增数据到两个数据库表与同时返回两个表的数据(插拔式)
    数据库工具DataGrip V2022.2正式发布——支持导入多个 CSV 文件的选项
    S7-1500 PLC之间进行TCP通信的具体方法和步骤详解(图文)
    面向对象程序设计关于Lua的初识之类
    Dart 异常详解
  • 原文地址:https://blog.csdn.net/Farewell_me/article/details/138078631