象棋马拉松
2022-1-20 ~ 2022-2-25
(1)
程序简介
象棋马拉松,这个小游戏就是控制一个马往前跳。原游戏只有新棋子第一次出现会显示跳哪些地方会被吃。而我加了右键提示,为了判定每个格子安不安全,本身需要一个存危险点和可以移动点的函数。原游戏挺上瘾的,配有落子的音效,就是下的随便的时候很容易失误,原游戏是无尽模式,我加了一个闯关模式。
里面的所有棋子都是象棋棋子,满足象棋规则。
无尽模式是控制一个“马”,日字格向前跳,某一步下完后会被黑子吃掉的话,即为失败。里面存在别象腿,别马腿。
闯关模式,我设计了“车马炮”,合理运用他们闯过前方的布阵,一起到达顶点,即为成功,刷新关卡。为降低难度,最后一个字到达顶点时,即使会被吃,也优先算过关。
第一次更新:
- 两个模式都增加了生命值,主要是方便闯关模式不小心的失误。无尽模式考验的更多就是耐心。以后也许能添加回血棋子。
- 无尽模式添加动画,不至于突兀。
- 添加游戏记录,包括前进几格(闯过几关)和吃了多少子,这是最直接的游戏目标。
- 修复了因为“炮”子导致的落子范围错误显示的 bug。
- 修复了闯关刷新之后无解的 bug。但不代表闯关模式一定有解,例如双“车”沉底,一定会损失一命,为此添加了刷新按钮,并且每通一关加一命,最大限度降低了影响。
也许以后更新还可以添加自定义闯关模式,设计敌我棋子的布局。或者把“车马炮”换成其他棋子。我的判断函数存了所用的全部 6 种棋子,所以是可以换的。那样能设计的模式就多了,这次就没有再加了。
第二次更新:
- 字符串更新,不再使用 char
- 修复因为随机种子参数,而每次开局都一样的 bug,随机种子参数变更为通过时间设置,即 srand( (unsigned)time( NULL ) )
3. 文章细节的更新。
第三次更新:
- 图片更新,减小边框
- 代码更新,现在兼容 vc2010,不兼容 vc6.0
vc2010:_stscanf_s,vc6.0:_stscanf
vc2010:_stprintf_s,vc6.0:_stprintf - 修复了闯关开局就无解的 bug。
程序执行效果
完整源代码
////////////////////////////////////////
// 程序:象棋马拉松
// 作者:Gary
// 编译环境:Visual C++ 2010,EasyX_20211109
// 编写日期:2021-7-14
////////////////////////////// 游戏进程头文件 //////////////////////////////
# include <math.h>
# include <graphics.h>
# include <string>
# include <time.h>
# include <stdlib.h>
// 头文件
// 头文件编译开始
#ifndef CIRCLE_H
#define CIRCLE_H
// 定义变量
static double pi = acos (-1.0); // 圆周率π
static HWND hOut; // 画布
// 定义一个结构体,格子
struct Node1
{
int boxnum; // 格子编号
LPTSTR text; // 刻字
COLORREF color; // 颜色
int piecenum; // 棋子类型参数
int posx, posy; // 坐标参数
int type; // 格子激活状态,有无棋子坐落
};
// 定义一个结构体,可抵达格子
struct Node2
{
int type; // 格子激活状态,可否抵达
};
// 定义一个结构体,危险格子
struct Node3
{
int type; // 格子激活状态,是否危险
};
// 定义一个结构体,按钮
struct Node4
{
int posx1, posy1, posx2, posy2; // 坐标
double r; // 原按钮半径
LPTSTR text; // 按钮文本
int type; // 按钮激活状态
};
// 定义一个类,game
class game
{
public:
// 函数
int carry_main (); // 游戏进程主循函数
void draw_piece (int posx, int posy, LPTSTR text, COLORREF color); // 棋子绘制函数
void draw_button (); // 按钮绘制函数
void creact_piece (int floor); // 棋子生成函数
void check (); // 判断函数
void check_main (); // 判断主函数
void carry_prepare (); // 准备进程主循函数
void initialization_prepare (); // 准备进程初始化函数
void draw_scene_prepare (); // 准备进程绘制函数
void draw_word (double size, int posx, int posy, LPTSTR text); // 标题绘制函数
void carry_start (); // 开始进程主循函数
void initialization_start (); // 开始进程初始化函数
void draw_scene_start (); // 开始进程绘制函数
void draw_bk (); // 背景绘制函数
void draw_tip (); // 提示绘制函数
// 结构体
Node1 box[16][7]; // 格子
Node2 box1[16][7]; // 可达格子
Node3 box2[16][7]; // 危险格子
Node4 boxm[20]; // 按钮,预制二十个
// 变量
int num_button; // 按钮数量
int exit_carry; // 主进程主循函数控制参数
int exit_start; // 开始进程主循函数控制参数
int mod_start; // 游戏模式参数
int flag; // 当前控制移动格子参数
int tip_or_not; // 是否提示参数
int selected_or_not; // 闯关模式是否选定移动目标棋子
int start_life; // 生命条
int start_record; // 记录
int start_eat; // 食子数
};
// 头文件编译结束
#endif
////////////////////////////// 主程序源文件 //////////////////////////////
// 窗口初始化
void initialization ()
{
// 窗口定义,整个程序仅定义一次
hOut = initgraph (450, 650);
pi = acos (-1.0);
// 窗口标题
SetWindowText (hOut, _T ("象棋马拉松"));
}
// 总进程主循函数
void carry ()
{
// 总进程参数初始化
int exit_carry = 0;
// 进程控制
BeginBatchDraw ();
// 创建游戏类对象
game G;
// 游戏进程
while (exit_carry == 0)
{
// 执行游戏总进程,并接收游戏进程结束时返回值
// 准备进程时,点击退出按钮结束返回 1
// 开始进程时,点击返回按钮结束返回 0
exit_carry = G.carry_main ();
}
EndBatchDraw ();
// 关闭窗口
closegraph ();
}
// 主函数
int main (void)
{
// 初始化
initialization ();
// 总进程主循函数
carry ();
return 0;
}
////////////////////////////// 游戏进程源文件 //////////////////////////////
// 游戏进程主循函数
int game::carry_main ()
{
// 游戏进程参数初始化
exit_carry = 0;
// 随机种子初始化
srand ((unsigned)time (NULL));
// 准备进程初始化函数
initialization_prepare ();
// 准备进程主循函数
carry_prepare ();
// 准备进程结束
// 准备进程时,点击退出按钮结束,游戏进程参数为 1
// 准备进程时,正常进入游戏,游戏进程参数为 0
if (exit_carry == 0)
{
// 开始进程初始化函数
initialization_start ();
// 开始进程主循函数
carry_start ();
}
// 开始进程结束
// 点击返回按钮结束,或者正常游戏结束,游戏进程参数不变
return exit_carry;
}
// 按钮绘制函数
void game::draw_button ()
{
// 根据颜色结构体设置参数
setlinecolor (RGB (125, 125, 125));
setfillcolor (BLACK);
setbkcolor (BLACK);
settextcolor (WHITE);
settextstyle (30, 15, _T ("Consolas"));
setlinestyle (PS_SOLID, 10);
// 根据按钮数量参数绘制
for (int i = 0; i < num_button; i++)
{
if (boxm[i].type == 0)
{
// 边框
fillroundrect (boxm[i].posx1, boxm[i].posy1, boxm[i].posx2, boxm[i].posy2, 25, 25);
// 文字
outtextxy (boxm[i].posx1 + (boxm[i].posx2 - boxm[i].posx1) / 2 - textwidth (boxm[i].text) / 2, boxm[i].posy1 + 15, boxm[i].text);
}
}
FlushBatchDraw ();
}
////////////////////////////// 准备进程源文件 //////////////////////////////
// 准备进程主循函数
void game::carry_prepare ()
{
int i;
// 鼠标定义
ExMessage m;
// 准备进程控制参数初始化
int exit_prepare = 0;
// 绘制界面
draw_scene_prepare ();
// 主循开始
while (exit_prepare == 0)
{
if (peekmessage (&m, EM_MOUSE | EM_KEY))
{
// 左键单击判断
if (m.message == WM_LBUTTONDOWN)
{
// 判断是否点击了按钮,按钮状态是否为激活
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].type == 0)
{
break;
}
}
// 开始游戏按钮
if (i == 0 || i == 1 || i == 3)
{
// 游戏类型储存
mod_start = i;
// 准备进程控制参数置一,结束主循
exit_prepare = 1;
// 开始进程控制参数置零,进入开始进程
exit_start = 0;
}
// 退出按钮
else if (i == 2)
{
// 总进程控制参数置一,跳过开始进程
exit_carry = 1;
// 准备进程控制参数置一,结束主循
exit_prepare = 1;
}
if (i < 3 && exit_prepare == 0)
{
// 点击按钮后,根据按钮激活参数,重新绘制界面
draw_scene_prepare ();
FlushBatchDraw ();
}
}
}
}
}
// 准备进程初始化函数
void game::initialization_prepare ()
{
// 按钮设置初始化
// 按钮数量参数初始化
num_button = 3;
// 按钮结构体参数初始化
boxm[0].posx1 = 140; boxm[0].posy1 = 120; boxm[0].posx2 = 310; boxm[0].posy2 = 180; boxm[0].text = _T ("无尽模式"); boxm[0].type = 0;
boxm[1].posx1 = 140; boxm[1].posy1 = 220; boxm[1].posx2 = 310; boxm[1].posy2 = 280; boxm[1].text = _T ("闯关模式"); boxm[1].type = 0;
boxm[2].posx1 = 140; boxm[2].posy1 = 420; boxm[2].posx2 = 310; boxm[2].posy2 = 480; boxm[2].text = _T ("退出"); boxm[2].type = 0;
}
// 准备进程绘制函数
void game::draw_scene_prepare ()
{
// 画布绘制
setbkcolor (WHITE);
cleardevice ();
// 按钮绘制
draw_button ();
// 标题绘制
draw_word (50, 130, 30, _T ("象棋马拉松"));
FlushBatchDraw ();
}
// 文字绘制函数
void game::draw_word (double size, int posx, int posy, LPTSTR text)
{
int i, j;
// 参数设置,填充透明
setbkmode (TRANSPARENT);
settextstyle (int (size), int (size / 5 * 2), _T ("Consolas"));
// 背景色的反色
settextcolor (BLACK);
// 范围绘制,构造阴影
for (i = posx - 3; i <= posx + 3; i++)
{
for (j = posy - 3; j <= posy + 3; j++)
{
outtextxy (i, j, text);
}
}
// 背景色
settextcolor (WHITE);
// 在阴影中绘制
outtextxy (posx, posy, text);
// 恢复填充
setbkmode (OPAQUE);
FlushBatchDraw ();
}
////////////////////////////// 开始进程源文件 //////////////////////////////
// 开始进程主循函数
void game::carry_start ()
{
// 鼠标定义
ExMessage m;
int i, j, k, x, y, a;
// 判断一下,避免返回不初始化格子判断参数
check_main ();
// 记录初始化
start_record = 0;
start_eat = 0;
// 是否选定参数
selected_or_not = 0;
// 生命初始化,无尽模式初始一条命
start_life = 1;
// 绘制
draw_scene_start ();
// 无尽模式
while (exit_start == 0 && mod_start == 0)
{
if (peekmessage (&m, EM_MOUSE | EM_KEY))
{
// 左键单击判断
if (m.message == WM_LBUTTONDOWN)
{
if (m.x < 350)
{
i = m.x / 50 + m.y / 50 * 7 + 7;
// 是否是可抵达位置
if (box1[i / 7][i % 7].type == 1)
{
// 交换落点
if (box[i / 7][i % 7].type == 1) { start_eat++; }
box[i / 7][i % 7].type = box[flag / 7][flag % 7].type;
box[i / 7][i % 7].text = box[flag / 7][flag % 7].text;
box[i / 7][i % 7].piecenum = box[flag / 7][flag % 7].piecenum;
box[i / 7][i % 7].color = box[flag / 7][flag % 7].color;
box[flag / 7][flag % 7].type = 0;
flag = i;
// 是否是安全位置
// 安全位置
if (box2[i / 7][i % 7].type == 0)
{
// 移动视角
if (i / 7 < 11)
{
x = 11 - i / 7;
start_record += x;
for (j = 13; j >= 0; j--)
{
for (k = 0; k < 7; k++)
{
if (box[j][k].type != 0)
{
box[j + x][k].type = box[j][k].type;
box[j + x][k].text = box[j][k].text;
box[j + x][k].piecenum = box[j][k].piecenum;
box[j + x][k].color = box[j][k].color;
box[j][k].type = 0;
}
}
}
flag += x * 7;
creact_piece (0);
// 移动视角后的卷屏动画
// 棋子已经整体下移 x 行了,要把格子整体上移 x 行,慢慢向原值靠拢
a = tip_or_not;
tip_or_not = 0;
for (y = x * 50; y >= 0; y -= 50)
{
for (k = 0; k < 16; k++)
{
for (j = 0; j < 7; j++)
{
box[k][j].posy = -25 + 50 * k - y;
}
}
draw_scene_start ();
Sleep (200);
}
tip_or_not = a;
}
// 清理棋子
for (j = 0; j < 7; j++)
{
box[14][j].type = 0;
box[15][j].type = 0;
}
// 重新判断
check_main ();
}
// 危险位置
else if (box2[i / 7][i % 7].type == 1)
{
// 失败动画
tip_or_not = 1;
for (k = 0; k < 5; k++)
{
box[i / 7][i % 7].type = 0;
draw_scene_start ();
Sleep (200);
box[i / 7][i % 7].type = 2;
draw_scene_start ();
Sleep (200);
}
exit_start = 1;
}
draw_scene_start ();
}
}
else
{
// 判断是否点击了按钮
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].type == 0)
{
break;
}
}
if (i == 0)
{
exit_start = 1;
}
}
}
// 右键打开提示
else if (m.message == WM_RBUTTONDOWN)
{
tip_or_not = tip_or_not == 0 ? 1 : 0;
draw_scene_start ();
}
}
}
// 生命初始化,闯关模式初始三条命
start_life = 3;
// 绘制
draw_scene_start ();
// 闯关模式
while (exit_start == 0 && mod_start == 1)
{
if (peekmessage (&m, EM_MOUSE | EM_KEY))
{
// 左键单击判断
if (m.message == WM_LBUTTONDOWN)
{
if (m.x < 350)
{
i = m.x / 50 + m.y / 50 * 7 + 7;
// 未选定状态,点击自己的棋子
if (selected_or_not == 0 && box[i / 7][i % 7].type == 2)
{
selected_or_not = 1;
flag = i;
// 更换棋子类型
for (k = 0; k < 16; k++)
{
for (j = 0; j < 7; j++)
{
if (box[k][j].type == 2)
{
box[k][j].type = 3;
}
}
}
box[flag / 7][flag % 7].type = 2;
check_main ();
draw_scene_start ();
}
// 选定状态,点击选定的棋子
else if (selected_or_not == 1 && i == flag)
{
selected_or_not = 0;
for (k = 0; k < 16; k++)
{
for (j = 0; j < 7; j++)
{
if (box[k][j].type == 3)
{
box[k][j].type = 2;
}
}
}
check_main ();
draw_scene_start ();
}
// 选定状态,点击其他的己方棋子,切换选择
else if (selected_or_not == 1 && box[i / 7][i % 7].type == 3)
{
box[i / 7][i % 7].type = 2;
box[flag / 7][flag % 7].type = 3;
flag = i;
check_main ();
draw_scene_start ();
}
// 选定状态,点击其他的格子
else if (selected_or_not == 1 && i != flag)
{
// 是否是可抵达位置
if (box1[i / 7][i % 7].type == 1)
{
selected_or_not = 0;
// 交换落点
if (box[i / 7][i % 7].type == 1) { start_eat++; }
box[i / 7][i % 7].type = box[flag / 7][flag % 7].type;
box[i / 7][i % 7].text = box[flag / 7][flag % 7].text;
box[i / 7][i % 7].piecenum = box[flag / 7][flag % 7].piecenum;
box[i / 7][i % 7].color = box[flag / 7][flag % 7].color;
box[flag / 7][flag % 7].type = 0;
for (k = 0; k < 16; k++)
{
for (j = 0; j < 7; j++)
{
if (box[k][j].type == 3)
{
box[k][j].type = 2;
}
}
}
// 重新判断
check_main ();
// 是否成功过关,三个子都抵达最上面
x = 0;
for (k = 0; k < 16; k++)
{
for (j = 0; j < 7; j++)
{
if (box[k][j].type == 2 && k > 1)
{
x = 1;
}
}
}
// 三个字在不在危险位置
for (k = 0; k < 16; k++)
{
for (j = 0; j < 7; j++)
{
if (box[k][j].type == 2 && box2[k][j].type == 1 && x == 1)
{
tip_or_not = 1;
// 失败动画
for (y = 0; y < 5; y++)
{
box[k][j].type = 0;
draw_scene_start ();
Sleep (200);
box[k][j].type = 2;
draw_scene_start ();
Sleep (200);
}
tip_or_not = 0;
// 减生命
start_life--;
// 生命减没了,结束
if (start_life == 0)
{
exit_start = 1;
}
}
}
}
draw_scene_start ();
// 成功过关
if (x == 0)
{
start_record += 1;
start_life++;
// 初始化
initialization_start ();
// 不出现两个子及以上同时危险的情况
y = 0;
if (box2[11][1].type == 1) { y++; }
if (box2[11][3].type == 1) { y++; }
if (box2[11][5].type == 1) { y++; }
while (y >= 2)
{
// 初始化
initialization_start ();
y = 0;
if (box2[11][1].type == 1) { y++; }
if (box2[11][3].type == 1) { y++; }
if (box2[11][5].type == 1) { y++; }
}
}
}
draw_scene_start ();
}
}
else
{
// 判断是否点击了按钮
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].type == 0)
{
break;
}
}
// 返回按钮
if (i == 0)
{
exit_start = 1;
}
// 刷新按钮
else if (i == 1)
{
// 初始化
initialization_start ();
// 不出现两个子及以上同时危险的情况
y = 0;
if (box2[11][1].type == 1) { y++; }
if (box2[11][3].type == 1) { y++; }
if (box2[11][5].type == 1) { y++; }
while (y >= 2)
{
// 初始化
initialization_start ();
y = 0;
if (box2[11][1].type == 1) { y++; }
if (box2[11][3].type == 1) { y++; }
if (box2[11][5].type == 1) { y++; }
}
// 重新绘制
draw_scene_start ();
}
}
}
// 右键切换提示
else if (m.message == WM_RBUTTONDOWN)
{
tip_or_not = tip_or_not == 0 ? 1 : 0;
check_main ();
draw_scene_start ();
}
}
}
flushmessage (EM_MOUSE);
}
// 开始进程初始化函数
void game::initialization_start ()
{
int i, j, k;
// 格子初始化
for (i = 0; i < 16; i++)
{
for (j = 0; j < 7; j++)
{
box[i][j].boxnum = i * 7 + j;
box[i][j].color = WHITE;
box[i][j].piecenum = 0;
box[i][j].text = _T ("");
box[i][j].posx = 25 + 50 * j;
box[i][j].posy = -25 + 50 * i;
box[i][j].type = 0;
}
}
// 提示参数初始化
tip_or_not = 0;
// 无尽模式
if (mod_start == 0)
{
box[11][3].type = 2;
box[11][3].piecenum = 3;
box[11][3].text = _T ("马");
box[11][3].color = RED;
flag = 80;
creact_piece (1);
// 判断初始化
check_main ();
}
// 闯关模式
else if (mod_start == 1)
{
k = 2;
while (k >= 2)
{
// 格子初始化
for (i = 0; i < 16; i++)
{
for (j = 0; j < 7; j++)
{
box[i][j].color = WHITE;
box[i][j].piecenum = 0;
box[i][j].text = _T ("");
box[i][j].type = 0;
}
}
// 红色车马炮
box[11][1].type = 2;
box[11][1].piecenum = 4;
box[11][1].text = _T ("车");
box[11][1].color = RED;
box[11][3].type = 2;
box[11][3].piecenum = 3;
box[11][3].text = _T ("马");
box[11][3].color = RED;
box[11][5].type = 2;
box[11][5].piecenum = 6;
box[11][5].text = _T ("炮");
box[11][5].color = RED;
flag = 82;
// 黑色障碍
for (i = 1; i < 6; i++)
{
creact_piece (i);
creact_piece (i);
}
// 判断初始化
check_main ();
k = 0;
if (box2[11][1].type == 1) { k++; }
if (box2[11][3].type == 1) { k++; }
if (box2[11][5].type == 1) { k++; }
}
}
// 按钮设置初始化
num_button = 2;
boxm[0].posx1 = 360; boxm[0].posy1 = 120; boxm[0].posx2 = 440; boxm[0].posy2 = 180; boxm[0].text = _T ("返回"); boxm[0].type = 0;
boxm[1].posx1 = 360; boxm[1].posy1 = 220; boxm[1].posx2 = 440; boxm[1].posy2 = 280; boxm[1].text = _T ("刷新"); boxm[1].type = 1;
// 闯关模式则打开刷新按钮
if (mod_start == 1) { boxm[1].type = 0; }
}
// 开始进程绘制函数
void game::draw_scene_start ()
{
int i, j;
// 背景绘制
draw_bk ();
// 绘制按钮
draw_button ();
// 棋子绘制
for (i = 0; i < 16; i++)
{
for (j = 0; j < 7; j++)
{
if (box[i][j].type != 0)
{
draw_piece (box[i][j].posx, box[i][j].posy, box[i][j].text, box[i][j].color);
}
}
}
if (tip_or_not == 1)
{
draw_tip ();
}
// 闯关模式,选定状态,显示小箭头
if (mod_start == 1 && selected_or_not == 1)
{
i = flag / 7;
j = flag % 7;
setlinecolor (RED);
setlinestyle (PS_SOLID, 2);
line (box[i][j].posx + 20, box[i][j].posy + 20, box[i][j].posx + 26, box[i][j].posy + 26);
line (box[i][j].posx + 20, box[i][j].posy + 20, box[i][j].posx + 20, box[i][j].posy + 26);
line (box[i][j].posx + 20, box[i][j].posy + 20, box[i][j].posx + 26, box[i][j].posy + 20);
line (box[i][j].posx + 20, box[i][j].posy - 20, box[i][j].posx + 26, box[i][j].posy - 26);
line (box[i][j].posx + 20, box[i][j].posy - 20, box[i][j].posx + 20, box[i][j].posy - 26);
line (box[i][j].posx + 20, box[i][j].posy - 20, box[i][j].posx + 26, box[i][j].posy - 20);
line (box[i][j].posx - 20, box[i][j].posy + 20, box[i][j].posx - 26, box[i][j].posy + 26);
line (box[i][j].posx - 20, box[i][j].posy + 20, box[i][j].posx - 20, box[i][j].posy + 26);
line (box[i][j].posx - 20, box[i][j].posy + 20, box[i][j].posx - 26, box[i][j].posy + 20);
line (box[i][j].posx - 20, box[i][j].posy - 20, box[i][j].posx - 26, box[i][j].posy - 26);
line (box[i][j].posx - 20, box[i][j].posy - 20, box[i][j].posx - 20, box[i][j].posy - 26);
line (box[i][j].posx - 20, box[i][j].posy - 20, box[i][j].posx - 26, box[i][j].posy - 20);
}
// 文字绘制
TCHAR s[20];
// 记录
if (start_record > 0) { draw_word (30, 350, 380, _T ("记录:")); }
_stprintf_s (s, _T ("%0.0d"), start_record);
draw_word (30, 410, 380, s);
// 食子
if (start_eat > 0) { draw_word (30, 350, 430, _T ("食子:")); }
_stprintf_s (s, _T ("%0.0d"), start_eat);
draw_word (30, 410, 430, s);
// 生命
if (start_life > 0) { draw_word (30, 350, 480, _T ("生命:")); }
_stprintf_s (s, _T ("%0.0d"), start_life);
draw_word (30, 410, 480, s);
FlushBatchDraw ();
}
// 背景绘制函数
void game::draw_bk ()
{
// 填充
int i = 225;
setbkcolor (RGB (215 - 45.0 / 180.0 * double (i), 161 - 39.0 / 180.0 * double (i), 114 - 32.0 / 180.0 * double (i)));
cleardevice ();
// 底色
for (i = 225; i > 0; i--)
{
setlinecolor (RGB (215 - 45.0 / 180.0 * double (i), 161 - 39.0 / 180.0 * double (i), 114 - 32.0 / 180.0 * double (i)));
setfillcolor (RGB (215 - 45.0 / 180.0 * double (i), 161 - 39.0 / 180.0 * double (i), 114 - 32.0 / 180.0 * double (i)));
fillcircle (175, 325, 145 + i);
}
// 底色
for (i = 0; i < 145; i++)
{
setlinecolor (RGB (215 + 10.0 / 145.0 * double (i), 161 + 7.0 / 145.0 * double (i), 114 + 5.0 / 145.0 * double (i)));
setfillcolor (RGB (215 + 10.0 / 145.0 * double (i), 161 + 7.0 / 145.0 * double (i), 114 + 5.0 / 145.0 * double (i)));
fillcircle (175, 325, 145 - i);
}
// 格子线
setlinestyle (PS_SOLID, 3);
setlinecolor (RGB (154, 101, 49));
// 横线
for (i = 0; i < 13; i++)
{
line (25, 25 + 50 * i, 325, 25 + 50 * i);
}
if (mod_start == 1)
{
i = 0;
setlinecolor (YELLOW);
line (25, 25 + 50 * i, 325, 25 + 50 * i);
}
// 竖线
setlinecolor (RGB (154, 101, 49));
for (i = 0; i < 7; i++)
{
line (25 + 50 * i, 0, 25 + 50 * i, 650);
}
line (15, 0, 15, 650);
line (335, 0, 335, 650);
FlushBatchDraw ();
}
// 判断主函数
void game::check_main ()
{
int i, j, k, x, y;
// 临时储存两个结构体的值
int eat1[16][7], eat2[16][7];
// 参数重置
for (i = 0; i < 16; i++)
{
for (j = 0; j < 7; j++)
{
box1[i][j].type = 0;
box2[i][j].type = 0;
}
}
// 先整体判断一次
check ();
// 存起来
for (i = 0; i < 16; i++)
{
for (j = 0; j < 7; j++)
{
eat1[i][j] = box1[i][j].type;
eat2[i][j] = box2[i][j].type;
}
}
// 纠正,对两个值都是一的格子进行纠正,每个格子,要么是可抵达且安全,要么是危险
// 纠正的原因是“炮”子导致的
if (selected_or_not == 1)
{
for (i = 0; i < 16; i++)
{
for (j = 0; j < 7; j++)
{
// 对可抵达且危险的格子进行纠正
if (eat1[i][j] == 1 && eat2[i][j] == 1)
{
// 先假设选定棋子(flag)走到该格
k = box[i][j].type;
box[i][j].type = 2;
box[flag / 7][flag % 7].type = 0;
// 参数重置
for (x = 0; x < 16; x++)
{
for (y = 0; y < 7; y++)
{
box1[x][y].type = 0;
box2[x][y].type = 0;
}
}
// 重新判断
check ();
// 依旧是危险格,则是危险,但不改变可抵达状态
if (box2[i][j].type == 1)
{
// 若改变为不可抵达,则不能落子到危险格了,避免了操作失误
// eat1[i][j]=0;
}
// 否则就是安全格
else
{
eat2[i][j] = 0;
}
// 棋子还原
box[i][j].type = k;
box[flag / 7][flag % 7].type = 2;
}
}
}
// 纠正,反取
for (i = 0; i < 16; i++)
{
for (j = 0; j < 7; j++)
{
box1[i][j].type = eat1[i][j];
box2[i][j].type = eat2[i][j];
}
}
}
}
// 判定落点,安全点函数
void game::check ()
{
int i, j, k;
for (i = 1; i < 14; i++)
{
for (j = 0; j < 7; j++)
{
if (box[i][j].type == 1)
{
switch (box[i][j].piecenum)
{
// 兵
case 1:
{
// 下方
box2[i + 1][j].type = 1;
// 左方
if (j > 0) { box2[i][j - 1].type = 1; }
// 右方
if (j < 6) { box2[i][j + 1].type = 1; }
break;
}
// 相
case 2:
{
// 不能憋象腿,四角
if ((j) > 1 && box[i - 1][j - 1].type == 0) { box2[i - 2][j - 2].type = 1; }
if ((j) > 1 && box[i + 1][j - 1].type == 0) { box2[i + 2][j - 2].type = 1; }
if ((j) < 5 && box[i - 1][j + 1].type == 0) { box2[i - 2][j + 2].type = 1; }
if ((j) < 5 && box[i + 1][j + 1].type == 0) { box2[i + 2][j + 2].type = 1; }
break;
}
// 马
case 3:
{
// 不能憋马腿,八角
if (j > 1 && box[i][j - 1].type == 0) { box2[i - 1][j - 2].type = 1; box2[i + 1][j - 2].type = 1; }
if (j < 5 && box[i][j + 1].type == 0) { box2[i - 1][j + 2].type = 1; box2[i + 1][j + 2].type = 1; }
if (box[i - 1][j].type == 0 && j > 0) { box2[i - 2][j - 1].type = 1; }
if (box[i - 1][j].type == 0 && j < 6) { box2[i - 2][j + 1].type = 1; }
if (box[i + 1][j].type == 0 && j > 0) { box2[i + 2][j - 1].type = 1; }
if (box[i + 1][j].type == 0 && j < 6) { box2[i + 2][j + 1].type = 1; }
break;
}
// 车
case 4:
{
// 四条直线,阻碍则止
// 左
k = j;
while ((k - 1) >= 0 && box[i][k - 1].type != 1) { box2[i][k - 1].type = 1; k--; }
if ((k - 1) >= 0 && box[i][k - 1].type == 1) { box2[i][k - 1].type = 1; }
// 右
k = j;
while ((k + 1) <= 6 && box[i][k + 1].type != 1) { box2[i][k + 1].type = 1; k++; }
if ((k + 1) <= 6 && box[i][k + 1].type == 1) { box2[i][k + 1].type = 1; }
// 上
k = i;
while ((k - 1) >= 0 && box[k - 1][j].type != 1) { box2[k - 1][j].type = 1; k--; }
if ((k - 1) >= 0 && box[k - 1][j].type == 1) { box2[k - 1][j].type = 1; }
// 下
k = i;
while ((k + 1) <= 13 && box[k + 1][j].type != 1) { box2[k + 1][j].type = 1; k++; }
if ((k + 1) <= 13 && box[k + 1][j].type == 1) { box2[k + 1][j].type = 1; }
break;
}
// 士
case 5:
{
// 四角
if (j > 0) { box2[i + 1][j - 1].type = 1; box2[i - 1][j - 1].type = 1; }
if (j < 6) { box2[i + 1][j + 1].type = 1; box2[i - 1][j + 1].type = 1; }
break;
}
// 炮
case 6:
{
// 架炮后与车一样
// 四条直线,遇阻碍则开始,再遇则结束
// 左
k = j;
while ((k - 1) >= 0 && box[i][k - 1].type == 0) { k--; }
if ((k - 1) >= 0 && box[i][k - 1].type != 0)
{
k--;
while ((k - 1) >= 0 && box[i][k - 1].type != 1) { box2[i][k - 1].type = 1; k--; }
if ((k - 1) >= 0 && box[i][k - 1].type == 1) { box2[i][k - 1].type = 1; }
}
// 右
k = j;
while ((k + 1) <= 6 && box[i][k + 1].type == 0) { k++; }
if ((k + 1) <= 6 && box[i][k + 1].type != 0)
{
k++;
while ((k + 1) <= 6 && box[i][k + 1].type != 1) { box2[i][k + 1].type = 1; k++; }
if ((k + 1) <= 6 && box[i][k + 1].type == 1) { box2[i][k + 1].type = 1; }
}
// 上
k = i;
while ((k - 1) >= 0 && box[k - 1][j].type == 0) { k--; }
if ((k - 1) >= 0 && box[k - 1][j].type != 0)
{
k--;
while ((k - 1) >= 0 && box[k - 1][j].type != 1) { box2[k - 1][j].type = 1; k--; }
if ((k - 1) >= 0 && box[k - 1][j].type == 1) { box2[k - 1][j].type = 1; }
}
// 下
k = i;
while ((k + 1) <= 13 && box[k + 1][j].type == 0) { k++; }
if ((k + 1) <= 13 && box[k + 1][j].type != 0)
{
k++;
while ((k + 1) <= 13 && box[k + 1][j].type != 1) { box2[k + 1][j].type = 1; k++; }
if ((k + 1) <= 13 && box[k + 1][j].type == 1) { box2[k + 1][j].type = 1; }
}
break;
}
default:break;
}
}
else if (box[i][j].type == 2)
{
switch (box[i][j].piecenum)
{
// 兵
case 1:
{
// 下方
box1[i - 1][j].type = 1;
// 左方
if (j > 0) { box1[i][j - 1].type = 1; }
// 右方
if (j < 6) { box1[i][j + 1].type = 1; }
break;
}
// 相
case 2:
{
// 不能憋象腿,四角
if ((j) > 1 && box[i - 1][j - 1].type == 0) { box1[i - 2][j - 2].type = 1; }
if ((j) > 1 && box[i + 1][j - 1].type == 0) { box1[i + 2][j - 2].type = 1; }
if ((j) < 5 && box[i - 1][j + 1].type == 0) { box1[i - 2][j + 2].type = 1; }
if ((j) < 5 && box[i + 1][j + 1].type == 0) { box1[i + 2][j + 2].type = 1; }
break;
}
// 马
case 3:
{
// 不能憋马腿,八角
if (j > 1 && box[i][j - 1].type == 0) { box1[i - 1][j - 2].type = 1; box1[i + 1][j - 2].type = 1; }
if (j < 5 && box[i][j + 1].type == 0) { box1[i - 1][j + 2].type = 1; box1[i + 1][j + 2].type = 1; }
if (box[i - 1][j].type == 0 && j > 0) { box1[i - 2][j - 1].type = 1; }
if (box[i - 1][j].type == 0 && j < 6) { box1[i - 2][j + 1].type = 1; }
if (box[i + 1][j].type == 0 && j > 0) { box1[i + 2][j - 1].type = 1; }
if (box[i + 1][j].type == 0 && j < 6) { box1[i + 2][j + 1].type = 1; }
break;
}
// 车
case 4:
{
// 四条直线,阻碍则止
// 左
k = j;
while ((k - 1) >= 0 && box[i][k - 1].type == 0) { box1[i][k - 1].type = 1; k--; }
if ((k - 1) >= 0 && box[i][k - 1].type == 1) { box1[i][k - 1].type = 1; }
// 右
k = j;
while ((k + 1) <= 6 && box[i][k + 1].type == 0) { box1[i][k + 1].type = 1; k++; }
if ((k + 1) <= 6 && box[i][k + 1].type == 1) { box1[i][k + 1].type = 1; }
// 上
k = i;
while ((k - 1) >= 0 && box[k - 1][j].type == 0) { box1[k - 1][j].type = 1; k--; }
if ((k - 1) >= 0 && box[k - 1][j].type == 1) { box1[k - 1][j].type = 1; }
// 下
k = i;
while ((k + 1) <= 13 && box[k + 1][j].type == 0) { box1[k + 1][j].type = 1; k++; }
if ((k + 1) <= 13 && box[k + 1][j].type == 1) { box1[k + 1][j].type = 1; }
break;
}
// 士
case 5:
{
// 四角
if (j > 0) { box1[i + 1][j - 1].type = 1; box1[i - 1][j - 1].type = 1; }
if (j < 6) { box1[i + 1][j + 1].type = 1; box1[i - 1][j + 1].type = 1; }
break;
}
// 炮
case 6:
{
// 架炮前与车一样
// 四条直线,阻碍则可以打下一个阻碍
// 左
k = j;
while ((k - 1) >= 0 && box[i][k - 1].type == 0) { box1[i][k - 1].type = 1; k--; }
if ((k - 1) >= 0 && box[i][k - 1].type != 0)
{
k--;
while ((k - 1) >= 0 && box[i][k - 1].type == 0) { k--; }
if ((k - 1) >= 0 && box[i][k - 1].type == 1)
{
box1[i][k - 1].type = 1;
}
}
// 右
k = j;
while ((k + 1) <= 6 && box[i][k + 1].type == 0) { box1[i][k + 1].type = 1; k++; }
if ((k + 1) <= 6 && box[i][k + 1].type != 0)
{
k++;
while ((k + 1) <= 6 && box[i][k + 1].type == 0) { k++; }
if ((k + 1) <= 6 && box[i][k + 1].type == 1)
{
box1[i][k + 1].type = 1;
}
}
// 上
k = i;
while ((k - 1) >= 0 && box[k - 1][j].type == 0) { box1[k - 1][j].type = 1; k--; }
if ((k - 1) >= 0 && box[k - 1][j].type != 0)
{
k--;
while ((k - 1) >= 0 && box[k - 1][j].type == 0) { k--; }
if ((k - 1) >= 0 && box[k - 1][j].type == 1)
{
box1[k - 1][j].type = 1;
}
}
// 下
k = i;
while ((k + 1) <= 13 && box[k + 1][j].type == 0) { box1[k + 1][j].type = 1; k++; }
if ((k + 1) <= 13 && box[k + 1][j].type != 0)
{
k++;
while ((k + 1) <= 13 && box[k + 1][j].type == 0) { k++; }
if ((k + 1) <= 13 && box[k + 1][j].type == 1)
{
box1[k + 1][j].type = 1;
}
}
break;
}
default:break;
}
}
}
}
}
// 提示绘制函数
void game::draw_tip ()
{
int i, j;
for (i = 1; i < 14; i++)
{
for (j = 0; j < 7; j++)
{
// 是可达位,或危险位
if (box2[i][j].type == 1 || box1[i][j].type == 1)
{
// 优先危险显示
if (box2[i][j].type == 1)
{
setlinecolor (BLACK);
}
// 可抵达显示
else if (box1[i][j].type == 1)
{
setlinecolor (LIGHTGREEN);
}
setlinestyle (PS_SOLID, 2);
// 空位显示架空十字架
if (box[i][j].type == 0)
{
line (box[i][j].posx + 5, box[i][j].posy + 5, box[i][j].posx + 5, box[i][j].posy + 10);
line (box[i][j].posx + 5, box[i][j].posy + 5, box[i][j].posx + 10, box[i][j].posy + 5);
line (box[i][j].posx + 5, box[i][j].posy - 5, box[i][j].posx + 5, box[i][j].posy - 10);
line (box[i][j].posx + 5, box[i][j].posy - 5, box[i][j].posx + 10, box[i][j].posy - 5);
line (box[i][j].posx - 5, box[i][j].posy + 5, box[i][j].posx - 5, box[i][j].posy + 10);
line (box[i][j].posx - 5, box[i][j].posy + 5, box[i][j].posx - 10, box[i][j].posy + 5);
line (box[i][j].posx - 5, box[i][j].posy - 5, box[i][j].posx - 5, box[i][j].posy - 10);
line (box[i][j].posx - 5, box[i][j].posy - 5, box[i][j].posx - 10, box[i][j].posy - 5);
}
// 非空位显示小方框
else
{
line (box[i][j].posx + 15, box[i][j].posy + 15, box[i][j].posx + 15, box[i][j].posy + 10);
line (box[i][j].posx + 15, box[i][j].posy + 15, box[i][j].posx + 10, box[i][j].posy + 15);
line (box[i][j].posx + 15, box[i][j].posy - 15, box[i][j].posx + 15, box[i][j].posy - 10);
line (box[i][j].posx + 15, box[i][j].posy - 15, box[i][j].posx + 10, box[i][j].posy - 15);
line (box[i][j].posx - 15, box[i][j].posy + 15, box[i][j].posx - 15, box[i][j].posy + 10);
line (box[i][j].posx - 15, box[i][j].posy + 15, box[i][j].posx - 10, box[i][j].posy + 15);
line (box[i][j].posx - 15, box[i][j].posy - 15, box[i][j].posx - 15, box[i][j].posy - 10);
line (box[i][j].posx - 15, box[i][j].posy - 15, box[i][j].posx - 10, box[i][j].posy - 15);
}
}
}
}
FlushBatchDraw ();
}
// 棋子绘制
void game::draw_piece (int posx, int posy, LPTSTR text, COLORREF color)
{
int i, j;
setlinestyle (PS_SOLID, 1);
// 阴影
setlinecolor (RGB (121, 75, 52));
setfillcolor (RGB (121, 75, 52));
fillcircle (posx, posy + 7, 20);
// 侧面
setlinecolor (RGB (212, 158, 111));
setfillcolor (RGB (212, 158, 111));
for (i = 0; i < 3; i++)
{
fillcircle (posx, posy + i + 4, 18);
}
// 正面
setlinecolor (RGB (246, 203, 155));
setfillcolor (RGB (246, 203, 155));
fillcircle (posx, posy, 15);
// 刻字
setlinecolor (color);
setlinestyle (PS_SOLID, 2);
setfillstyle (BS_NULL);
fillcircle (posx, posy, 14);
setfillstyle (BS_SOLID);
settextcolor (color);
setbkmode (TRANSPARENT);
settextstyle (22, 11, _T ("Consolas"));
for (i = 0; i < 1; i++)
{
for (j = 0; j < 2; j++)
{
outtextxy (posx - 10 + i, posy - 10 + j, text);
}
}
setbkmode (OPAQUE);
FlushBatchDraw ();
}
// 棋子生成函数,已知行数
void game::creact_piece (int floor)
{
int i, k;
// 随机列数
do
{
i = rand () % 7;
} while (box[floor][i].type != 0);
box[floor][i].type = 1;
box[floor][i].color = BLACK;
// 随机棋子
k = rand () % 6 + 1;
box[floor][i].piecenum = k;
switch (k)
{
case 1:box[floor][i].text = _T ("兵"); break;
case 2:box[floor][i].text = _T ("相"); break;
case 3:box[floor][i].text = _T ("马"); break;
case 4:box[floor][i].text = _T ("车"); break;
case 5:box[floor][i].text = _T ("士"); break;
case 6:box[floor][i].text = _T ("炮"); break;
case 7:box[floor][i].text = _T (""); break;
default:break;
}
}