【蓝因子教育】用C语言自制开发新版扫雷:六边形寻宝模式!

程序简介

六边形扫雷,寻宝模式,稍稍介绍一下。

他也是要把所有安全的地方点出来。

他没有扫雷模式的消零算法。每一个安全的点都需要单独挖出来,一次显示一个格子。

添加了生命值的概念,也就是说存在一定的容错。

显示的数字有别于扫雷模式。点击宝藏点,会显示周围宝藏点数量,绿色;点击地雷,会显示周围地雷数量,黑色。注意,这个数字不包括自己,显示的范围自然就是 0~6 了。点击地雷会减生命值,生命值归零则结束。

所以雷和宝藏都是有价值的,都是能给准确信息的。

我能给一个参考难度:占总格子数 40%的地雷,占总地雷数 50 %的生命值。

程序运行展示

完整源代码

# include <math.h>

# include <graphics.h>

# include <string>

# include <time.h>

static double pi = acos (-1.0); // 圆周率 π

static HWND hOut; // 画布

// 定义一个结构体,按钮

struct Node1

{

int posx1, posy1, posx2, posy2; // 坐标

LPTSTR text; // 文字

int mod; // 状态

};

// 定义一个结构体,六边形格子

struct Node2

{

int i, j, k; // 特征值

int mod_life; // 翻开

int mod_mine; // 雷

int mod_flag; // 标记

int posx, posy; // 坐标

int num_mine; // 周围雷数

int num_peace; // 周围空地块

};

// 定义一个类

class Gary

{

public:

void carry (); // 主进程

void initialization (); // 初始化

void draw_scene (); // 绘制界面函数

void draw_box (int num_box); // 绘制格子

void draw_flag (int num_box); // 绘制标记

void draw_num (int num_box, int num); // 绘制数字

void move (); // 窗口主视角

void create (); // 地雷生成

void check_over (); // 结束判定

int num_button; // 按钮数量参数

int exit_carry; // 主循函数控制参数

int exit_move; // 开始界面控制参数

int exit_game; // 游戏进行控制参数

int num_life; // 生命值

int num_size; // 边长

int num_mine; // 总雷数

int num_box; // 总地块数

int num_flag; // 标记数

COLORREF color_text[2]; // 按钮绘制填充

Node1 boxm[30]; // 按钮,预制 30 个

Node2 box[1000]; // 地块

};

// 标记绘制函数

void Gary::draw_flag (int num_box)

{

setlinestyle (PS_SOLID, 1);

setlinecolor (BLACK);

line (box[num_box].posx + 2, box[num_box].posy + 7, box[num_box].posx + 2, box[num_box].posy - 7);

setfillcolor (LIGHTRED);

setlinecolor (LIGHTRED);

fillrectangle (box[num_box].posx - 7 + 2, box[num_box].posy - 7, box[num_box].posx + 2, box[num_box].posy - 1);

}

// 数字绘制函数

void Gary::draw_num (int num_box, int num)

{

int i;

// 画六边形,格子处于点击后状态

setfillcolor (RGB (170, 170, 170));

setlinecolor (RGB (85, 85, 85));

POINT pts[6];

setlinestyle (PS_SOLID, 1);

for (i = 0; i < 6; i++)

{

pts[i].x = long(box[num_box].posx + 14.0 * cos (60.0 * double (i) * pi / 180.0));

pts[i].y = long(box[num_box].posy + 14.0 * sin (60.0 * double (i) * pi / 180.0));

}

fillpolygon (pts, 6);

// 数字绘制

TCHAR s[15];

settextstyle (20, 0, _T ("Consolas"));

_stprintf_s (s, _T ("%0.1d"), num);

outtextxy (box[num_box].posx - 5, box[num_box].posy - 10, s);

}

// 场景绘制函数

void Gary::draw_scene ()

