扫雷
菜单
比较简单,代码如下
void menu()
{
printf("*******************\n");
printf("**** 1. play ****\n");
printf("**** 0. exit ****\n");
printf("*******************\n");
}
效果如图
然后就是根据不同的输入来执行不同的程序,这里用到了switch函数,也比较简单,如果想让这个游戏可以一直玩的话,我们再加上一个循环,这里用了do_while循环
do
{
menu();
int input = 0;
printf("请输入选项\n");
scanf("%d", &input);
switch (input)
{
case 1:
printf("开始扫雷\n");
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("请重新选择\n");
break;
}
} while (input);
}
以上的都比较简单,重点是里面game()的实现,对于初学者来说可能有一点难。
对于这个扫雷呢,我们的思路是设置两个棋盘,一个棋盘用来布置雷,也就是存放雷的信息,而另一个棋盘则用来展示给玩家看,也就是展示排查出来雷的信息,于是我们定义这样的两个棋盘。
char mine[ROWS][COLS] = { 0 };//布置好的雷的信息
char show[ROWS][COLS] = { 0 };//排查出的雷的信息
假设这是一个9*9的棋盘我们在头文件里面声明ROW和COL
#define ROW 9
#define COL 9
注意上面我们定义棋盘的时候用的不是ROW和COL,而是ROWS和COLS,这是因为我们在排查雷到边界点的时候,再往外排查啊会出现下标越界的情况,于是我们上下各加一行,左右各加一列,于是就变成了1111,也就是ROW+2COL+2,于是我们接着在头文件中定义
#define ROWS ROW+2
#define COLS COL+2
代码实现
初始化棋盘
定义好棋盘后我们就要对它进行初始化,如图
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set);//初始化棋盘
因为我们对两个棋盘进行初始化的值不一样,所有在形参的后面加了一个返回值set,我们这里将mine棋盘初始化为’0’,将show棋盘初始化为’*’
InitBoard(mine, ROWS, COLS, '0');
InitBoard(show, ROWS, COLS, '*');
接下来就是这个函数的代码实现了,比较简单
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
{
int i = 0;
for (i = 0; i < rows; i++)
{
int j = 0;
for (j = 0; j < cols; j++)
{
board[i][j] = set;
}
}
}
打印棋盘
将棋盘进行初始化之后我们可以来打印棋盘出来看看,看是否初始化成功,函数声明如下
void PrintBoard(char board[ROWS][COLS], int row, int col);//打印棋盘
这里看起来复杂,其实比较简单,就是利用循环打印数组里的元素,这里为了方便玩家看清还在棋盘的侧面加上了坐标
void PrintBoard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
printf("--------扫雷-------\n");
//控制列号
for (j = 0; j <= col; j++)
{
printf("%d ", j);
}
printf("\n");
for (i = 1; i <= row; i++)
{
printf("%d ", i);
for (j = 1; j <= col; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
}
效果如下
注意在玩的时候第二个棋盘是玩家看不到的,也就是不打印的。
出现这样的界面就说明我们的棋盘已经初始化成功并且能够打印棋盘了
布置雷
接下来我们就要在第一个棋盘上存放雷的信息了
函数声明如下
void SetMine(char mine[ROWS][COLS], int row, int col);//布置雷
首先我们假设一个简单的难度,有10个雷,这个可以自己去调节
#define EASY_COUNT 10
那么思路是什么呢?
首先我们还是要利用rand()函数来生成合法的随机下标,然后就是每生成一个雷后这个雷的数量减一,直到变成0,这样就布置好了10个雷
void SetMine(char mine[ROWS][COLS], int row, int col)
{
int count = EASY_COUNT;
while (count)
{
//1.生成随机下标
int x = rand() % row + 1;//对生成的随机数进行限制
int y = rand() % col + 1;
//2.布置雷
if (mine[x][y] == '0')
//若该位置没有布置过雷,则在该位置布雷
{
mine[x][y] = '1';
count--;
}
}
}
写好之后我们可以来打印看看
可以看到棋盘上出现了10个1,也就说明成功地布置了10个雷
排除雷
声明和之前都比较类似
void FineMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);//排除雷
而对于排雷的过程的思路是在玩家随机输入一个排雷坐标后,若该地方没有雷,则显示周围八个格子内雷的数目,若该地方已被排查过,则提示,若该地方为雷,则提示游戏结束
所以在这个函数实现之前我们需要定义一个函数来返回周围八个格子雷的总数的函数,假设玩家输入的坐标为x,y,则其周围八个格子的坐标可以找到
int get_mine_count(char mine[ROWS][COLS], int x, int y)
{
return mine[x - 1][y] + mine[x - 1][y - 1] + mine[x][y - 1]
+ mine[x + 1][y - 1] + mine[x + 1][y] + mine[x + 1][y + 1]
+ mine[x][y + 1] + mine[x - 1][y - 1] - 8 * '0';
}
这里的-8 * ‘0’是因为棋盘中存放的雷都是以字符1的形式来存放的,假设该位置周围有两个雷,即两个’1’,那么该位置显示的数就是2*‘1’+6*‘0’-8*‘0’,也就是2
再根据上面排雷的思路,我们可以大概写出部分代码的实现
void FineMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
printf("请输入要排查的坐标");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)//越界检查
{
if (show[x][y] != '*')
{
printf("该坐标被排查过");
continue;
}
if (mine[x][y] == '1')
{
printf("很遗憾,踩到雷了\n");
PrintBoard(mine, ROW, COL);
break;
}
else
{
int n = get_mine_count(mine, x, y);
show[x][y] = n + '0';
PrintBoard(show, ROW, COL);
}
}
else
{
printf("坐标错误,请重新输入\n");
}
}
这里的show[x][y] = n + '0';
的意思是把周围的雷的数目返回到show[x][y],但是我们在屏幕上显示的是字符2而不是数字2,但这个函数返回的数字2,十一我们要想办法把数字2变成字符2,由ASCII表可知也就是加上48,即加上一个字符0就可以了
而当雷都排完也就是十个雷都找完后的时候游戏就结束了,我们可以定义一个win,每找到一个雷win就加一,一直加到对于我们对应的难度后游戏结束,所以我们可以对以上代码进行补充
void FineMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int win = 0;
while (win < (row * col - EASY_COUNT))
{
printf("请输入要排查的坐标");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (show[x][y] != '*')
{
printf("该坐标被排查过");
continue;
}
if (mine[x][y] == '1')
{
printf("很遗憾,踩到雷了\n");
PrintBoard(mine, ROW, COL);
break;
}
else
{
int n = get_mine_count(mine, x, y);
show[x][y] = n + '0';
PrintBoard(show, ROW, COL);
win++;
}
}
else
{
printf("坐标错误,请重新输入\n");
}
}
if (win == (row * col - EASY_COUNT))
{
printf("恭喜你,排雷成功\n");
}
}
到这里的话游戏就可以玩了,不好的地方是需要一个个去排雷,不能展开没有雷的地方,要想达到这个效果就得用到递归的思想了。
下面是运行截图(破解版)
全部代码
game.h
#define _CRT_SECURE_NO_WARNINGS 1
#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 EASY_COUNT 10
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set);//初始化棋盘
void PrintBoard(char board[ROWS][COLS], int row, int col);//打印棋盘
void SetMine(char mine[ROWS][COLS], int row, int col);//布置雷
void FineMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);//排除雷
game.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
{
int i = 0;
for (i = 0; i < rows; i++)
{
int j = 0;
for (j = 0; j < cols; j++)
{
board[i][j] = set;
}
}
}
void PrintBoard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
printf("--------扫雷-------\n");
//控制列号
for (j = 0; j <= col; j++)
{
printf("%d ", j);
}
printf("\n");
for (i = 1; i <= row; i++)
{
printf("%d ", i);
for (j = 1; j <= col; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
}
void SetMine(char mine[ROWS][COLS], int row, int col)
{
int count = EASY_COUNT;
while (count)
{
int x = rand() % row + 1;//1-9
int y = rand() % col + 1;
if (mine[x][y] == '0')
{
mine[x][y] = '1';
count--;
}
}
}
int get_mine_count(char mine[ROWS][COLS], int x, int y)
{
return mine[x - 1][y] + mine[x - 1][y - 1] + mine[x][y - 1]
+ mine[x + 1][y - 1] + mine[x + 1][y] + mine[x + 1][y + 1]
+ mine[x][y + 1] + mine[x - 1][y - 1] - 8 * '0';
}
void FineMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int win = 0;
while (win < (row * col - EASY_COUNT))
{
printf("请输入要排查的坐标");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (show[x][y] != '*')
{
printf("该坐标被排查过");
continue;
}
if (mine[x][y] == '1')
{
printf("很遗憾,踩到雷了\n");
PrintBoard(mine, ROW, COL);
break;
}
else
{
int n = get_mine_count(mine, x, y);
show[x][y] = n + '0';
PrintBoard(show, ROW, COL);
win++;
}
}
else
{
printf("坐标错误,请重新输入\n");
}
}
if (win == (row * col - EASY_COUNT))
{
printf("恭喜你,排雷成功\n");
}
}
text.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void menu()
{
printf("*******************\n");
printf("**** 1. play ****\n");
printf("**** 0. exit ****\n");
printf("*******************\n");
}
void game()
{
char mine[ROWS][COLS] = { 0 };
char show[ROWS][COLS] = { 0 };
InitBoard(mine, ROWS, COLS, '0');
InitBoard(show, ROWS, COLS, '*');
PrintBoard(show, ROW, COL);
SetMine(mine, ROW, COL);
PrintBoard(mine, ROW, COL);
FineMine(mine, show, ROW, COL);
}
void test()
{
srand((unsigned int)time(NULL));
int input = 0;
do
{
menu();
int input = 0;
printf("请输入选项\n");
scanf("%d", &input);
switch (input)
{
case 1:
printf("开始扫雷\n");
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("请重新选择\n");
break;
}
} while (input);
}
int main()
{
test();
return 0;
}