C语言实现 扫雷游戏 | 简单项目

目录

文件组成

test.c 游戏主题框架         

infor.h 信息模块函数的声明

 infor.c 信息模块的函数定义与功能实现

game.h 游戏模块函数的声明

game.c 游戏模块的函数定义与功能实现

结尾 源码


文件组成

要写一个扫雷游戏,由于体量较大,我们打算分三个.c 文件(源文件) 来定义函数,实现代码,两个 .h 文件(头文件) 来实现我们.c文件中函数的声明和库函数头文件的引用。

三个 源文件 : test.c , game.c , print.c

两个头文件:game.h , print.h

文件的源码 我会放在结尾以供大家学习

test.c 游戏主题框架         

#define _CRT_SECURE_NO_WARNINGS 1

#include "game.h"  /这里引上我们编写好的头文件
#include "infor.h"/里面有我们所有自定函数的声明和库函数头文件的引用

void menu() {/游戏主界面的菜单
	printf("***************************n");
	printf("*******   1. PLAY   *******n");
	printf("*******   0. EXIT   *******n");
	printf("*******   2. INFOR  *******n");
	printf("***************************n");

}

int main() {
	srand((unsigned int)time(NULL));/由于游戏中布置雷需要随机数,我们在这里就将它初始化
	int input;/用来接收玩家输入
	do {/主题采用循环结构 当玩家结束游戏后可以进行选择进入或者退出
		menu();/打印菜单
		printf("请选择序号:>");/提示玩家选择
		scanf("%d", &input);
		switch (input) {
		case 1:
			game();/进入游戏模块
			break;
		case 0:
			printf("退出游戏n");/退出游戏
			break;
		case 2:
			INFOR();/进入信息菜单 查看规则以及其他信息
			break;
		default:
			printf("输入错误 重新输入n");/输入错入提示
		}

	} while (input);/当玩家输入0 退出程序

	return 0;
}

此时我们程序运行起来 就会是这个样子

 

infor.h 信息模块函数的声明

#pragma once

void INFOR();/信息模块入口
void menu_in();/信息模块的菜单
void game_rules();/游戏规则说明
void infor();/补充信息

 infor.c 信息模块的函数定义与功能实现

#include<stdio.h>/引上库函数的头文件


void menu_in() {/只是当玩家选择 1 后显示的菜单
	printf("1.游戏规则n");
	printf("2.制作信息n");
	printf("3.奖励n");
	printf("0.返回n");

}
void game_rules() {/游戏规则
	printf("n踩点和标记需输入对应 行和列如 第一行第一列 应该输入 "1 1"n猜到雷会被炸死,恐怖至极,骨灰都找不到!!!n踩到非雷会显示以它中心3X3矩形范围内雷的个数.n如果显示0会自动帮你展开n正确标记出所有雷,或者踩完所有非雷点即可获胜.nthats it...nn");
}
void infor() {/其他信息这里可以看自己喜好添加
	printf(".一步一步按提示来 不然要炸nn");
}
void reward() {/奖励
	printf("完成1级难度即可获得:> ");
	printf("游戏作者的大拇指!!!n");

}

以上是这一模块函数的定义
——————————————————————————————————————————————————————
以下是则以模块的的框架
跟主界面类似 用到循环体 以实现重复选择

void INFOR() {/这一模块的框架
	menu_in();/菜单
	int input;
	do {
		printf("请选择序号:>");
		scanf("%d", &input);
		switch (input) {
		case 1:
			game_rules();/规则
			break;
		case 2:
			infor();/信息
			break;
		case 3:
			reward();/奖励
			break;
		case 0:
			break;/退出循环,回到主界面
        default:
			printf("输入错误 重新输入n");/输入错入提示
		}
	} while (input);/可以重复选择
}
结束后回到主界面

这时 如果你运行程序 并在主界面输入 2 并按下回车

将会是这样

如继续输入 0 就回到主界面  

至此 扫雷游戏除了游戏 就都编写完成了(狗头)

game.h 游戏模块函数的声明

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

/定义 棋盘行列的全局变量
为了方便 我们定义11X11的棋盘 但只使用 其中9X9的空间
#define ROW 9 
#define COL 9 
#define ROWS 11
#define COLS 11

/扫雷游戏主体
void game();
/初始化棋盘的函数
void InitBoard(char Board[ROWS][COLS], int rows, int cols, char set);
/打印棋盘的函数
void DisplayBoard(char Board[ROWS][COLS], int row, int col);
/设置雷的函数
void SetMine(char Board[ROWS][COLS],int row,int col,int nub);
/玩家排雷(一直玩到结束,返回值为输赢结果)
char FindMine(char Board[ROWS][COLS], char show[ROWS][COLS], int row, int col,int nub);
/返回点周围雷的个数
char CountMine(char Board[ROWS][COLS],char[ROWS][COLS] ,int row, int col);
/将点展开
void Extend(char Board[ROWS][COLS], char show[ROWS][COLS], int row, int col);
/判断赢没赢(赢返回 1 ,没赢返回 0 )
int Is_win(char Board[ROWS][COLS],char show[ROWS][COLS], int row, int col,int nub);
/游戏胜利 或 失败后延时打印结果
void SleepPrint(char* p);

