目录
一. 游戏所需的功能设计
二.步骤和代码
三.效果展示
一. 游戏所需的功能设计
1. 设计棋盘的大小范围,可以设计为10@10,也可以设计为16@16,需要用二维数组来打印棋盘;
2. 设计玩家棋盘,和设计者棋盘;
3. 设计避免刚开局就扫到雷的机会;
4. 设计输入坐标之后,展开周围的功能;
5. 设计统计坐标周围8个方位雷的个数;
6. 计算剩余总雷数,判断胜利与否;
7. 计算游戏从开始到结束的时间。
二. 步骤和代码
该程序需要三个文件,分别为创建主题文件的test.c, 存放头文件的game.h, 和游戏的实现文件game.c。
2.1 test.c文件(创建主题文件)
#include"game.h"
double start, finish;
void menu()
{
printf("****************************************\n");
printf("************** 1.Play ************\n");
printf("************** 0.Exit ************\n");
printf("****************************************\n");
}
void game()
{
int ret = 0;
init_mine();//初始化棋盘
set_mine();//布雷
print_mine();//打印设计者棋盘
printf("\n");
print_player();//打印玩家棋盘
start = clock();//游戏开始时间
safe_mine();//避免首开炸雷
if (count_show_mine() == COUNT)//如果开局就赢
{
print_mine();
printf("玩家赢了!\n");
return;
}
print_player();//打印玩家棋盘
while (1)//循环扫雷
{
int ret = sweep_mine();//扫到雷返回1,没扫到返回0
if(count_show_mine()==COUNT)//如果玩家获胜
{
print_mine();
printf("玩家赢了!\n");
finish = clock();//游戏结束时间
printf("用时%d秒\n", (int)(finish - start) / CLOCKS_PER_SEC);
break;
}
if (ret)//判断是否扫到雷了
{
printf("扫到雷了!\t");
finish = clock();//游戏结束时间
printf("用时%d秒\n", (int)(finish - start) / CLOCKS_PER_SEC);
print_mine();//打印设计者棋盘查看雷的分布
break;
}
print_player();//打印玩家棋盘
}
}
int main()
{
srand((unsigned int)time(NULL));//产生随机种子值
int input = 0;
menu();
do {
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("输入错误,请重新输入:>\n");
break;
}
} while (input);
return 0;
}
在该文件中设计了游戏从开始到结束的时间,以及一开局就胜利的机会。用safe_mine函数设置了避免开局就扫到雷的机会。
2.2 game.h (配置环境存放头文件)
在头文件中声明用到的函数。
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<time.h>
#define row 11
#define col 11
#define COUNT 10//雷的总数
char show_mine[row][col];//棋盘展示
char real_mine[row][col];//棋盘部署
void menu();//菜单
void init_mine();//初始化棋盘
void set_mine();//部署雷
int count_mine();//计算周围雷的个数
void print_player();//玩家棋盘
void print_mine();//设计者棋盘
int sweep_mine();//扫雷
void safe_mine();//避免开盘炸雷
void open_mine(int x, int y);//棋盘展开
int count_show_mine();//判断玩家棋盘剩余未知区域的个数
2.3 game.c (存放游戏的实现逻辑)
该游戏需要初始化两个棋盘:设计者棋盘,和玩家棋盘。在设计者棋盘中,字符0代表“非雷”,字符1代表“雷”。
#include"game.h"
void init_mine()//初始化设计者和玩家的棋盘
{
int i = 0;
int j = 0;
for (int i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
show_mine[i][j] = '*';
real_mine[i][j] = '0';
}
}
}
打印两个棋盘的时候,需要打印横坐标和纵坐标的序号(0-9),如下图:
void print_player()//打印玩家棋盘
{
int i = 0;
int j = 0;
printf("0 ");
for (i = 1; i < row - 1; i++)//打印横坐标0-9
{
printf("%d ", i);
}
printf("\n");
for (i = 1; i < row - 2; i++)//打印纵坐标0-9
{
printf("%d ", i);
for(j = 1; j < col - 1;j++)
{
printf("%c ", show_mine[i][j]);
}
printf("\n");
}
printf("9 ");//打印最后一行
for (i = 1; i < row - 1; i++)
{
printf("%c ", show_mine[9][i]);
}
printf("\n");
}
void print_mine()//打印设计者棋盘
{
int i = 0;
int j = 0;
printf("0 ");
for (i = 1; i < row - 1; i++)//打印横坐标0-9
{
printf("%d ", i);
}
printf("\n");
for (i = 1; i < row - 2; i++)//打印纵坐标0-9
{
printf("%d ", i);
for (j = 1; j < col - 1; j++)
{
printf("%c ", real_mine[i][j]);
}
printf("\n");
}
printf("9 ");//打印最后一行
for (i = 1; i < row - 1; i++)
{
printf("%c ", real_mine[9][i]);
}
printf("\n");
}
打印完两个棋盘和序号之后,开始布雷,用count 函数布置了10个雷,用rand函数让每一次的棋盘中的雷的分布都不同。
void set_mine()//设计者棋盘布雷
{
int x = 0;
int y = 0;
int count = COUNT;//雷的总数
while (count)
{
int x = rand() % 10 + 1;//随机横坐标0-9
int y = rand() % 10 + 1;//随机纵坐标0-9
if (real_mine[x][y] == '0')
{
real_mine[x][y] = '1';
count--;
}//所有雷布置完后跳出循环
}
}
int count_mine(int x, int y)//统计周围8个区域的雷的个数
{
int count = 0;
if (real_mine[x - 1][y - 1] == '1')
count++;
if (real_mine[x - 1][y] == '1')
count++;
if (real_mine[x - 1][y + 1] == '1')
count++;
if (real_mine[x][y - 1] == '1')
count++;
if (real_mine[x + 1][y - 1] == '1')
count++;
if (real_mine[x + 1][y] == '1')
count++;
if (real_mine[x + 1][y + 1] == '1')
count++;
return count;
}
为了避免一开局就点到雷,用safe_mine避免该情况的发生。
void safe_mine()//避免首开被炸
{
int x = 0;
int y = 0;
char ch = 0;
int count = 0;
int ret = 1;
printf("请输入坐标:>");
while (1)
{
scanf("%d %d", &x, &y);
if ((x >= 1 && x <= 10) && (y >= 1 && y <= 10))
{
if (real_mine[x][y] == '1')//如果首开扫到雷
{
real_mine[x][y] = '0';
char ch = count_mine(x, y);
show_mine[x][y] = ch + '0';
open_mine(x, y);
while (ret)//在周围设置雷
{
int x = rand() % 10 + 1;
int y = rand() % 10 + 1;
if (real_mine[x][y] == '0')//在没有雷的地方布雷
{
real_mine[x][y] = '1';
ret--;
break;
}
}break;
}
if (real_mine[x][y] == '0')
{
char ch = count_mine(x, y);
show_mine[x][y] = ch + '0';
open_mine(x, y);
break;
}
}
else
{
printf("输入错误,请重新输入:>");
}
}
}
如文章开头的图片那样,想要实现展开功能,使得展开的坐标显示其周围的雷的数量.
void open_mine(int x, int y)//展开坐标周围区域
{
if(real_mine[x - 1][y - 1] == '0')
{
show_mine[x - 1][y - 1] = count_mine(x - 1, y - 1) + '0';
}
if(real_mine[x - 1][y] == '0')
{
show_mine[x - 1][y] = count_mine(x - 1, y) + '0';
}
if(real_mine[x - 1][y + 1] == '0')
{
show_mine[x - 1][y + 1] = count_mine(x - 1, y + 1) + '0';
}
if(real_mine[x][y - 1] == '0')
{
show_mine[x][y - 1] = count_mine(x, y - 1) + '0';
}
if(real_mine[x][y + 1] == '0')
{
show_mine[x][y + 1] = count_mine(x, y + 1) + '0';
}
if(real_mine[x+1][y - 1] == '0')
{
show_mine[x + 1][y - 1] = count_mine(x + 1, y - 1) + '0';
}
if(real_mine[x + 1][y] == '0')
{
show_mine[x + 1][y] = count_mine(x + 1, y) + '0';
}
if(real_mine[x + 1][y + 1] == '0')
{
show_mine[x + 1][y + 1] = count_mine(x + 1, y + 1) + '0';
}
}
接下来,是扫雷函数的实现。
int sweep_mine()//扫雷函数
{
int x = 0;
int y = 0;
int count = 0;
printf("请输入坐标:>\n");
scanf("%d %d", &x, &y);//1-9
if ((x >= 1 && x <= 10) && (y >= 1 && y <= 10))
{
if (real_mine[x][y] == '0')//如果没有扫到雷
{
char ch = count_mine(x, y);
show_mine[x][y] = ch + '0';
open_mine(x, y);
if (count_show_mine() == COUNT)//判断未知区域坐标的个数
{
print_mine();
printf("玩家赢了!\n");
return 0;
}
}
else if (real_mine[x][y] == '1')//如果扫到雷了
{
return 1;
}
}
else
{
printf("输入错误,请重新输入:>");
}
return 0;
}
最后,是实现游戏胜利的函数,通过统计玩家棋盘中剩余坐标的个数和雷的总数来判断,如果剩余坐标的个数和雷的总数一致,则游戏胜利。
int count_show_mine()//判断未知区域坐标雷的个数
{
int count = 0;
int i = 0;
int j = 0;
for (i = 1; i <= row - 2; i++)
{
for (j = 1; j <= row - 2; j++)
{
if (show_mine[i][j] == '*')
{
count++;
}
}
}
return count;
}
三.效果展示