扫雷游戏的开发主要运用二维数组,对初学者巩固基础,增加学习的兴趣有很大帮助(其实是作者玩不赢99个雷,制作的可以“抄答案”的小游戏(╯°□°)╯︵ ┻━┻)
前言
扫雷是一款经典的游戏,百玩不腻。从15个雷到99个雷,各种模式非常好玩。但是想要挑战更高难度的关卡怎么办??本程序可以满足你的一切要求!本程序中格子的数目,大小用的宏定义,可以一键修改,雷的数量在命令提示符中输入,完美解决友友们对地狱级难度的追求!!!
整体架构流程
众周所知,C语言程序是由一个个函数组成的程序。所以,我们要将扫雷的各种功能写成函数。
由浅到深来说,它应该有一个和格子一样规格的矩阵,矩阵中有雷和数字。在我的这个程序中,我把负数设为雷,正数就是表示该格子周围雷的数目。
然后我们实现翻开功能,其实就是显示功能。把点的那个地方对应矩阵(二维数组)中的数字展示出来,用if语句判断一下,如果大于0,就显示那个数字,如果小于0,就显示“雷”。
再然后是插旗功能,因为插旗之后还要能取消,所以这里又弄了一个相同的数组代表插旗。同时,插旗后代表雷和数字的矩阵的数字会乘以-1,这个操作有利于我们实现输赢的判断。
(有一处有点坑,就是插旗后也能点开,如果是雷插旗后点开会是一个没有意义的数字,如果不是雷,插旗后点开就会变成雷。以下代码中作者用/*代码*/注释并加以说明了,我觉得这个挺好玩大家喜欢的话留言,如果想玩这种以后出个万宁版的扫雷<( ̄︶ ̄)↗[GO!])
技术名词解释
写程序时,先写所需要的头文件。头文件可以理解为别人写好的函数库的名称,你在程序开头写上这个名称,程序就能找到这个函数库,在下面的程序中你就可以用这些函数。比如printf()函数。
在本程序里我们的扫雷是在另外开的窗口中进行的,所以我们要引用头文件windows.h。然后我们弄得窗口需要头文件easyx.h,这个头文件可能会有人没有下载,搜索“easyx.h下载”跟着教程下载即可。
#define是宏定义,意思就是后边那个完全等价与前面那个,跟代号一样。例如#define A 1 之后在这个程序里面所有的A都表示4。这样写方便进行整体更改。
MOUSEMSG是一个结构体名,主要是用来获取鼠标信息的。MOUSEMSG相当于int char之类,只不过在后边的变量拥有下图{}里面的所有变量。这里涉及不多,作者也不怎么会解释,不太理解对下面程序的编写影响不大。
代码展示与解说
引用头文件
#include <stdio.h>
#include <windows.h>//窗口
#include <graphics.h>
#include <easyx.h>//图形库
#include <stdlib.h>
#include <time.h>//以时间为种子产生随机数
进行宏定义和结构体变量定义
作者英语水平不怎么样😢大家如果觉得Wide和Key看着不带劲可以改,但是下面每一处WideheKey都要改(●'◡'●)。这里宏定义后,Wide就完全等于15。m是随便起的一个变量,主要就是获得鼠标的位置。
#define Wide 15//格子的数量是Wide*Wide
#define Key 40//每一格的大小是Key(40)像素点
MOUSEMSG m;//变量名为m的结构体
定义两个数组
第一个是来表示雷和数字的,第二个是表示插旗的。这里就可以用Wide了,就相当于15。
int chess_board[Wide][Wide] = {0};
int chess_flag[Wide][Wide] = {0};
画格子函数
因为我们不加载图片,所以一个一个格子我们要画出来,用画线函数。
void draw_line()
{
setlinecolor(BLACK);
int i = 0;
for (i; i <= Wide; i++)
{
line(50 + Key * i, 50, 50 + Key * i, 50+Key*Wide);//竖线
line(50, 50 + Key * i, 50 + Key * Wide, 50 + Key * i);//横线
}
}
随机产生雷
这个是扫雷游戏的核心,代码看着有些长,其实都是重复的操作。
主要原理就是传入生成雷的数量Num,然后在随机的格子里面产生雷(同时判断该格子是不是空的),负数是雷,-9是为了防止周围都是雷把它变成正数。再然后就是将该雷周围格子数加一,分了三种情况所以代码比较长。
void rand_lei(int Num)
{
int x, y;
while (Num)
{
x = rand() % Wide;//产生随机数
y = rand() % Wide;
if (chess_board[y][x] == 0)
{
*(&chess_board[y][x]) = -9;
Num--;
}
}
for (x = 1; x < Wide-1; x++)
{
for (y = 1; y < Wide-1; y++)
{
if (chess_board[x][y] < 0)
{
*(&chess_board[x - 1][y - 1]) = chess_board[x - 1][y - 1] + 1;
*(&chess_board[x - 1][y]) = chess_board[x - 1][y] + 1;
*(&chess_board[x - 1][y + 1]) = chess_board[x - 1][y + 1] + 1;
*(&chess_board[x + 1][y - 1]) = chess_board[x + 1][y - 1] + 1;
*(&chess_board[x + 1][y]) = chess_board[x + 1][y] + 1;
*(&chess_board[x + 1][y + 1]) = chess_board[x + 1][y + 1] + 1;
*(&chess_board[x][y - 1]) = chess_board[x][y - 1] + 1;
*(&chess_board[x][y + 1]) = chess_board[x][y + 1] + 1;
}
}
if (chess_board[0][x] < 0)
{
*(&chess_board[0][x - 1]) = chess_board[0][x - 1] + 1;
*(&chess_board[0][x + 1]) = chess_board[0][x + 1] + 1;
*(&chess_board[1][x + 1]) = chess_board[1][x + 1] + 1;
*(&chess_board[1][x - 1]) = chess_board[1][x - 1] + 1;
*(&chess_board[1][x]) = chess_board[1][x] + 1;
}
if (chess_board[Wide-1][x] < 0)
{
*(&chess_board[Wide - 1][x - 1]) = chess_board[Wide - 1][x - 1] + 1;
*(&chess_board[Wide - 1][x + 1]) = chess_board[Wide - 1][x + 1] + 1;
*(&chess_board[Wide - 2][x + 1]) = chess_board[Wide - 2][x + 1] + 1;
*(&chess_board[Wide - 2][x - 1]) = chess_board[Wide - 2][x - 1] + 1;
*(&chess_board[Wide - 2][x]) = chess_board[Wide - 2][x] + 1;
}
if (chess_board[x][0] < 0)
{
*(&chess_board[x + 1][0]) = chess_board[x + 1][0] + 1;
*(&chess_board[x + 1][1]) = chess_board[x + 1][1] + 1;
*(&chess_board[x][1]) = chess_board[x][1] + 1;
*(&chess_board[x - 1][0]) = chess_board[x - 1][0] + 1;
*(&chess_board[x - 1][1]) = chess_board[x - 1][1] + 1;
}
if (chess_board[x][Wide - 1] < 0)
{
*(&chess_board[x + 1][Wide - 1]) = chess_board[x + 1][Wide - 1] + 1;
*(&chess_board[x + 1][Wide - 2]) = chess_board[x + 1][Wide - 2] + 1;
*(&chess_board[x][Wide - 2]) = chess_board[x][Wide - 2] + 1;
*(&chess_board[x - 1][Wide - 1]) = chess_board[x - 1][Wide - 1] + 1;
*(&chess_board[x - 1][Wide - 2]) = chess_board[x - 1][Wide - 2] + 1;
}
if (chess_board[0][0] < 0)
{
*(&chess_board[0][1]) = chess_board[0][1] + 1;
*(&chess_board[1][1]) = chess_board[1][1] + 1;
*(&chess_board[1][0]) = chess_board[1][0] + 1;
}
if (chess_board[Wide-1][0] < 0)
{
*(&chess_board[Wide-1][1]) = chess_board[Wide-1][1] + 1;
*(&chess_board[Wide-2][1]) = chess_board[Wide-2][1] + 1;
*(&chess_board[Wide-2][0]) = chess_board[Wide-2][0] + 1;
}
if (chess_board[0][Wide-1] < 0)
{
*(&chess_board[0][Wide-2]) = chess_board[0][Wide-2] + 1;
*(&chess_board[1][Wide-1]) = chess_board[1][Wide-1] + 1;
*(&chess_board[1][Wide-2]) = chess_board[1][Wide-2] + 1;
}
if (chess_board[Wide-1][Wide-1] < 0)
{
*(&chess_board[Wide-1][Wide-2]) = chess_board[Wide-1][Wide-2] + 1;
*(&chess_board[Wide-2][Wide-2]) = chess_board[Wide-2][Wide-2] + 1;
*(&chess_board[Wide-2][Wide-1]) = chess_board[Wide-2][Wide-1] + 1;
}
}
}
展示点开结果
因为数字没法像文字一样显示上去,所以这里我又写了一个函数显示数字,用switch语句选择,传入三个参数,两个是位置一个是数字。
void show_num(int n,int x,int y)
{
settextcolor(BLUE);
settextstyle(Key - 2, 0, _T("楷书"));
outtextxy(51 + Key * x, 51 + Key * y, _T(" "));
switch (n)
{
case 9:outtextxy(51 + Key * x, 51 + Key * y, _T(" ")); break;
case 1:outtextxy(50 + Key / 3 + Key * x, 51 + Key * y, _T("1")); break;
case 2:outtextxy(50 + Key / 3 + Key * x, 51 + Key * y, _T("2")); break;
case 3:outtextxy(50 + Key / 3 + Key * x, 51 + Key * y, _T("3")); break;
case 4:outtextxy(50 + Key / 3 + Key * x, 51 + Key * y, _T("4")); break;
case 5:outtextxy(50 + Key / 3 + Key * x, 51 + Key * y, _T("5")); break;
case 6:outtextxy(50 + Key / 3 + Key * x, 51 + Key * y, _T("6")); break;
case 7:outtextxy(50 + Key / 3 + Key * x, 51 + Key * y, _T("7")); break;
case 8:outtextxy(50 + Key / 3 + Key * x, 51 + Key * y, _T("8")); break;
}
}
下面这个是展示翻开结果的。这个函数因为点开雷直接失败所以有返回值。下面就是判断数组里面的数字是几,其他都没有什么。但如果是0,就需要将它周围格子都翻开。
int turn_chess(int x, int y)
{
if (y < 0 || x < 0 || x >(Wide - 1) || y >(Wide - 1))
return 0;
if (chess_board[y][x] < 0&&chess_flag[y][x]%2==0)//把&&chess_flag[y][x]%2==0删除体验不同感受
{
settextcolor(RED);
settextstyle(Key - 2, 0, _T("楷书"));
outtextxy(51 + Key * x, 51 + Key * y, _T("雷"));
return -1;
}
if (chess_board[y][x] > 0&&chess_flag[y][x]%2==0)//把&&chess_flag[y][x]%2==0删除体验不同感受
{
outtextxy(51 + Key * x, 51 + Key * y, _T(" "));
show_num(chess_board[y][x], x, y);
return 1;
}
if (chess_board[y][x] == 0&&chess_flag[y][x]%2==0)//把&&chess_flag[y][x]%2==0删除体验不同感受
{
*(&chess_board[y][x]) = 9;
show_num(chess_board[y][x], x, y);
turn_chess(x - 1, y - 1);
turn_chess(x - 1, y);
turn_chess(x - 1, y + 1);
turn_chess(x + 1, y - 1);
turn_chess(x + 1, y);
turn_chess(x + 1, y + 1);
turn_chess(x, y - 1);
turn_chess(x, y + 1);
return 1;
}
}
插旗函数
插旗就是在另一个数组里面计数,如果基数就插旗如果偶数就取消插旗。
插旗后chess_board里面对应的数会变成他的相反数。
void Flag(int x,int y)
{
settextcolor(GREEN);
settextstyle(Key - 2, 0, _T("楷书"));
*(&chess_flag[y][x]) = chess_flag[y][x] + 1;
if(chess_flag[y][x]%2==1)
outtextxy(51 + Key * x, 51 + Key * y, _T("旗"));
else
{
settextcolor(RGB(150, 150, 250));
fillrectangle(50 + Key * x, 50 + Key * y, 50 + Key * x + Key, 50 + Key * y + Key);
}
*(&chess_board[y][x]) = (-1) * (chess_board[y][x]);
/*for (int i = 0; i < Wide; i++)
{
for (int k = 0; k < Wide; k++)
printf("%2d", chess_board[i][k]);
printf("\n");
}
printf("\n");//这个取消注释可以看答案*/
}
判断输赢
chess_board里面对应的数如果都是非负数就赢了。
int win_or_lose()
{
int i, j;
for (i = 0; i < Wide; i++)
{
for (j = 0; j < Wide; j++)
{
if (chess_board[i][j] < 0)
return 0;
}
}
return 1;
}
最后的main函数
把所有函数都用在上面就完成了。
void main()
{
srand(time(NULL));
initgraph(100 + Key * Wide, 100 + Key * Wide);
setbkcolor(WHITE);
cleardevice();
setfillcolor(RGB(150, 150, 250));
fillrectangle(50, 50, 50 + Key * Wide, 50 + Key * Wide);
draw_line();
int n=0;
while (n <= 0 || n >= Key * Key)
{
printf("请输入雷的数量:\n");
scanf_s("%d", &n);
}
rand_lei(n);
n = 0;
/*for (int i = 0; i < Wide; i++)
{
for (int k = 0; k < Wide; k++)
printf("%2d", chess_board[i][k]);
printf("\n");
}
printf("\n");*///这个也是显示答案的地方
while (1)
{
m = GetMouseMsg();
if (m.uMsg == WM_RBUTTONDOWN)
{
Flag((m.x - 50) / Key, (m.y - 50) / Key);
n = win_or_lose();
if (n == 1)
{
settextcolor(RED);
settextstyle(Key * 2, 0, _T("楷书"));
outtextxy(25, 25 + Key * Wide / 2, _T("挑战成功 游戏胜利"));
}
}
if (m.uMsg == WM_LBUTTONDOWN)
{
n=turn_chess((m.x - 50) / Key, (m.y - 50) / Key);
if (n == -1)
{
settextcolor(RED);
settextstyle(Key * 2, 0, _T("楷书"));
outtextxy(25, 25 + Key * Wide / 2, _T("挑战失败 游戏结束"));
}
}
}
}
小结
到这里就结束了,如果不想看代码,把代码从上到下复制一遍就也能玩啦!有什么问题欢迎大家在评论区留言,最后祝大家玩的开心。点个赞再走吧(✿◕‿◕✿)
最后,呈上源码。
#include <stdio.h>
#include <windows.h>
#include <graphics.h>
#include <easyx.h>
#include<stdlib.h>
#include<time.h>
#define Wide 15
#define Key 40
MOUSEMSG m;
int chess_board[Wide][Wide] = {0};
int chess_flag[Wide][Wide] = {0};
void draw_line()
{
setlinecolor(BLACK);
int i = 0;
for (i; i <= Wide; i++)
{
line(50 + Key * i, 50, 50 + Key * i, 50+Key*Wide);
line(50, 50 + Key * i, 50 + Key * Wide, 50 + Key * i);
}
}
void rand_lei(int Num)
{
int x, y;
while (Num)
{
x = rand() % Wide;
y = rand() % Wide;
if (chess_board[y][x] == 0)
{
*(&chess_board[y][x]) = -9;
Num--;
}
}
for (x = 1; x < Wide-1; x++)
{
for (y = 1; y < Wide-1; y++)
{
if (chess_board[x][y] < 0)
{
*(&chess_board[x - 1][y - 1]) = chess_board[x - 1][y - 1] + 1;
*(&chess_board[x - 1][y]) = chess_board[x - 1][y] + 1;
*(&chess_board[x - 1][y + 1]) = chess_board[x - 1][y + 1] + 1;
*(&chess_board[x + 1][y - 1]) = chess_board[x + 1][y - 1] + 1;
*(&chess_board[x + 1][y]) = chess_board[x + 1][y] + 1;
*(&chess_board[x + 1][y + 1]) = chess_board[x + 1][y + 1] + 1;
*(&chess_board[x][y - 1]) = chess_board[x][y - 1] + 1;
*(&chess_board[x][y + 1]) = chess_board[x][y + 1] + 1;
}
}
if (chess_board[0][x] < 0)
{
*(&chess_board[0][x - 1]) = chess_board[0][x - 1] + 1;
*(&chess_board[0][x + 1]) = chess_board[0][x + 1] + 1;
*(&chess_board[1][x + 1]) = chess_board[1][x + 1] + 1;
*(&chess_board[1][x - 1]) = chess_board[1][x - 1] + 1;
*(&chess_board[1][x]) = chess_board[1][x] + 1;
}
if (chess_board[Wide-1][x] < 0)
{
*(&chess_board[Wide - 1][x - 1]) = chess_board[Wide - 1][x - 1] + 1;
*(&chess_board[Wide - 1][x + 1]) = chess_board[Wide - 1][x + 1] + 1;
*(&chess_board[Wide - 2][x + 1]) = chess_board[Wide - 2][x + 1] + 1;
*(&chess_board[Wide - 2][x - 1]) = chess_board[Wide - 2][x - 1] + 1;
*(&chess_board[Wide - 2][x]) = chess_board[Wide - 2][x] + 1;
}
if (chess_board[x][0] < 0)
{
*(&chess_board[x + 1][0]) = chess_board[x + 1][0] + 1;
*(&chess_board[x + 1][1]) = chess_board[x + 1][1] + 1;
*(&chess_board[x][1]) = chess_board[x][1] + 1;
*(&chess_board[x - 1][0]) = chess_board[x - 1][0] + 1;
*(&chess_board[x - 1][1]) = chess_board[x - 1][1] + 1;
}
if (chess_board[x][Wide - 1] < 0)
{
*(&chess_board[x + 1][Wide - 1]) = chess_board[x + 1][Wide - 1] + 1;
*(&chess_board[x + 1][Wide - 2]) = chess_board[x + 1][Wide - 2] + 1;
*(&chess_board[x][Wide - 2]) = chess_board[x][Wide - 2] + 1;
*(&chess_board[x - 1][Wide - 1]) = chess_board[x - 1][Wide - 1] + 1;
*(&chess_board[x - 1][Wide - 2]) = chess_board[x - 1][Wide - 2] + 1;
}
}
if (chess_board[0][0] < 0)
{
*(&chess_board[0][1]) = chess_board[0][1] + 1;
*(&chess_board[1][1]) = chess_board[1][1] + 1;
*(&chess_board[1][0]) = chess_board[1][0] + 1;
}
if (chess_board[Wide-1][0] < 0)
{
*(&chess_board[Wide-1][1]) = chess_board[Wide-1][1] + 1;
*(&chess_board[Wide-2][1]) = chess_board[Wide-2][1] + 1;
*(&chess_board[Wide-2][0]) = chess_board[Wide-2][0] + 1;
}
if (chess_board[0][Wide-1] < 0)
{
*(&chess_board[0][Wide-2]) = chess_board[0][Wide-2] + 1;
*(&chess_board[1][Wide-1]) = chess_board[1][Wide-1] + 1;
*(&chess_board[1][Wide-2]) = chess_board[1][Wide-2] + 1;
}
if (chess_board[Wide-1][Wide-1] < 0)
{
*(&chess_board[Wide-1][Wide-2]) = chess_board[Wide-1][Wide-2] + 1;
*(&chess_board[Wide-2][Wide-2]) = chess_board[Wide-2][Wide-2] + 1;
*(&chess_board[Wide-2][Wide-1]) = chess_board[Wide-2][Wide-1] + 1;
}
}
void show_num(int n,int x,int y)
{
settextcolor(BLUE);
settextstyle(Key - 2, 0, _T("楷书"));
switch (n)
{
case 9:outtextxy(51 + Key * x, 51 + Key * y, _T(" ")); break;
case 1:outtextxy(50 + Key / 3 + Key * x, 51 + Key * y, _T("1")); break;
case 2:outtextxy(50 + Key / 3 + Key * x, 51 + Key * y, _T("2")); break;
case 3:outtextxy(50 + Key / 3 + Key * x, 51 + Key * y, _T("3")); break;
case 4:outtextxy(50 + Key / 3 + Key * x, 51 + Key * y, _T("4")); break;
case 5:outtextxy(50 + Key / 3 + Key * x, 51 + Key * y, _T("5")); break;
case 6:outtextxy(50 + Key / 3 + Key * x, 51 + Key * y, _T("6")); break;
case 7:outtextxy(50 + Key / 3 + Key * x, 51 + Key * y, _T("7")); break;
case 8:outtextxy(50 + Key / 3 + Key * x, 51 + Key * y, _T("8")); break;
}
}
int turn_chess(int x, int y)
{
if (y < 0 || x < 0 || x >(Wide - 1) || y >(Wide - 1))
return 0;
if (chess_board[y][x] < 0)
{
settextcolor(RED);
settextstyle(Key - 2, 0, _T("楷书"));
outtextxy(51 + Key * x, 51 + Key * y, _T("雷"));
return -1;
}
if (chess_board[y][x] > 0)
{
outtextxy(51 + Key * x, 51 + Key * y, _T(" "));
show_num(chess_board[y][x], x, y);
return 1;
}
if (chess_board[y][x] == 0)
{
*(&chess_board[y][x]) = 9;
show_num(chess_board[y][x], x, y);
turn_chess(x - 1, y - 1);
turn_chess(x - 1, y);
turn_chess(x - 1, y + 1);
turn_chess(x + 1, y - 1);
turn_chess(x + 1, y);
turn_chess(x + 1, y + 1);
turn_chess(x, y - 1);
turn_chess(x, y + 1);
return 1;
}
}
void Flag(int x,int y)
{
settextcolor(GREEN);
settextstyle(Key - 2, 0, _T("楷书"));
*(&chess_flag[y][x]) = chess_flag[y][x] + 1;
if(chess_flag[y][x]%2==1)
outtextxy(51 + Key * x, 51 + Key * y, _T("旗"));
else
{
settextcolor(RGB(150, 150, 250));
fillrectangle(50 + Key * x, 50 + Key * y, 50 + Key * x + Key, 50 + Key * y + Key);
}
*(&chess_board[y][x]) = (-1) * (chess_board[y][x]);
for (int i = 0; i < Wide; i++)
{
for (int k = 0; k < Wide; k++)
printf("%2d", chess_board[i][k]);
printf("\n");
}
printf("\n");
}
int win_or_lose()
{
int i, j;
for (i = 0; i < Wide; i++)
{
for (j = 0; j < Wide; j++)
{
if (chess_board[i][j] < 0)
return 0;
}
}
return 1;
}
void main()
{
srand(time(NULL));
initgraph(100 + Key * Wide, 100 + Key * Wide);
setbkcolor(WHITE);
cleardevice();
setfillcolor(RGB(150, 150, 250));
fillrectangle(50, 50, 50 + Key * Wide, 50 + Key * Wide);
draw_line();
int n=0;
while (n <= 0 || n >= Key * Key)
{
printf("请输入雷的数量:\n");
scanf_s("%d", &n);
}
rand_lei(n);
n = 0;
for (int i = 0; i < Wide; i++)
{
for (int k = 0; k < Wide; k++)
printf("%2d", chess_board[i][k]);
printf("\n");
}
printf("\n");
while (1)
{
m = GetMouseMsg();
if (m.uMsg == WM_RBUTTONDOWN)
{
Flag((m.x - 50) / Key, (m.y - 50) / Key);
n = win_or_lose();
if (n == 1)
{
settextcolor(RED);
settextstyle(Key * 2, 0, _T("楷书"));
outtextxy(25, 25 + Key * Wide / 2, _T("挑战成功 游戏胜利"));
}
}
if (m.uMsg == WM_LBUTTONDOWN)
{
n=turn_chess((m.x - 50) / Key, (m.y - 50) / Key);
if (n == -1)
{
settextcolor(RED);
settextstyle(Key * 2, 0, _T("楷书"));
outtextxy(25, 25 + Key * Wide / 2, _T("挑战失败 游戏结束"));
}
}
}
}