{

TCHAR s[15];

int i, j;

setlinecolor (BLACK);

setfillcolor (WHITE);

setlinestyle (PS_SOLID, 1);

// 主界面

fillrectangle (401, 0, 650, 400);

// 根据按钮数量绘制

settextcolor (BLACK);

for (i = 0; i < num_button; i++)

{

setfillcolor (color_text[boxm[i].mod]);

setbkcolor (color_text[boxm[i].mod]);

// 边框

fillrectangle (boxm[i].posx1, boxm[i].posy1, boxm[i].posx2, boxm[i].posy2);

// 文字

outtextxy (boxm[i].posx1 + (boxm[i].posx2 - boxm[i].posx1) / 2 - textwidth (boxm[i].text) / 2, boxm[i].posy1 + 4, boxm[i].text);

}

// 设置参数

setbkcolor (WHITE);

settextcolor (BLACK);

setlinecolor (BLACK);

// 变量绘制

j = 25;

// 生命值

i = 1;

setbkcolor (color_text[boxm[i].mod]);

_stprintf_s (s, _T ("%0.1d"), num_life);

outtextxy (boxm[i].posx1 + (boxm[i].posx2 - boxm[i].posx1) / 2 - textwidth (boxm[i].text) / 2, boxm[i].posy1 + j, s);

// 边长

i = 2;

setbkcolor (color_text[boxm[i].mod]);

_stprintf_s (s, _T ("%0.1d"), num_size);

outtextxy (boxm[i].posx1 + (boxm[i].posx2 - boxm[i].posx1) / 2 - textwidth (boxm[i].text) / 2, boxm[i].posy1 + j, s);

// 总地雷数

i = 3;

setbkcolor (color_text[boxm[i].mod]);

_stprintf_s (s, _T ("%0.1d"), num_mine);

outtextxy (boxm[i].posx1 + (boxm[i].posx2 - boxm[i].posx1) / 2 - textwidth (boxm[i].text) / 2, boxm[i].posy1 + j, s);

// 格子

i = 4;

setbkcolor (color_text[boxm[i].mod]);

_stprintf_s (s, _T ("%0.1d"), num_box);

outtextxy (boxm[i].posx1 + (boxm[i].posx2 - boxm[i].posx1) / 2 - textwidth (boxm[i].text) / 2, boxm[i].posy1 + j, s);

// 标记数

i = 5;

setbkcolor (color_text[boxm[i].mod]);

_stprintf_s (s, _T ("%0.1d"), num_flag);

outtextxy (boxm[i].posx1 + (boxm[i].posx2 - boxm[i].posx1) / 2 - textwidth (boxm[i].text) / 2, boxm[i].posy1 + j, s);

FlushBatchDraw ();

}

// 地雷生成函数

void Gary::create ()

{

int i, j;

// 设置雷

for (i = 0; i < num_mine; i++)

{

// 随机

j = rand () % 1000;

while (box[j].mod_mine == 1 || box[j].mod_life == 1)

{

// 随机

j = rand () % 1000;

}

// 是雷

box[j].mod_mine = 1;

}

// 周边雷数统计

// 遍历

for (i = 0; i <= 888; i++)

{

if (box[i].mod_life == 0)

{

// 遍历

for (j = 0; j <= 999; j++)

{

// 排除自己

if (j != i && box[j].mod_life == 0)

{

// 周围六个

if ((box[j].posx - box[i].posx) * (box[j].posx - box[i].posx) + (box[j].posy - box[i].posy) * (box[j].posy - box[i].posy) <= 900)

{

// 是雷

if (box[j].mod_mine == 1)

{

// 周边雷数参数加一

box[i].num_mine++;

}

// 不是雷

else if (box[j].mod_mine == 0)

{

// 周边安全数参数加一

box[i].num_peace++;

}

}

}

}

}

}

}

// 结束判断函数

void Gary::check_over ()

