目录
一、扫雷游戏的功能
扫雷功能:
1.通过菜单选择进入游戏还是退出游戏
2.显示9*9的初级棋盘
3.随机布雷十个
4.排查雷
(1).如果位置是雷,被炸死。
(2).如果不是雷,就显示坐标周围有几个雷。
(3).所有雷找出,显示恭喜你排雷成功。
二、多文件实现扫雷游戏
本次扫雷游戏,我们通过多文件来实现,分别用三个文件:
1.test.c,本文件主要为了测试逻辑
2.game.c,本文件主要是为了游戏的实现
3.game.h,本文件主要是实现函数的声明
三、游戏的分析和设计
(一)游戏的分析
初级的扫雷我们要有一个扫雷的棋盘用来放雷,首先我们需要定义二维数组,来存放雷。其次我们需要让棋盘初始化的时候,是雷为1,不是雷为0。然后我们排雷的时候,如果这个位置不是雷的话,那我们就算这个坐标周围有几颗雷。这个时候就会存在冲突,假如选择的位置周围有一颗雷,那么输出1,这个1表示雷还有周围有一颗雷呢?
我认为可以用两个棋盘来存放,用mine数组来存放雷的位置,用show来存放周围雷的个数,我们可以用符号‘1‘,’0’存放在mine数组,符号*存放在show数组。
创建棋盘时,当我们计算周围雷个数时,当计算遇到边缘时,就可能会出现越界问题,那么我们可以创建一个11*11的棋盘,来解决越界问题。
即在头文件中可以如下处理:
#define ROW 9//9行
#define COL 9//9列
#define ROWS ROW+2//11行
#define COLS COL+2//11列
用ROW(行)和COL(列)表示会在后续使用中更方便,而不是一次性代码。
(二)游戏的设计
1.实现游戏界面,以及游戏的选择
我们可以用do while来实现主函数:
#include<stdio.h>
#include"game.h"
void menu()
{
printf("************************************\n");
printf("************请选择******************\n");
printf("***********1.进入游戏***************\n");
printf("***********0.退出游戏***************\n");
printf("************************************\n");
printf("************************************\n");
}
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();//游戏界面
scanf("%d", &input);
switch (input)
{
case 1:
printf("扫雷游戏");
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("输入有误,重新输入\n");
}
} while (input);
return 0;
}
do while可以实现先执行在判断,根据功能我们需要先进入游戏界面。我们利用menu函数,来打印界面,并且配合switch语句来选择是否进入扫雷游戏,如果我们输入不是0/1,那我们就重新输入,如果是1就进入游戏,如果是0就退出游戏。
2.游戏的具体设计
当我们选择1的时候,我们就会进入游戏,所以我们要在case 1:语句的时候定义game函数来调用具体的函数来实现扫雷游戏。
#include<stdio.h>
#include"game.h"
void game()
{
char mine[ROWS][COLS];//布局棋盘
char show[ROWS][COLS];//展示棋盘
InitBoard(mine,ROWS,COLS,'0');//初始化棋盘 全为0
InitBoard(show,ROWS,COLS,'*');//初始化棋盘 全为*
//打印棋盘
//DisplayBoard(mine,ROW,COL);//记录雷的个数
DisplayBoard(show,ROW, COL);//展示
//布雷
SetMine(mine,ROW,COL);
//DisplayBoard(mine, ROW, COL);//查看布雷结果
//排雷
FindMine(mine,show,ROW,COL);
}
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
printf("菜单");//不与上述内容重复
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("输入有误,重新输入\n");
}
} while (input);
return 0;
game函数的步骤为:①创建两个二维数组②初始化棋盘③打印棋盘④布雷⑤排查雷
3.在game.c中对游戏的具体实现
(1)初始化棋盘
我们用InitBoard函数定义初始化棋盘,我们要让mine棋盘全为‘0’;让show棋盘全为*。如何解决两个棋盘无法定义两种符号的情况呢?我们可以在函数调用时传入实参‘0’和 *,然后用形参set接收即可。注意:别忘记在头文件中声明InitBoard函数,一个函数的定义,一定要有函数的声明。
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
{//初始化棋盘:让两个棋盘全为0/*
for (int i = 0; i < ROWS; i++)
{
for (int j = 0; j < COLS; j++)
{
board[i][j] = set;//初始化好棋盘
}
}
(2)打印棋盘
我们用DisplayBoard函数来表示打印棋盘。注意:我们打印时,一定要打印9* 9的棋盘,因为我们最初设计时,就是9*9(初级难度),但是当我们定义传参时,要与当时创建数组的行列数相同,所以char board[ROWS][COLS]。
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
printf("---------扫雷游戏---------\n");
for (int j = 0; j <= row; j++)
{
printf("%d ", j);//列标
}
printf("\n");
for (int i = 1; i <= row; i++)
{
printf("%d ", i);//行号
for (int j = 1; j <= col; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
printf("---------扫雷游戏---------\n");
}
(3)布置雷的个数(10个)
我们用SetMine函数来布雷,注意我们布雷要在9*9棋盘内布雷。
void SetMine(char mine[ROWS][COLS],int row,int col)
{
int count = Easy_Count;
while (count)
{
//随机生成的行列布雷
int x = rand() % row + 1;
int y = rand() % col + 1;
if (mine[x][y] == '0')
{
mine[x][y] = '1';
count--;
}
}
}
因为布置雷的时候我们要在9*9的棋盘内,生成随机行列1-9的位置(为什么是1-9?因为从数组的下标来算,0行/0列与10列/10行,是我们防越界时设置的,所以不算在内),所以我们就需要rand函数来生成随机值,在使用rand函数时,我们要在主函数内先定义srand函数(srand函数只用一次,所以我们把它定义在主函数内):srand((unsigned int)time(NULL))。要包含头文件#include<time.h>与#include<stdlib.h>。
扩展:当我们要生成a-b的随机值时,我们可以用固定公式:a+rand()%(b-a+1)
(4)排雷
我们用Findmine函数来实现排雷,在mine数组中找雷,如果不是雷,那么我们计算出雷的个数传入show数组中。
int GetmineCount(char mine[ROWS][COLS],int x,int y)
{
return(mine[x - 1][y - 1] + mine[x - 1][y] + mine[x - 1][y + 1] +
mine[x][y - 1] + mine[x][y + 1] +
mine[x +1][y - 1] + mine[x + 1][y] + mine[x + 1][y + 1] - 8 * '0');
//'1'-'0'=1
//字符1-字符0=数字1,以此类推算出周围还有多少雷
}
void FindMine(char mine[ROWS][COLS],char show[ROWS][COLS], int row,int col)
{
int i = 0;//行
int j = 0;//列
int win = 0;
while (win<ROW*COL-Easy_Count)
{
scanf("%d%d", &i, &j);
if (show[i][j]!='*')
{
printf("重复输入,请重新输入");
scanf("%d%d", &i, &j);//防止输入相同数值
}
if (i > 1 && j > 1 && i <= row && j <= col)
{
//输入合法值
if (mine[i][j] == '1')
{
printf("你被炸死了\n");
DisplayBoard(mine, ROW, COL);//让我看布雷结果
break;
}
else
{
int count = GetmineCount(mine,i,j);//count需要返回一个数字
show[i][j]=count +'0';//例如:返回count为1,1+'0'=49
//'0'等于ASCII码48
//'1'等于ASCII码49
DisplayBoard(show, ROW, COL);
win++;
}
}
else
{
//不合法
printf("重新输入");
}
}
if (win == ROW * COL - Easy_Count)
{
printf("恭喜你,排雷成功!!");
DisplayBoard(mine, ROW, COL);
}
}
其中 GetmineCount函数的作用,计算我输入坐标的周围有几个雷。我们最开始用符号0和符号1来表示是否有雷,那么‘1’-‘0’=1,以此类推,来推算出我周围有多少个雷。例如: 返回count为数字1时,1+‘0’=49
'0’等于ASCII码48
'1’等于ASCII码49
四、扫雷游戏的扩展
1.是否可以选择游戏难度:简单9*9,困难16 *16,地狱30 *16
2.如果排查位置不是雷,周围也没有雷,可以展开周围的⼀⽚
3.是否可以标记雷
4.是否可以加上排雷的时间显⽰
五、代码总体预览
1.test.c
#include<stdio.h>
#include"game.h"
void menu()
{
printf("************************************\n");
printf("************请选择******************\n");
printf("***********1.进入游戏***************\n");
printf("***********0.退出游戏***************\n");
printf("************************************\n");
printf("************************************\n");
}
void game()
{
char mine[ROWS][COLS];//布局棋盘
char show[ROWS][COLS];//展示棋盘
InitBoard(mine,ROWS,COLS,'0');//初始化棋盘 全为0
InitBoard(show,ROWS,COLS,'*');//初始化棋盘 全为*
//打印棋盘
//DisplayBoard(mine,ROW,COL);//记录雷的个数
DisplayBoard(show,ROW, COL);//展示
//布雷
SetMine(mine,ROW,COL);
//DisplayBoard(mine, ROW, COL);//查看布雷结果
//排雷
FindMine(mine,show,ROW,COL);
}
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("输入有误,重新输入\n");
}
} while (input);
return 0;
}
2.game.c
#define _CRT_SECURE_NO_WARNINGS
#include"game.h"
//游戏实现
int GetmineCount(char mine[ROWS][COLS],int x,int y)
{
return(mine[x - 1][y - 1] + mine[x - 1][y] + mine[x - 1][y + 1] +
mine[x][y - 1] + mine[x][y + 1] +
mine[x +1][y - 1] + mine[x + 1][y] + mine[x + 1][y + 1] - 8 * '0');
//'1'-'0'=1
//字符1-字符0=数字1,以此类推算出周围还有多少雷
}
void FindMine(char mine[ROWS][COLS],char show[ROWS][COLS], int row,int col)
{
int i = 0;//行
int j = 0;//列
int win = 0;
while (win<ROW*COL-Easy_Count)
{
scanf("%d%d", &i, &j);
if (show[i][j]!='*')
{
printf("重复输入,请重新输入");
scanf("%d%d", &i, &j);//防止输入相同数值
}
if (i > 1 && j > 1 && i <= row && j <= col)
{
//输入合法值
if (mine[i][j] == '1')
{
printf("你被炸死了\n");
DisplayBoard(mine, ROW, COL);//让我看布雷结果
break;
}
else
{
int count = GetmineCount(mine,i,j);//count需要返回一个数字
show[i][j]=count +'0';
DisplayBoard(show, ROW, COL);
win++;
}
}
else
{
//不合法
printf("重新输入");
}
}
if (win == ROW * COL - Easy_Count)
{
printf("恭喜你,排雷成功!!");
DisplayBoard(mine, ROW, COL);
}
}
void SetMine(char mine[ROWS][COLS],int row,int col)
{
int count = Easy_Count;
while (count)
{
//随机生成的行列布雷
int x = rand() % row + 1;
int y = rand() % col + 1;
if (mine[x][y] == '0')
{
mine[x][y] = '1';
count--;
}
}
}
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
printf("---------扫雷游戏---------\n");
for (int j = 0; j <= row; j++)
{
printf("%d ", j);//列标
}
printf("\n");
for (int i = 1; i <= row; i++)
{
printf("%d ", i);//行号
for (int j = 1; j <= col; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
printf("---------扫雷游戏---------\n");
}
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
{//初始化棋盘:让两个棋盘全为0/*
for (int i = 0; i < ROWS; i++)
{
for (int j = 0; j < COLS; j++)
{
board[i][j] = set;//初始化好棋盘
}
}
}
3.game.h
#pragma once
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#define ROW 9//9行
#define COL 9//9列
#define ROWS ROW+2
#define COLS COL+2
#define Easy_Count 10//十个雷
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 mine[ROWS][COLS], int row, int col);
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
int GetmineCount(char mine[ROWS][COLS], int x, int y);