game.c 游戏模块的函数定义与功能实现

为了方便 我们定义两个二维数组 来分别代表 用户看到的棋盘数字 ,标记 (排查雷的信息)的棋盘 和 存放雷的棋盘 里面 只有 雷。

用户棋盘show board:

 

存雷棋盘:

 

玩家可以选择是要踩 还是 要 标记,把所有非标记的雷周围的点都踩完 就赢了:

当玩家踩到非雷时 会显示 这个点 周围雷的个数:

当这个点周围没有雷时 不会显示数字0,而是自动帮你展开 到周围有雷的位置:

 

 只有胜利 或者 被炸死从而结束游戏时 会 打印一次 存放雷的棋盘:

 代码如下 :

#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"


/初始化棋盘的函数
void InitBoard(char Board[ROWS][COLS],int rows,int cols,char set) {
	int i;
	int j;
	for (i = 0; i < rows; i++) {/将每个元素都设为0
		for (j = 0; j < cols; j++) {
			Board[i][j] = set;
		}
	}
}
/打印棋盘的函数   
void DisplayBoard(char Board[ROWS][COLS], int row, int col) {
	int i;
	int j;
	
	printf("————扫雷游戏————n");
	for (j = 0; j < 10; j++) {
		if (0 == j) {
			printf("%d  ", j);
			continue;
		}
		printf("%d ",j);
	}
	printf("nn");
	for (i = 1; i <=row; i++) {
		printf("%d  ", i);
		for (j = 1; j <= col; j++) {
			printf("%c ", Board[i][j]);
		}
		printf("n");
	}
	printf("————扫雷游戏————n");

}

会打印如下棋盘

/设置雷的函数
void SetMine(char Board[ROWS][COLS], int row, int col,int nub) {	 
	int i;
	int j;
	while (nub) { /nub为雷的个数
		 i = rand() % row + 1;/随机生成行
		 j = rand() % col + 1;/随机生成列
		if (Board[i][j] == '*') {/查重
			Board[i][j] = '#';/我们用 字符'#'来表示雷
			nub--;/每设置一个雷 nub自减

		}
	}
}
/数雷的个数的函数
char CountMine(char Board[ROWS][COLS], char show[ROWS][COLS],int row, int col) {
	char count = '0';
	int i; int j;
	for (i = row - 1; i < row + 2; i++) {

		for (j = col - 1; j < col + 2; j++) {/排查点 周围 雷的个数
			
			if (Board[i][j] == '#') {
				count++;

			}
		}

	}
	return count;
	}
	
