目录
一.创建项目
首先我们创建项目准备一个头文件game.h用来做函数的声明,一个源文件game.c用来写函数,最后用一个源文件main.c来作主函数的运行。
需要在game.c和text.c中包含一下头文件,要注意自己写的头文件要用双引号引用如下:
二.菜单制作
game函数:
1.游戏的页面设计
我们可以想象做以下这样一个页面,让玩家输入坐标来排雷。
2.游戏规则
(1).输入坐标位置是雷,游戏失败。
(2).如果不是雷,则在该位置标记出周围一圈雷的个数,玩家继续输入。
(3).如果不是雷,而且周围一圈都没有雷(即显示数字0),那么,将显示周围一片周围雷数都为0的区域,只到遇到非零。
(4).当排除所有不是雷的地方(即只剩下有雷的地方未显示)游戏胜利。
三.棋盘制作以及初始化
我们需要制作3个棋盘
第一个棋盘用来布置雷(数组a[rs][cs])
第二个棋盘用来呈现给玩家看(数组b[rs][cs])
第三个棋盘用来储存每个坐标周围雷的个数(数组e[rs][cs])
1.棋盘初始化
因为考虑到计算每个坐标周围雷数的时候可能会发生数组越界,所以我们要制作一个9*9,10个雷的扫雷游戏时,实际我们需要做一个(9+2)*(9+2)的棋盘格,而只用给玩家显示9*9的棋盘。其中多加的两行两列只是为了防止数组越界,不必布置雷。
我们用a,b,e三个二级指针来模拟三个二维数组
a矩阵来布置雷,b矩阵用来呈现给用户看,e矩阵来储存每个个坐标周围雷的个数
rs,cs,L分别表示雷区的长宽和雷的个数
写一个二级指针模拟二维数组的函数relc
2.模式设置
Sleep函数可以实现睡眠,Sleep(600)表示睡眠600毫秒用这样一个函数可以增加游戏效果,然后我们可以写一个color函数来设置控制台颜色入下:
#include<stdio.h>
#include<Windows.h>
#include<stdlib.h>
void color(int k)
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), k);
}
int main()
{
for (int i = 1; i <= 255; i++)
{
color(i);
printf("%3d ", i);
if (i%15==0)
printf("\n");
}
color(15);
return 0;
}
上面代码的输出结果如下:
游戏的模式设置:
color(6);
printf("请选择模式>>\n");
color(15);
Sleep(600);
printf("******** "); color(2); printf("@&*******************&@"); color(15); printf(" ********\n"); Sleep(100);
printf("**********"); color(11); printf("1.基础 < 9 * 9 >"); color(15); printf("***********\n"); Sleep(100);
printf("**********"); color(9); printf("2.简单 < 16 * 16 > "); color(15); printf("***********\n"); Sleep(100);
printf("**********"); color(13); printf("3.困难 < 16 * 30 > "); color(15); printf("***********\n"); Sleep(100);
printf("**********"); color(4); printf("4.极限 < 36 * 50 > "); color(15); printf("***********\n"); Sleep(100);
printf("**********"); color(14); printf("5.自定义 < ? * ?>"); color(15); printf("************\n"); Sleep(100);
printf("******* "); color(2); printf(">+$*******************$+<"); color(15); printf(" *******\n"); Sleep(100);
k = 0;
int p = 0;
int u = 0;
char** a=NULL, **b=NULL, **e=NULL;
int rs = 0, cs = 0, L = 0;
int w;
while (scanf("%d", &w),w < 1 || w>5)
{
color(4);
printf("输入错误,请输入1,2,3,4或5\n");
color(6);
printf("请选择模式>>\n");
color(15);
}
switch (w)
{
case 1:
rs = 11, cs = 11, L = 10;
break;
case 2:
rs = 18,cs = 18,L = 40;
break;
case 3:
rs = 18,cs = 32,L = 99;
break;
case 4:
rs = 38,cs = 52,L = 140;
break;
case 5:
printf("请输入雷区的长>>\n");
scanf("%d", &k);
printf("请输入雷区的宽>>\n");
scanf("%d", &u);
printf("雷区中雷的个数>>\n");
scanf("%d", &p);
cs = k + 2,rs = u + 2,L = p;
break;
default:
perror("w_error");
return;
}
效果如下:
使用刚才写的relc函数中创建棋盘
kkk,le,uuu这些函数可以写在game.c中,但要在game.h中声明。
如下:
3.布置雷
一个位置要么是雷要么不是,只有两种情况,那么我们就可以用字符 ' 1 ' 表示雷,字符 ' 0 ' 表示没有雷,(这里用字符而不用数字的原因是为了与 ' * ' 保持一致方便后续操作)。
布雷是随机的,所以就要用到一个随机数,这里需要包含头文件<stdlib.h>和<time.h>
4.计算坐标周围雷数
这里我们要知道到 ' 1 ' + ' 1 '并不等于 ' 2 ',字符本身不能相加减,相加减的是它们的Ascll值。
所以我们计算周围雷数的时候用以下操作:
四.屏幕输出设计
1.棋盘输出函数
为了增加用户的体验感,我们可以添加一些颜色,做这样一个输出函数。
效果如下:
2.屏幕呈现状态
玩家输入坐标后用数组a[rs][cs]判断是否为雷(即是否是 ' 1 ')如果是则游戏失败并显示给玩家雷区信息(及棋盘a[rs][cs])。如果不是则把e[rs][cs] (即周围一圈雷的个数)赋值给对应位置的数组b[rs][cs],该过程通过Fo函数递归实现,即下面第3点递归扫雷,最后把数组b[rs][cs]呈现(输出函数实现)给玩家。
3.递归扫雷
如果用户输入坐标位置不是雷,而且周围一圈都没有雷(即显示数字0),那么,将显示周围一片周围雷数都为0的区域,直到遇到非零。
4.游戏结束的条件
玩家是需要多次输入的所以需要一个循环,直到游戏成功或失败时退出循环。
(1)游戏失败退出游戏我们可以在循环中设置一个break语句。
(2)游戏成功退出游戏我们可以写一个函数(muu函数)来计算剩余 ' * ' 的个数,如果为10则退出循环且呈现游戏胜利。
5.清屏处理
为了方便玩家观看我们可以把上一次输出的结果清除后再进行输出。用到一个system函数。
五.原码:
1.头文件game.h
#pragma once
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#include<windows.h>
//棋盘初a,b始化
void kkk(char** a, int n, int m, char f);
//输出棋盘
void print(char** a,int r,int c);
//布置雷区
void le(char** a,int L,int r,int c);
//排查雷区个数
int count(char* a, int m, int n);
//玩家输入
void nnn(char** a, char** b, char** e,int r,int c,int L);
//棋盘c_周围雷数
void uuu(char** a, char** u,int r,int c);
//递归扫雷
void Fo(char** e, char** b, int m, int n,int r,int c);
2.源文件game.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h";
void kkk(char** a, int n, int m, char f)
{
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
a[i][j] = f;
}
}
}
void color(int k)
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), k);
}
void print(char** a, int r, int c)
{
for (int i = 0; i < c - 4; i++)
{
printf(" ");
}
color(48);
printf(" >.p..*-扫雷-*..q.<\n");
for (int i = 0; i <= c; i++)
{
color(14);
printf("%2d ", i);
}
printf("\n");
for (int i = 1; i <= r; i++)
{
color(14);
printf("%2d ", i);
for (int j = 1; j <= c; j++)
{
switch (a[i][j])
{
case '*':
color(2);
printf("%2c ", a[i][j]);
break;
case '0':
color(7);
printf("%2c ", a[i][j]);
break;
case '1':
color(3);
printf("%2c ", a[i][j]);
break;
case '2':
color(12);
printf("%2c ", a[i][j]);
break;
case '3':
color(4);
printf("%2c ", a[i][j]);
break;
default:
color(6);
printf("%2c ", a[i][j]);
break;
}
}
printf("\n");
}
}
void le(char** a, int L, int r, int c)//布雷
{
srand((unsigned int)time(NULL));
for (int i = 1; i <= L; i++)
{
int x = rand() % r + 1;
int y = rand() % c + 1;
if (a[x][y] == '1')
{
i--;
continue;
}
a[x][y] = '1';
}
}
int count(char** a, int m, int n)
{
int u = 0;
for (int i = m - 1; i <= m + 1; i++)
{
for (int j = n - 1; j <= n + 1; j++)
{
u += a[i][j] - '0';
}
}
return u;
}
//
int muu(char** b, int rs, int cs)
{
int a = 0;
for (int i = 1; i <= rs-2; i++)
{
for (int j = 1; j <= cs-2; j++)
{
if (b[i][j] == '*')
{
a++;
}
}
}
return a;
}
//
void nnn(char** a, char** b, char** e, int r, int c,int L)
{
while (muu(b,r+2,c+2) != L)
{
int n, m;
color(12);
printf("请输入坐标>>\n");
scanf("%d%d", &n, &m);
if (!(n <= r && n > 0 && m > 0 && m <= c))
{
printf("输入错误,请重新输入\n");
}
else
{
if (a[n][m] == '1')
{
printf("很遗憾你被炸死了\n");
print(a,r,c);
system("color 04");
color(7);
break;
}
else
{
system("cls");
Fo(e, b, n, m,r,c);
print(b,r,c);
}
}
}
if (muu(b,r+2,c+2) == L)
{
color(4);
printf("!!恭喜你通过游戏!!\n");
color(15);
}
}
void uuu(char** a, char** u, int r, int c)
{
for (int i = 1; i <= r; i++)
{
for (int j = 1; j <= c; j++)
{
u[i][j] = count(a, i, j) + '0';
}
}
}
void Fo(char** e, char** b, int n, int m, int r, int c)
{
if (n > r || n < 1 || m > c || m < 1)
{
return;
}
if (b[n][m] != '*')
{
return;
}
b[n][m] = e[n][m];
if (e[n][m] == '0')
{
Fo(e, b, n + 1, m, r, c);
Fo(e, b, n - 1, m, r, c);
Fo(e, b, n, m + 1, r, c);
Fo(e, b, n, m - 1, r, c);
Fo(e, b, n + 1, m + 1, r, c);
Fo(e, b, n - 1, m - 1, r, c);
Fo(e, b, n + 1, m - 1, r, c);
Fo(e, b, n - 1, m + 1, r, c);
}
else
{
return;
}
}
3.源文件main.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
#include<assert.h>
#include<stdio.h>
char** relc(char** a,int rs,int cs)
{
a = (char**)malloc(sizeof(char*) * rs);
assert(a);
for (int i = 0; i < rs; i++)
{
a[i] = (char*)malloc(sizeof(a[0][0]) * cs);
assert(a[i]);
}
return a;
}
void menu()
{
while (1)
{
printf("*************扫雷游戏**************\n");
printf("***********************************\n");
printf("************* 1.play **************\n");
printf("************* 0.exit **************\n");
printf("***********************************\n");
printf("请选择->>:\n");
char k;
scanf("%c", &k);
if (k == '0')
{
printf("游戏已退出");
return;
}
while(k!='1')
{
color(4);
printf("输入错误,请选择0或1\n");
color(15);
printf("请选择->>:\n");
scanf("%c", &k);
color(15);
}
color(6);
printf("请选择模式>>\n");
color(15);
Sleep(600);
printf("******** "); color(2); printf("@&*******************&@"); color(15); printf(" ********\n"); Sleep(100);
printf("**********"); color(11); printf("1.基础 < 9 * 9 >"); color(15); printf("***********\n"); Sleep(100);
printf("**********"); color(9); printf("2.简单 < 16 * 16 > "); color(15); printf("***********\n"); Sleep(100);
printf("**********"); color(13); printf("3.困难 < 16 * 30 > "); color(15); printf("***********\n"); Sleep(100);
printf("**********"); color(4); printf("4.极限 < 36 * 50 > "); color(15); printf("***********\n"); Sleep(100);
printf("**********"); color(14); printf("5.自定义 < ? * ?>"); color(15); printf("************\n"); Sleep(100);
printf("******* "); color(2); printf(">+$*******************$+<"); color(15); printf(" *******\n"); Sleep(100);
k = 0;
int p = 0;
int u = 0;
char** a=NULL, **b=NULL, **e=NULL;
int rs = 0, cs = 0, L = 0;
int w;
while (scanf("%d", &w),w < 1 || w>5)
{
color(4);
printf("输入错误,请输入1,2,3,4或5\n");
color(6);
printf("请选择模式>>\n");
color(15);
}
switch (w)
{
case 1:
rs = 11, cs = 11, L = 10;
break;
case 2:
rs = 18,cs = 18,L = 40;
break;
case 3:
rs = 18,cs = 32,L = 99;
break;
case 4:
rs = 38,cs = 52,L = 140;
break;
case 5:
printf("请输入雷区的长>>\n");
scanf("%d", &k);
printf("请输入雷区的宽>>\n");
scanf("%d", &u);
printf("雷区中雷的个数>>\n");
scanf("%d", &p);
cs = k + 2,rs = u + 2,L = p;
break;
default:
perror("w_error");
return;
}
a = relc(a, rs, cs);//申请空间
b = relc(b, rs, cs);//......
e = relc(e, rs, cs);//......
kkk(a, rs, cs, '0');//kkk函数把矩阵a初始化为全'0'
kkk(b, rs, cs, '*');//把矩阵a初始化为全'*'
le(a,L,rs-2,cs-2);//在矩阵a中布置L个雷
uuu(a, e, rs - 2, cs - 2);//计算每个坐标周围雷的个数并存入e中
system("cls");
if (w == '4')
{
color(12);
printf(" 展开全屏效果更佳哦!\n");
}
for (int i = 0; i <= cs-2; i++)
{
color(14);
printf("%2d ", i);
}
printf("\n");
for (int i = 1; i <= rs-2; i++)
{
color(14);
Sleep(10);
printf("%2d ", i);
for (int j = 1; j <= cs-2; j++)
{
color(2);
Sleep(10);
printf("%2c ", b[i][j]);
}
printf("\n");
}
nnn(a, b, e,rs-2,cs-2,L);
}
}
int main()
{
menu();
return 0;
}