{

int i, k;

k = 0;

for (i = 0; i <= 888; i++)

{

// 每有一个翻开且不是雷的点,则加一

if (box[i].mod_mine == 0 && box[i].mod_life == 1)

{

k++;

}

}

// 全翻开则结束

if (k == num_box - num_mine)

{

// 将所有未翻开雷做上标记

for (i = 0; i <= 888; i++)

{

if (box[i].mod_mine == 1 && box[i].mod_life == 0)

{

draw_flag (i);

}

}

// 胜利标志:笑脸

setfillcolor (WHITE);

setlinecolor (WHITE);

fillrectangle (50, 20, 75, 45);

settextstyle (30, 0, _T ("Wingdings"));

setbkmode (TRANSPARENT);

settextcolor (BLACK);

outtextxy (50, 20, 0x4A);

setbkmode (OPAQUE);

settextstyle (20, 0, _T ("Consolas"));

// 结束变化

exit_game = 1;

boxm[1].mod = 0;

boxm[2].mod = 0;

boxm[3].mod = 0;

boxm[6].mod = 0;

boxm[7].mod = 1;

num_flag = 0;

// 绘制

draw_scene ();

}

}

// 格子绘制函数

void Gary::draw_box (int num_box)

{

int i;

int posx, posy;

// 六边形绘制

posx = box[num_box].posx;

posy = box[num_box].posy;

POINT pts[6];

setlinestyle (PS_SOLID, 2);

// 背景色

setfillcolor (RGB (255, 255, 255));

for (i = 0; i < 6; i++)

{

pts[i].x = long(posx + 14.0 * cos (60.0 * double (i) * pi / 180.0));

pts[i].y = long(posy + 14.0 * sin (60.0 * double (i) * pi / 180.0));

}

solidpolygon (pts, 6);

// 灰边

setlinecolor (RGB (85, 85, 85));

line (pts[0].x, pts[0].y, pts[1].x, pts[1].y);

line (pts[5].x, pts[5].y, pts[0].x, pts[0].y);

line (pts[1].x, pts[1].y, pts[2].x, pts[2].y);

// 前景色

setfillcolor (RGB (170, 170, 170));

for (i = 0; i < 6; i++)

{

pts[i].x = long(posx + 12.0 * cos (60.0 * double (i) * pi / 180.0));

pts[i].y = long(posy + 12.0 * sin (60.0 * double (i) * pi / 180.0));

}

solidpolygon (pts, 6);

FlushBatchDraw ();

}

// 初始化函数

void Gary::initialization ()

{

int i, j, k, t;

// 随机初始化

srand ((unsigned)time (NULL));

// 颜色初始化

color_text[0] = WHITE;

color_text[1] = RGB (170, 170, 170);

// 按钮的初始化

num_button = 10;

// 坐标

for (i = 0; i < 10; i++)

{

boxm[i].posx1 = 410 + 120 * (i % 2);

boxm[i].posy1 = 25 + 75 * (i / 2);

boxm[i].posx2 = 520 + 120 * (i % 2);

boxm[i].posy2 = 75 + 75 * (i / 2);

}

// 内容

boxm[0].text = _T ("寻宝模式"); boxm[1].text = _T ("生命值");

boxm[2].text = _T ("地图边长"); boxm[3].text = _T ("总地雷数");

boxm[4].text = _T ("总地块数"); boxm[5].text = _T ("已标记数");

boxm[6].text = _T ("开始"); boxm[7].text = _T ("重置");

boxm[8].text = _T ("截图"); boxm[9].text = _T ("退出");

// 状态

boxm[0].mod = 1;

boxm[1].mod = 1;

boxm[2].mod = 1;

boxm[3].mod = 1;

boxm[4].mod = 1;

boxm[5].mod = 1;

boxm[6].mod = 1;

boxm[7].mod = 0;

boxm[8].mod = 0;

boxm[9].mod = 0;

num_box = 3 * num_size * (num_size - 1) + 1;

num_flag = 0;

// 绘制参数初始化

setlinecolor (BLACK);

setlinestyle (PS_SOLID, 1);

settextstyle (20, 0, _T ("Consolas"));

// 第一次绘制

draw_scene ();

// 重置

setfillcolor (WHITE);

fillrectangle (0, 0, 400, 400);

// 平静脸

setfillcolor (WHITE);

setlinecolor (WHITE);

fillrectangle (50, 20, 75, 45);

settextstyle (30, 0, _T ("Wingdings"));

setbkmode (TRANSPARENT);

settextcolor (BLACK);

outtextxy (50, 20, 0x4B);

setbkmode (OPAQUE);

settextstyle (20, 0, _T ("Consolas"));

// 格子初始化

for (t = 0; t <= 999; t++)

{

// 已翻开

box[t].mod_life = 1;

// 城墙

box[t].mod_mine = 2;

// 坐标,点不到

box[t].posx = -200;

box[t].posy = -200;

}

// 初始化

for (i = 0; i < num_size; i++)

{

for (j = 0; j < num_size; j++)

{

for (k = 0; k < num_size; k++)

{

// 特征值至少一个为零

if (i == 0 || j == 0 || k == 0)

{

// 编号

t = i * 100 + j * 10 + k;

// 特征值

box[t].i = i;

box[t].j = j;

box[t].k = k;

// 未翻开

box[t].mod_life = 0;

// 不是雷

box[t].mod_mine = 0;

// 未标记

box[t].mod_flag = 0;

// 坐标

box[t].posx = 200 + 22 * (j - k);

box[t].posy = 200 - 25 * i + 13 * (j + k);

// 周围雷数初始化

box[t].num_mine = 0;

box[t].num_peace = 0;

// 绘制地块

draw_box (t);

}

}

}

}

// 地雷生成函数

create ();

}