/当3X3范围内没有雷时 自动展开的函数
这里用到了递归,若周围没有雷就把这个点设成 空白字符 并自动把周围的点都踩了,直到周围有雷为止
void Extend(char Board[ROWS][COLS],char show[ROWS][COLS],int row,int col){
	show[row][col] = ' ';

	int i, j;
	for (i = row - 1; i < row + 2; i++) {
		for (j = col - 1; j < col + 2; j++) {
			
			if (show[i][j] == '*') {
				show[i][j] = CountMine(Board, show, i, j);
				if (show[i][j] == '0') {
					Extend(Board, show, i, j);
				}
			}
		}
		
	}
}
/判断 游戏的函状态的函数
int Is_win(char Board[ROWS][COLS],char show[ROWS][COLS], int row, int col,int nub) {
	int i,j;
	int count = 0;/数正确的标记
	int count0 = 0;/数标记的总个数
	int COUNT = 0;/数*号后面是雷的个数
	int COUNT0 = 0;/数*号的总个数
	for (i = 1; i <=row; i++) {
		for (j = 1; j <= col; j++) {
			if (show[i][j] == '!') {
				count0++;
				if (Board[i][j] == '#') {
					count++;
				}
			}if (show[i][j] == '*') {
				COUNT0++;
				if (Board[i][j] == '#') {
					COUNT++;


				}
			}
		}
	}
	if ((nub == count&&nub==count0)|| COUNT == COUNT0) { 
/如果标记出了所有雷 或者 正确标记了所有没踩了的雷 就代表胜利

		return 1;返回 1
	}
	else if (nub == count && nub <= count0) {
/如果有错误标记或者标记过多
		return 2;返回 2
	}
	/一切正常 但没赢 
	return 0; 返回 0 
}
/玩家 排雷或者标记的函数!
char FindMine(char Board[ROWS][COLS],char show[ROWS][COLS], int row,int col,int nub) {
	int a, b;
	int input=1;
	while (1) {
		printf("请选择是要踩(1)还是要标记(2):>");/标记(插旗)或者 踩点
		scanf("%d", &input);
		switch (input)/这里用switch语句来对玩家的输入 执行不同的语句
		{
		case 1:/ 若玩家输入 1 就是踩点 ,则执行一下语句
			printf("请输入要走的行列:>");
			while (1) { /执行踩
				scanf("%d %d", &a, &b);
				if (a > 0 && a < 10 && b>0 && b < 10) {
					if (show[a][b] != '*' && show[a][b] != '!') {/查重
						printf("这个点 (%d行%d列) 已经踩过了,重新输入:>", a, b);
						continue;
					}
					break;
				}
				else
					printf("输入错误,重新输入:>");/输入错误提示 
			}
			if (Board[a][b] == '#') {/如果该点是雷,则失败,结束游戏
				return 'F';

			}
			else {
				show[a][b] = CountMine(Board, show, a, b);/如果不是雷,数周围雷的个数
				if (show[a][b] == '0') {/如果周围没有雷,调用自动展开函数来自动展开
					Extend(Board, show, a, b);
				}
			}
			if (1 == Is_win(Board, show, row, col, nub)) {/每次走完 判断是否已经赢下游戏
				DisplayBoard(show, row, col);/如果赢了就结束游戏
				return 'W';
			}
			
			DisplayBoard(show, row, col);/打印棋盘
		
			

			break;
		case 2://标记
/更踩点思路相似
			printf("请输入要标记的行列:>");
			while (1) {
				scanf("%d %d", &a, &b);/行 列
				if (a > 0 && a < 10 && b>0 && b < 10) {/判断坐标的合法性

					if (show[a][b] == '!') {/如果这是标记过的点 ,我们就把这个标记取消
						show[a][b] = '*';
/判断是否赢得游戏
						if (1 == Is_win(Board, show, row, col, nub)) {
							DisplayBoard(show, row, col);
							return 'W';
						}
/如果标记多了就提示
						if (2 == Is_win(Board, show, row, col, nub)) {
							printf("标记多了...");
						}
						
						break;
					}
					else {/如果是没标记过的点 我们就把这个点 标记上
/随后在检测是否赢得游戏
						show[a][b] = '!';
						if (1==Is_win(Board, show, row, col,nub)) {
							return 'W';
						}
						if (2 == Is_win(Board, show, row, col, nub)) {
							printf("标记多了...");
						}
						break;
					}
				}
				else {
					printf("输入错误,重新输入:>");
				}
			}
			DisplayBoard(show, row, col);
			break;
/这里判断 最开始选择要踩还是标记那里 是否 输入错误
		default:
			printf("输入错误,重新输入:>");
			printf("n");
		}
	}
	
}

/这是一个 延时打印 胜利图案的函数 增加游戏的趣味性
void SleepPrint(char* p) {
	int i;
	int len = strlen(p);
	for (i = 0; i < len; i += 2) {
		printf("%c%c", *(p + i), *(p + i + 1));
		Sleep(600);
	}

}
这是游戏模块的主体框架
void game() {
	char Board[ROWS][COLS] = { 0 };//布置好雷的信息
	char show[ROWS][COLS] = { 0 };//排查出雷的信息
	InitBoard(Board, ROWS, COLS, '*');
	InitBoard(show, ROWS, COLS, '*');
	printf("请选择游戏难度(1~3):>");
	int tmpe;
	int nub=0;
	do {
		scanf("%d", &tmpe);
		switch (tmpe)
		{
		case 1:
			nub = 10;
			break;
		case 2:
			nub = 15;
			break;
		case 3:
			nub = 20;
			break;
		default:
			printf("输入错误,重新输入:>");
			break;
		}
	} while (tmpe != 1 && tmpe != 3 && tmpe != 2);
	SetMine(Board, ROW, COL, nub);
	DisplayBoard(show, ROW, COL);
	
	char Result=FindMine(Board, show, ROW, COL,nub);
	switch (Result) {
	case 'F':/如果输了 就延时打印 “你被炸死了”
		SleepPrint("你被炸死了");
		for (int i = 0; i < 3; i++) {
			printf(".");
			Sleep(600);
		}
		printf("n");
		DisplayBoard(Board, ROW, COL);
		break;
	case'W':/如果赢了就延时打印 “你赢了”

		SleepPrint("你赢了");
		for (int i = 0; i < 3; i++) {
			printf("!");
			Sleep(600);
		}
		printf("n");
		DisplayBoard(Board, ROW, COL);
	}
}
/随后退出到 主界面 让玩家选择是退出程序 或是进入某个模块

这样 ,我们的扫雷游戏的部分就 完成了 .

结尾 源码

希望这篇博客 能对大家有所帮助,祝看到这篇的博客的人都早日成为 大牛!!!

 游戏的 源文件 头文件:>

                                                 扫雷游戏https://gitee.com/leyi999/project.githttps://gitee.com/leyi999/project.git

        .

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>