// 窗口主视角函数,获取用户操作

void Gary::move ()

{

// 鼠标定义

ExMessage m;

TCHAR ss[15];

int i, t;

exit_move = 0;

exit_game = 0;

while (exit_move == 0)

{

// 鼠标信息

if (peekmessage (&m, EM_MOUSE | EM_KEY))

{

// 左键单击判断

if (m.message == WM_LBUTTONDOWN)

{

// 判断是否点击了格子

if (m.x > 0 && m.y > 0 && m.x < 400 && m.y < 400 && exit_game == 0)

{

for (t = 0; t <= 888; t++)

{

// 成功点击未标记的空格子

if ((m.x - box[t].posx) * (m.x - box[t].posx) + (m.y - box[t].posy) * (m.y - box[t].posy) <= 144 && box[t].mod_life == 0 && box[t].mod_flag == 0)

{

// 点击的格子不是雷

if (box[t].mod_mine == 0)

{

// 绿色,安全,绘制

settextcolor (LIGHTGREEN);

draw_num (t, box[t].num_peace);

// 改为翻开

box[t].mod_life = 1;

}

// 点击的格子雷

else if (box[t].mod_mine == 1)

{

// 扣除生命值

num_life--;

// 黑色,危险,绘制

settextcolor (BLACK);

draw_num (t, box[t].num_mine);

// 改为翻开

box[t].mod_life = 1;

// 生命值减为零

if (num_life <= 0)

{

// 失败标志:哭脸

setfillcolor (WHITE);

setlinecolor (WHITE);

fillrectangle (50, 20, 75, 45);

settextstyle (30, 0, _T ("Wingdings"));

setbkmode (TRANSPARENT);

settextcolor (BLACK);

outtextxy (50, 20, 0x4C);

setbkmode (OPAQUE);

settextstyle (20, 0, _T ("Consolas"));

// 失败

exit_game = 1;

boxm[1].mod = 0;

boxm[2].mod = 0;

boxm[3].mod = 0;

boxm[6].mod = 0;

boxm[7].mod = 1;

num_flag = 0;

}

// 绘制

draw_scene ();

}

// 成功结束判断

check_over ();

break;

}

}

}

// 判断是否点击了可点击按钮

for (i = 0; i < num_button; i++)

{

if (m.x > boxm[i].posx1 && m.y > boxm[i].posy1 && m.x < boxm[i].posx2 && m.y < boxm[i].posy2 && boxm[i].mod == 0)

{

break;

}

}

// 点击矩形按钮

switch (i)

{

// 生命值:num_life

case 1:

{

// 输入

InputBox (ss, 10, _T ("输入生命值(1 ~ 999)"));

_stscanf_s (ss, _T ("%d"), &i);

if (i > 0 && i <= 999)

{

num_life = i;

}

else { MessageBox (hOut, _T ("输入错误,不在范围内"), _T ("来自小豆子的提醒"), MB_OK); }

// 绘制

draw_scene ();

break;

}

// 地图边长:num_size

case 2:

{

// 输入

InputBox (ss, 10, _T ("输入边长(2 ~ 8)"));

_stscanf_s (ss, _T ("%d"), &i);

if (i > 1 && i <= 8)

{

num_size = i;

num_box = 3 * num_size * (num_size - 1) + 1;

}

else { MessageBox (hOut, _T ("输入错误,不在范围内"), _T ("来自小豆子的提醒"), MB_OK); }

// 绘制

draw_scene ();

break;

}

// 总地雷数:num_mine

case 3:

{

InputBox (ss, 10, _T ("输入地雷数(1 ~ 总格子数)"));

_stscanf_s (ss, _T ("%d"), &i);

if (i > 0 && i < num_box)

{

num_mine = i;

}

else { MessageBox (hOut, _T ("输入错误,不在范围内"), _T ("来自小豆子的提醒"), MB_OK); }

// 绘制

draw_scene ();

break;

}

// 开始

case 6:

{

num_box = 3 * num_size * (num_size - 1) + 1;

if (num_mine < num_box && num_life > 0)

{

exit_game = 0;

// 初始化

initialization ();

}

else

{

MessageBox (hOut, _T ("请将雷数修改为小于格子数或将生命值修改为大于零"), _T ("来自小豆子的提醒"), MB_OK);

}

break;

}

// 重置

case 7:

{

// 结束游戏进程,进入准备阶段

if (exit_game == 0)

{

exit_game = 1;

boxm[1].mod = 0;

boxm[2].mod = 0;

boxm[3].mod = 0;

boxm[6].mod = 0;

boxm[7].mod = 1;

num_flag = 0;

// 绘制

draw_scene ();

}

break;

}

// 截图

case 8:

{

saveimage (_T ("image.png"));

break;

}

// 退出

case 9:

{

exit_game = 1;

exit_move = 1;

exit_carry = 1;

break;

}

default:break;

}

}

// 右键,且处于游戏进行状态

else if (m.message == WM_RBUTTONDOWN && exit_game == 0)

{

for (t = 0; t <= 888; t++)

{

// 成功点击空格子

if ((m.x - box[t].posx) * (m.x - box[t].posx) + (m.y - box[t].posy) * (m.y - box[t].posy) <= 144 && box[t].mod_life == 0)

{

// 标记状态转换

box[t].mod_flag = (box[t].mod_flag == 0 ? 1 : 0);

// 绘制

draw_box (t);

// 画小旗子

if (box[t].mod_flag == 1)

{

draw_flag (t);

num_flag++;

}

else

{

num_flag--;

}

// 绘制

draw_scene ();

}

}

}

}

}

}

// 主进程

void Gary::carry ()

{

// 窗口定义

hOut = initgraph (651, 401);

SetWindowText (hOut, _T ("六边形扫雷:扫雷模式"));

// 参数初始化

num_size = 5;

num_mine = 10;

num_life = 3;

// 背景绘制

setbkcolor (WHITE);

cleardevice ();

// 进程控制

exit_carry = 0;

while (exit_carry == 0)

{

initialization ();

move ();

}

closegraph ();

}

// 主函数

int main (void)

{

Gary G;

G.carry ();

return 0;

}返回搜狐,查看更多

责任编辑:

平台声明:该文观点仅代表作者本人,搜狐号系信息发布平台,搜狐仅提供信息存储空间服务。
阅读 ()