用VS软件开发“中国象棋“游戏<笔记摘录>

news/2024/3/29 0:40:21/文章来源:https://blog.csdn.net/Lukegood/article/details/128096856

 整体架构如上

1.很直观地去看这个中国象棋的界面,数一下它有多少行和多少列.

10行,9列:要注意这里数的是安放象棋的位置,有10行9列

这里我们首先想到的必然是二维数组,每一个行列交叉的点都设置成二维数组a[i][j]这样的格式,以此来确定棋盘上面每一个棋子的位置和走向.

我们把上面安放棋子的二维数组定义成一个地图,也就是map[i][j]的格式,但同时要注意,每一个象棋棋子都有行,列,颜色,是否过河和名称(也就是什么棋子)几种定义区分.

那么这里我们就需要把棋子定义成一个结构.如下:

struct  Chesscoordinate//棋子综合信息
{int x;int y;DWORD type;  //颜色bool river;//是否过河int id;
};

当定义了棋子综合信息,我们是不是需要每一个信息都拓展一下?

x代表的是在棋盘上面的列,也就是竖行,y代表的是棋子在棋盘上面的行,也就是横线,而type代表的棋子的颜色,棋子颜色可以分为黑色和红色两种;river设置成bool型的,只需要判断棋子是否过河就可以了.最后id定义的是棋子上面的名称,比如将,帅等.

接下来我们就来VS当中进行棋子的程序定义拓展:

#define distance  35//窗口线与棋盘边界线的距离
#define   longth  65//棋盘方格的长
#define   high   61//棋盘方格的宽

distance longth 和high我们都把其设置成宏,这个就要回溯到棋盘上面,把棋盘假设成一个xy的二维坐标,那么要定义每一个棋子的位置,或者说是每一行与每一列的交叉点,就要用到上面三个宏定义.

比如左上角第一个棋子的坐标可以表示为:

map[0][0].x=distance;

map[0][0].y=distance

而第一行第二个棋子的坐标可以表示为:

map[1][0].x=distance+longth;

map[1][0].y=distance

依次类推......

int  xx(int a)//数组下标转换成坐标
{a = distance + longth * a;return a;
}
int  yy(int a)
{a = distance + high * a;return a;
}

我们可以推断出每一个棋子的坐标,都可以通过上面几个宏定义以及棋子的实际行列表示出来,

enum pieces
{SPACE = -1,車, 馬, 象, 士, 将, 炮, 卒,车, 马, 相, 仕, 帥, 砲, 兵,BEGIN, END,};
enum pieces redchess[] = { 車,馬,象,士,将,炮,卒, };
enum pieces blackchess[] = { 车,马,相,仕,帥,砲,兵, };
enum pieces state = BEGIN;
struct move {  //鼠标选中的棋子int beginx;int beginy;int endx;int endy;int state;
}moving = { -1,-1,-1,-1,BEGIN };
const char* chessname[] = { "車","馬","象","士","将","炮","卒","车","马","相","仕","帥","砲","兵", };

这里我们把棋子的id设置成一个联合结构数组,因为里面的棋子的id都基本不同,同时我们考虑到了棋子要进行运动,把棋子的开始状态设置为BEGIN

而新建一个move的结构,表示鼠标选中棋子的基本信息.begin的行列和结束的行列和运行状态.

最后回到棋子id上面,我们是不是需要把这些id都设置到棋子或者棋盘上面啊,采用常量字符数组的形式,把棋盘上面所有的棋子都表示出来.

而把刚才的map[i][j]二维数组同样定义成一个二维结构数组.如下:

struct Chesscoordinate  map[9][10];//坐标
struct Chesscoordinate  AImap[9][10];//坐标

同时,我们设置了AImap[i][j]的二维结构数组,看看是否下面在进行棋子移动的时候,我们会用到.

这里i=9,j=10是根据我们上面看中国象棋棋盘得到的数据.

2.我们要开始加载图片信息了,把我们已经有的棋盘素材放在同文件下面,然后采用下面程序,就可以在窗口当中显示出中国棋盘的背景图.

void begining()
{loadimage(&img, "D:/program/Project3-chess successful/1.png");initgraph(img.getwidth(), img.getheight(), 1); //初始化图形系统putimage(0, 0, &img);//输出开始界面;

至于,loadimage()和initgraph()函数以及putimage()函数三者的基本理解和解释,建议去搜索,都有比较详细的解释.这里我们解释一下initgraph()函数的基本含义:

这个函数用于初始化绘图环境。

HWND initgraph(int width,int height,int flag = NULL
);

参数:

width   绘图环境的宽度。

height   绘图环境的高度。

flag  绘图环境的样式,默认为 NULL。

上面程序的基本思路也就不言而喻:先加载或者找到我们素材的地址,然后定义出素材的宽和长度,然后再输出这个棋盘背景.

当输出完背景之后,我们是不是要先把所有的棋子放在初始位置,也就是初始化棋盘?

void  coord()//棋子信息赋值
{loadimage(&img, "D:/program/Project3-chess successful/1.png");putimage(0, 0, &img);//输出棋盘for (int i = 0; i <= 8; i++){for (int j = 0; j <= 9; j++)//遍历二维数组{enum pieces chessid = SPACE;//先把全部位置的id赋值为SAPCEDWORD  chesstype;//定义颜色中间变量if (j <= 4){chesstype = BLACK;//黑方if (j == 0){if (i <= 4){chessid = blackchess[i];//}else{chessid = blackchess[8 - i];}}if (j == 2 && (i == 1 || i == 7)){chessid = blackchess[5];}if (j == 3 && (i == 0 || i == 2 || i == 4 || i == 4 || i == 6 || i == 8)){chessid = blackchess[6];}}else{chesstype = RED;//红方if (j == 6 && (i == 0 || i == 2 || i == 4 || i == 6 || i == 8)){chessid = redchess[6];}if (j == 7 && (i == 1 || i == 7)){chessid = redchess[5];}if (j == 9){if (i <= 4){chessid = redchess[i];}else{chessid = redchess[8 - i];}}}//依次赋值map[i][j].id = chessid;map[i][j].river = false;map[i][j].type = chesstype;map[i][j].x = distance + longth * i;map[i][j].y = distance + high * j;}}for (int i = 0; i <= 8; i++){for (int j = 0; j <= 9; j++){if (map[i][j].id == SPACE){map[i][j].type = YELLOW;}}}}

看上述程序:

首先先加载出棋盘背景,然后把棋盘上面行和列交叉的位置都设置为SPACE,可以理解为初始化棋盘.然后如果j<=4,也就是楚河的一侧,我们定义棋子type全部都为黑色,而棋子的id要根据行列的位置来确定,首先看第一行,前5列数据,是不是应该是"車,馬,象,士,将"而后四列数据,是不是应该是前面去除将的反序,而观察一下,如果把前面定义成i列,后面对应相等的字符则是8-i列.那么我们就定义完了第一行的数据.

而炮和兵的数据,以及红方的数据是不是同上述思路一样.

然后就开始定义每一个棋子初始化的状态,回溯到棋子的基本信息结构当中,有x,y,river,type和id,我们要依次对其进行定义,

注意在初始状态的时候,棋子的river都为false,因为都没有过楚河

定义完棋子的位置,那么剩下没有棋子的位置,我们是不是要把刚开始初始化的状态都修改为棋盘的背景颜色啊.上述定义完,再次输出棋盘

void  qiban()
{loadimage(&img, "D:/program/Project3-chess successful/1.png");initgraph(img.getwidth(), img.getheight(), 1);putimage(0, 0, &img);//输出棋盘
}

这个时候就已经初始化了中国象棋的棋盘.

接下来是不是要把每一个棋子都定义到棋盘上面.开始绘画棋子

void getbackground() //画棋子
{int x_start, y_start;x_start = distance;y_start = distance;settextstyle(30, 0, "黑体");//棋子大小颜色setbkmode(0);for (int i = 0; i <= 8; i++){for (int j = 0; j <= 9; j++){if (map[i][j].id != SPACE)//在棋盘上输出{setfillcolor(RGB(253, 216, 161));//    setlinestyle(BLACK);settextcolor(map[i][j].type);fillcircle(map[i][j].x, map[i][j].y, 24);fillcircle(map[i][j].x, map[i][j].y, 18);outtextxy(map[i][j].x - 13, map[i][j].y - 13, chessname[map[i][j].id]);}}}}

如果上面棋盘行列之间的id不是SPACE,那自然就是我们定义的棋子应该安置的位置.从第0行第0列开始,依次进行定义:

画一个棋子,两个圆环,其颜色要画成背景颜色,而棋子上面的文本颜色要根据实际行列定义的type,设置成黑色和红色,

最后便是采用outtextxy()把每一个棋子的字符输入进行.注意此处根据棋盘x和y的地址均减13,是根据实际调试来进行,并不是确定常量.

写到这里,是不是就把棋子和棋盘都初始化好了?yes,of course.

3.棋盘棋子都初始化好了,那么接下来我们是不是就可以开始移动棋盘上面的棋子,进行下棋了?

这里有一个有意思的思考:我刚开始认为吃掉棋子和走到空白的地方是两种不同的情况,后面仔细思考了一下,是同一状态,只需要把原来的修改为结束的就可以了,而原来的只需要位置只需要修改颜色和id为空也就没了,不管他end地址有没有棋子.

void movechess(int a, int b, int c, int d)//移动棋子,改变其坐标
{map[c][d].id = map[a][b].id;map[c][d].river = map[a][b].river;map[c][d].type = map[a][b].type;map[c][d].x = xx(c);map[c][d].y = yy(d);map[a][b].id = SPACE;map[a][b].type = YELLOW;}
int  xx(int a)//数组下标转换成坐标
{a = distance + longth * a;return a;
}
int  yy(int a)
{a = distance + high * a;return a;
}

把[a][b]位置的棋子信息,全部给了[c][d]位置处的棋子,而[a][b]棋子此处的信息要记得修改id和type,id设置为空,而颜色设置成背景颜色.而xx(c),yy(d)就成了棋子移动到下一个点的坐标

void MouseControl()//获取鼠标点击信息并完响应
{//getbackground();if (MouseHit()){float beginrow, beginrol, endrow, endrol;//第一次按下时的坐标int intbeginrow, intbeginrol, intendrow, intendrol;//第二次按下时的坐标MOUSEMSG msg = GetMouseMsg();/*这个函数用于获取一个鼠标消息。如果当前鼠标消息队列中没有,就一直等待。*/if (msg.uMsg == WM_LBUTTONDOWN)//按下鼠标左键时{//获取鼠标点击的数组的下标//    printf("(%d,%d)", msg.x, msg.y);//回溯转换成行列beginrow = (float)(msg.x - distance) / longth;beginrol = (float)(msg.y - distance) / high;intbeginrow = round(beginrow);intbeginrol = round(beginrol);if (moving.state == BEGIN){moving.state = END;moving.beginx = intbeginrow;moving.beginy = intbeginrol;//    printf("(%d,%d)  \n", moving.beginx, moving.beginy);}else if (moving.state == END){moving.state = BEGIN;moving.endx = intbeginrow;moving.endy = intbeginrol;execute(moving.beginx, moving.beginy, moving.endx, moving.endy);}}}}

 上面这一段我其实有一点不清晰,我所理解的应该是定义了两个状态,如果状态是开始的时候,那状态改为结束,然后把第一次点击的数据给了开始的数据,如果状态是结束,把状态修改为开始,把第一次点击的数据给了结束的坐标.

关键:

            intbeginrow = round(beginrow);intbeginrol = round(beginrol);

判断输赢:

int  win()
{int redgeneral = 0;int blackgeneral = 0;for (int i = 0; i <= 8; i++){for (int j = 0; j <= 9; j++){if (map[i][j].id == blackchess[4]){blackgeneral++;}else if (map[i][j].id == redchess[4]){redgeneral++;}else{blackgeneral = blackgeneral;redgeneral = redgeneral;}}}//printf("%d %d\n", blackgeneral, redgeneral);if (blackgeneral == 0)//红方胜{return 0;}else if (redgeneral == 0)//黑方胜{return 1;}else//打平{return 2;}}

给将和帅都定义了初始值,相当于如果将死了,那就是帅赢,相反同理,而如果两者都存在,也就是1+1,那自然就是平手,return 2;

下面就是判断每一种棋子是否按游戏规则进行移动:

bool jiang(int a, int b, int  c, int d)//判断是否只移动了一格(将军、兵的规则)
{float h;h = sqrt(abs(d - b) * abs(d - b) + abs(c - a) * abs(c - a));if (b < 4 && c > 2 && c < 6 && d < 3){if (h == 1 && map[c][d].type != map[a][b].type)return true;elsereturn false;}if (b > 4 && c > 2 && c < 6 && d >6){if (h == 1 && map[c][d].type != map[a][b].type)return true;elsereturn false;}else{return false;}}
bool bing(int a, int b, int c, int d)
{float h;h = sqrt(abs(d - b) * abs(d - b) + abs(c - a) * abs(c - a));if (map[a][b].type == BLACK){if (map[a][b].river == false){if (d == b + 1 && h == 1 && map[c][d].type != map[a][b].type){return true;}else{return false;}}else{if (d >= b && h == 1 && map[c][d].type != map[a][b].type){return true;}else{return false;}}}else if (map[a][b].type == RED){if (map[a][b].river == false){if (d == b - 1 && h == 1 && map[c][d].type != map[a][b].type){return true;}else{return false;}}else{if (d <= b && h == 1 && map[c][d].type != map[a][b].type){return true;}else{return false;}}}else{return false;}
}
bool pao(int a, int b, int c, int d)//炮的移动
{if (c == a && d != b){int time = 0;int max = d > b ? d : b;int min = b < d ? b : d;for (int i = min; i <= max; i++){if (map[c][i].id != SPACE){time++;}}//    printf("%d\n", time);if (map[c][d].id == SPACE){if (time == 1)return  true;elsereturn false;}if (map[c][d].id != SPACE){if (time != 3){return false;}else{if (map[c][d].type == map[a][b].type){return false;}else{return true;}}}}else if (d == b && c != a){int time = 0;int max = a > c ? a : c;int min = c < a ? c : a;for (int i = min; i <= max; i++){if (map[i][d].id != SPACE){time++;}}//    printf("%d\n", time);if (map[c][d].id == SPACE){if (time == 1)return  true;elsereturn false;}if (map[c][d].id != SPACE){if (time != 3){return false;}else{if (map[c][d].type == map[a][b].type){return false;}else{return true;}}}}else{return false;}
}
bool che(int a, int b, int c, int d)
{if (c == a && d != b)//是否为直线{int time = 0;int max = d > b ? d : b;int min = b < d ? b : d;for (int i = min; i <= max; i++)//遍历路径{if (map[c][i].id != SPACE){time++;}}//    printf("%d", time);if (time == 1)//车移动不吃棋子{return true;}if (time == 2)//车移动并且吃目的坐标的棋子{if (map[c][d].type == map[a][b].type)//如果是目的坐标是自己的棋子,则返回false{return false;}if (map[c][d].type == YELLOW){return false;}else{return true;}}else{return false;}}else    if (d == b && c != a){int time = 0;int max = c > a ? c : a;int min = a < c ? a : c;for (int i = min; i <= max; i++)//遍历路径{if (map[i][d].id != SPACE){time++;}}//    printf("%d", time);if (time == 1)//车是否车跳棋{return true;}else if (time == 2){if (map[c][d].type == map[a][b].type){return false;}if (map[c][d].type == YELLOW){return false;}else{return true;}}else{return false;}}else{return 0;}
}
bool ma(int a, int b, int c, int d)
{float h;h = sqrt(abs(d - b) * abs(d - b) + abs(c - a) * abs(c - a));//    printf("%f", h);if (h <= 2 || h >= 2.5)//根号8=2.8.根号5=2.2{//    printf("太远了!\n");return  false;}else{int xx, yy, max, min;//关键点的坐标和中间值max = abs(d - b) > abs(c - a) ? abs(d - b) : abs(c - a);min = abs(c - a) < abs(d - b) ? abs(c - a) : abs(d - b);//printf("max\min:(%d,%d)", max, min);if (max == abs(d - b)){yy = b + (d - b) / 2;xx = a;}else{xx = a + (c - a) / 2;yy = b;}//    printf("xx\yy:(%d,%d)\n", xx, yy);if (map[xx][yy].id == SPACE){if (map[c][d].type != map[a][b].type){//    printf("目的坐标(%d,%d)\n", c, d);//    printf("那是你自己的棋子!\n");return true;}else{//    printf("那是你的棋子!\n");return false;}}else{//    printf("关键位置有棋子!\n");return false;}}
}
bool xiang(int a, int b, int c, int d)
{float h;h = sqrt(abs(d - b) * abs(d - b) + abs(c - a) * abs(c - a));if (b <= 4){if (d > 4){return false;}else{if (h < 2.4 || h>2.9){return false;}else{int xx = (a + c) / 2;int yy = (b + d) / 2;if (map[xx][yy].id == SPACE){if (map[c][d].type == map[a][b].type){return false;}else{return true;}}else{return false;}}}}else{if (d < 5){return false;}else{if (h < 2.4 || h>2.9){return false;}else{int xx = (a + c) / 2;int yy = (b + d) / 2;if (map[xx][yy].id == SPACE){if (map[c][d].type == map[a][b].type){return false;}else{return true;}}else{return false;}}}}}
bool shi(int a, int b, int c, int d)
{float h = sqrt(abs(d - b) * abs(d - b) + abs(c - a) * abs(c - a));//  printf("%f", h)if (b < 5){if (c >= 3 && c <= 5 && d <= 2){if (1.2 < h && h < 1.5){if (map[c][d].type != map[a][b].type)return true;elsereturn false;}else{return false;}}else{return false;}}else if (b > 5){if (c >= 3 && c <= 5 && d >= 7){if (1.2 < h && h < 1.5){if (map[c][d].type != map[a][b].type)return true;elsereturn false;}else{return false;}}else{return false;}}elsereturn false;
}

上述全都是bool型,用以表示判断是否正确就行

接下来是行棋子,如果遵守规则,也就是上面的bool输出true,则移动,否则输出"你不能这样做!"

void execute(int a, int b, int c, int d)//行棋
{if (map[a][b].id == blackchess[4])//黑方将{if (jiang(a, b, c, d)){movechess(a, b, c, d);}else{printf("你不能这样做\n");}}else if (map[a][b].id == redchess[4])//红方将{if (jiang(a, b, c, d)){movechess(a, b, c, d);}else{printf("你不能这样做!\n");}}else if (map[a][b].id == blackchess[6])//黑方兵{if (map[a][b].river == false){if (bing(a, b, c, d)){movechess(a, b, c, d);if (d > 4){map[c][d].river = true;}}else{printf("你不可以这样做!\n");}}else{if (bing(a, b, c, d) && d >= b){movechess(a, b, c, d);}else{printf("你不可以这样做\n");}}}else if (map[a][b].id == redchess[6])//红方兵{if (map[a][b].river == false){if (bing(a, b, c, d)){movechess(a, b, c, d);if (d < 5){map[c][d].river = true;}}else{printf("你不可以这样做!\n");}}else{if (bing(a, b, c, d) && d <= b){movechess(a, b, c, d);}else{printf("你不可以这样做!\n");}}}else if (map[a][b].id == blackchess[5] || map[a][b].id == redchess[5]){if (pao(a, b, c, d)){movechess(a, b, c, d);}else{printf("你不能这样做!\n");}}else if (map[a][b].id == blackchess[0] || map[a][b].id == redchess[0]){if (che(a, b, c, d)){movechess(a, b, c, d);}else{printf("你不可以这样做!\n");}}else if (map[a][b].id == blackchess[1] || map[a][b].id == redchess[1]){if (ma(a, b, c, d)){movechess(a, b, c, d);}else{printf("你不能这样做!\n");}}else if (map[a][b].id == blackchess[2] || map[a][b].id == redchess[2]){if (xiang(a, b, c, d)){movechess(a, b, c, d);}elseprintf("你不能这样做!\n");}else if (map[a][b].id == blackchess[3]){if (shi(a, b, c, d)){movechess(a, b, c, d);}elseprintf("你不能这样做!");}else if (map[a][b].id == redchess[3]){if (shi(a, b, c, d)){movechess(a, b, c, d);}elseprintf("你不能这样做!");}
}

定义完上面所有的函数,最后就是主函数,运行就可以了

int main()
{begining();while (1)//当正确的时候{coord();//输出棋盘win();BeginBatchDraw();/*这个函数用于开始批量绘图。执行后任何绘图操作都将暂时不输出到绘图窗口上,直到执行 FlushBatchDraw 或 EndBatchDraw 才将之前的绘图输出。*///运行BeginBatchDraw后,所有的绘图都不再显示在屏幕上,而是在内存中进行//封装的双缓存,避免闪屏/*那如果我们能让打印的过程不显示出来,只显示打印完后的显示缓冲区不就行了吗*/while (win() == 2)//平局状态,是不是还需要继续运行下去?{win();putimage(0, 0, &img);getbackground();//输出棋子MouseControl();//鼠标更改数据FlushBatchDraw();/*这个函数用于执行未完成的绘制任务。*/}putimage(0, 0, &img);getbackground();//输出棋子MouseControl();//鼠标更改数据FlushBatchDraw();/*这个函数用于执行未完成的绘制任务。*/if (win() == 0){printf("红方胜!\n");}else if (win() == 1){printf("黑方胜!\n");}}getchar();return 0;
}

总代码:

#include<stdio.h>
#include<graphics.h>
#include<math.h>
void execute(int a, int b, int c, int d);
bool jiang(int a, int b, int  c, int d);
bool pao(int a, int b, int c, int d);
bool ma(int a, int b, int c, int d);
IMAGE img;
#define distance  35//窗口线与棋盘边界线的距离
#define   longth  65//棋盘方格的长
#define   high   61//棋盘方格的宽
struct movecoordinate
{long x;long y;
};
struct  Chesscoordinate//棋子综合信息
{int x;int y;DWORD type;  //颜色bool river;//是否过河int id;
};
enum pieces
{SPACE = -1,車, 馬, 象, 士, 将, 炮, 卒,车, 马, 相, 仕, 帥, 砲, 兵,BEGIN, END,};
enum pieces redchess[] = { 車,馬,象,士,将,炮,卒, };
enum pieces blackchess[] = { 车,马,相,仕,帥,砲,兵, };
enum pieces state = BEGIN;
struct move {  //鼠标选中的棋子int beginx;int beginy;int endx;int endy;int state;
}moving = { -1,-1,-1,-1,BEGIN };
const char* chessname[] = { "車","馬","象","士","将","炮","卒","车","马","相","仕","帥","砲","兵", };
struct Chesscoordinate  map[9][10];//坐标
struct Chesscoordinate  AImap[9][10];//坐标
movecoordinate begin = { -1,-1 }, end = { -1,-1 };
int  xx(int a)//数组下标转换成坐标
{a = distance + longth * a;return a;
}
int  yy(int a)
{a = distance + high * a;return a;
}
void begining()
{loadimage(&img, "D:/program/Project3-chess successful/1.png");initgraph(img.getwidth(), img.getheight(), 1); //初始化图形系统putimage(0, 0, &img);//输出开始界面;}
void  qiban()
{loadimage(&img, "D:/program/Project3-chess successful/1.png");initgraph(img.getwidth(), img.getheight(), 1);putimage(0, 0, &img);//输出棋盘
}
void  coord()//棋子信息赋值
{loadimage(&img, "D:/program/Project3-chess successful/1.png");putimage(0, 0, &img);//输出棋盘for (int i = 0; i <= 8; i++){for (int j = 0; j <= 9; j++)//遍历二维数组{enum pieces chessid = SPACE;//先把全部位置的id赋值为SAPCEDWORD  chesstype;//定义颜色中间变量if (j <= 4){chesstype = BLACK;//黑方if (j == 0){if (i <= 4){chessid = blackchess[i];//}else{chessid = blackchess[8 - i];}}if (j == 2 && (i == 1 || i == 7)){chessid = blackchess[5];}if (j == 3 && (i == 0 || i == 2 || i == 4 || i == 4 || i == 6 || i == 8)){chessid = blackchess[6];}}else{chesstype = RED;//红方if (j == 6 && (i == 0 || i == 2 || i == 4 || i == 6 || i == 8)){chessid = redchess[6];}if (j == 7 && (i == 1 || i == 7)){chessid = redchess[5];}if (j == 9){if (i <= 4){chessid = redchess[i];}else{chessid = redchess[8 - i];}}}//依次赋值map[i][j].id = chessid;map[i][j].river = false;map[i][j].type = chesstype;map[i][j].x = distance + longth * i;map[i][j].y = distance + high * j;}}for (int i = 0; i <= 8; i++){for (int j = 0; j <= 9; j++){if (map[i][j].id == SPACE){map[i][j].type = YELLOW;}}}}
void getbackground() //画棋子
{int x_start, y_start;x_start = distance;y_start = distance;settextstyle(30, 0, "黑体");//棋子大小颜色setbkmode(0);for (int i = 0; i <= 8; i++){for (int j = 0; j <= 9; j++){if (map[i][j].id != SPACE)//在棋盘上输出{setfillcolor(RGB(253, 216, 161));//    setlinestyle(BLACK);settextcolor(map[i][j].type);fillcircle(map[i][j].x, map[i][j].y, 24);fillcircle(map[i][j].x, map[i][j].y, 18);outtextxy(map[i][j].x - 13, map[i][j].y - 13, chessname[map[i][j].id]);}}}}
void movechess(int a, int b, int c, int d)//移动棋子,改变其坐标
{map[c][d].id = map[a][b].id;map[c][d].river = map[a][b].river;map[c][d].type = map[a][b].type;map[c][d].x = xx(c);map[c][d].y = yy(d);map[a][b].id = SPACE;map[a][b].type = YELLOW;}void MouseControl()//获取鼠标点击信息并完响应
{//getbackground();if (MouseHit()){float beginrow, beginrol, endrow, endrol;//第一次按下时的坐标int intbeginrow, intbeginrol, intendrow, intendrol;//第二次按下时的坐标MOUSEMSG msg = GetMouseMsg();/*这个函数用于获取一个鼠标消息。如果当前鼠标消息队列中没有,就一直等待。*/if (msg.uMsg == WM_LBUTTONDOWN)//按下鼠标左键时{//获取鼠标点击的数组的下标//    printf("(%d,%d)", msg.x, msg.y);//回溯转换成行列beginrow = (float)(msg.x - distance) / longth;beginrol = (float)(msg.y - distance) / high;intbeginrow = round(beginrow);intbeginrol = round(beginrol);if (moving.state == BEGIN){moving.state = END;moving.beginx = intbeginrow;moving.beginy = intbeginrol;//    printf("(%d,%d)  \n", moving.beginx, moving.beginy);}else if (moving.state == END){moving.state = BEGIN;moving.endx = intbeginrow;moving.endy = intbeginrol;execute(moving.beginx, moving.beginy, moving.endx, moving.endy);}}}}int  win()
{int redgeneral = 0;int blackgeneral = 0;for (int i = 0; i <= 8; i++){for (int j = 0; j <= 9; j++){if (map[i][j].id == blackchess[4]){blackgeneral++;}else if (map[i][j].id == redchess[4]){redgeneral++;}else{blackgeneral = blackgeneral;redgeneral = redgeneral;}}}//printf("%d %d\n", blackgeneral, redgeneral);if (blackgeneral == 0)//红方胜{return 0;}else if (redgeneral == 0)//黑方胜{return 1;}else//打平{return 2;}}
bool jiang(int a, int b, int  c, int d)//判断是否只移动了一格(将军、兵的规则)
{float h;h = sqrt(abs(d - b) * abs(d - b) + abs(c - a) * abs(c - a));if (b < 4 && c > 2 && c < 6 && d < 3){if (h == 1 && map[c][d].type != map[a][b].type)return true;elsereturn false;}if (b > 4 && c > 2 && c < 6 && d >6){if (h == 1 && map[c][d].type != map[a][b].type)return true;elsereturn false;}else{return false;}}
bool bing(int a, int b, int c, int d)
{float h;h = sqrt(abs(d - b) * abs(d - b) + abs(c - a) * abs(c - a));if (map[a][b].type == BLACK){if (map[a][b].river == false){if (d == b + 1 && h == 1 && map[c][d].type != map[a][b].type){return true;}else{return false;}}else{if (d >= b && h == 1 && map[c][d].type != map[a][b].type){return true;}else{return false;}}}else if (map[a][b].type == RED){if (map[a][b].river == false){if (d == b - 1 && h == 1 && map[c][d].type != map[a][b].type){return true;}else{return false;}}else{if (d <= b && h == 1 && map[c][d].type != map[a][b].type){return true;}else{return false;}}}else{return false;}
}
bool pao(int a, int b, int c, int d)//炮的移动
{if (c == a && d != b){int time = 0;int max = d > b ? d : b;int min = b < d ? b : d;for (int i = min; i <= max; i++){if (map[c][i].id != SPACE){time++;}}//    printf("%d\n", time);if (map[c][d].id == SPACE){if (time == 1)return  true;elsereturn false;}if (map[c][d].id != SPACE){if (time != 3){return false;}else{if (map[c][d].type == map[a][b].type){return false;}else{return true;}}}}else if (d == b && c != a){int time = 0;int max = a > c ? a : c;int min = c < a ? c : a;for (int i = min; i <= max; i++){if (map[i][d].id != SPACE){time++;}}//    printf("%d\n", time);if (map[c][d].id == SPACE){if (time == 1)return  true;elsereturn false;}if (map[c][d].id != SPACE){if (time != 3){return false;}else{if (map[c][d].type == map[a][b].type){return false;}else{return true;}}}}else{return false;}
}
bool che(int a, int b, int c, int d)
{if (c == a && d != b)//是否为直线{int time = 0;int max = d > b ? d : b;int min = b < d ? b : d;for (int i = min; i <= max; i++)//遍历路径{if (map[c][i].id != SPACE){time++;}}//    printf("%d", time);if (time == 1)//车移动不吃棋子{return true;}if (time == 2)//车移动并且吃目的坐标的棋子{if (map[c][d].type == map[a][b].type)//如果是目的坐标是自己的棋子,则返回false{return false;}if (map[c][d].type == YELLOW){return false;}else{return true;}}else{return false;}}else    if (d == b && c != a){int time = 0;int max = c > a ? c : a;int min = a < c ? a : c;for (int i = min; i <= max; i++)//遍历路径{if (map[i][d].id != SPACE){time++;}}//    printf("%d", time);if (time == 1)//车是否车跳棋{return true;}else if (time == 2){if (map[c][d].type == map[a][b].type){return false;}if (map[c][d].type == YELLOW){return false;}else{return true;}}else{return false;}}else{return 0;}
}
bool ma(int a, int b, int c, int d)
{float h;h = sqrt(abs(d - b) * abs(d - b) + abs(c - a) * abs(c - a));//    printf("%f", h);if (h <= 2 || h >= 2.5)//根号8=2.8.根号5=2.2{//    printf("太远了!\n");return  false;}else{int xx, yy, max, min;//关键点的坐标和中间值max = abs(d - b) > abs(c - a) ? abs(d - b) : abs(c - a);min = abs(c - a) < abs(d - b) ? abs(c - a) : abs(d - b);//printf("max\min:(%d,%d)", max, min);if (max == abs(d - b)){yy = b + (d - b) / 2;xx = a;}else{xx = a + (c - a) / 2;yy = b;}//    printf("xx\yy:(%d,%d)\n", xx, yy);if (map[xx][yy].id == SPACE){if (map[c][d].type != map[a][b].type){//    printf("目的坐标(%d,%d)\n", c, d);//    printf("那是你自己的棋子!\n");return true;}else{//    printf("那是你的棋子!\n");return false;}}else{//    printf("关键位置有棋子!\n");return false;}}
}
bool xiang(int a, int b, int c, int d)
{float h;h = sqrt(abs(d - b) * abs(d - b) + abs(c - a) * abs(c - a));if (b <= 4){if (d > 4){return false;}else{if (h < 2.4 || h>2.9){return false;}else{int xx = (a + c) / 2;int yy = (b + d) / 2;if (map[xx][yy].id == SPACE){if (map[c][d].type == map[a][b].type){return false;}else{return true;}}else{return false;}}}}else{if (d < 5){return false;}else{if (h < 2.4 || h>2.9){return false;}else{int xx = (a + c) / 2;int yy = (b + d) / 2;if (map[xx][yy].id == SPACE){if (map[c][d].type == map[a][b].type){return false;}else{return true;}}else{return false;}}}}}
bool shi(int a, int b, int c, int d)
{float h = sqrt(abs(d - b) * abs(d - b) + abs(c - a) * abs(c - a));//  printf("%f", h)if (b < 5){if (c >= 3 && c <= 5 && d <= 2){if (1.2 < h && h < 1.5){if (map[c][d].type != map[a][b].type)return true;elsereturn false;}else{return false;}}else{return false;}}else if (b > 5){if (c >= 3 && c <= 5 && d >= 7){if (1.2 < h && h < 1.5){if (map[c][d].type != map[a][b].type)return true;elsereturn false;}else{return false;}}else{return false;}}elsereturn false;
}
void execute(int a, int b, int c, int d)//行棋
{if (map[a][b].id == blackchess[4])//黑方将{if (jiang(a, b, c, d)){movechess(a, b, c, d);}else{printf("你不能这样做\n");}}else if (map[a][b].id == redchess[4])//红方将{if (jiang(a, b, c, d)){movechess(a, b, c, d);}else{printf("你不能这样做!\n");}}else if (map[a][b].id == blackchess[6])//黑方兵{if (map[a][b].river == false){if (bing(a, b, c, d)){movechess(a, b, c, d);if (d > 4){map[c][d].river = true;}}else{printf("你不可以这样做!\n");}}else{if (bing(a, b, c, d) && d >= b){movechess(a, b, c, d);}else{printf("你不可以这样做\n");}}}else if (map[a][b].id == redchess[6])//红方兵{if (map[a][b].river == false){if (bing(a, b, c, d)){movechess(a, b, c, d);if (d < 5){map[c][d].river = true;}}else{printf("你不可以这样做!\n");}}else{if (bing(a, b, c, d) && d <= b){movechess(a, b, c, d);}else{printf("你不可以这样做!\n");}}}else if (map[a][b].id == blackchess[5] || map[a][b].id == redchess[5]){if (pao(a, b, c, d)){movechess(a, b, c, d);}else{printf("你不能这样做!\n");}}else if (map[a][b].id == blackchess[0] || map[a][b].id == redchess[0]){if (che(a, b, c, d)){movechess(a, b, c, d);}else{printf("你不可以这样做!\n");}}else if (map[a][b].id == blackchess[1] || map[a][b].id == redchess[1]){if (ma(a, b, c, d)){movechess(a, b, c, d);}else{printf("你不能这样做!\n");}}else if (map[a][b].id == blackchess[2] || map[a][b].id == redchess[2]){if (xiang(a, b, c, d)){movechess(a, b, c, d);}elseprintf("你不能这样做!\n");}else if (map[a][b].id == blackchess[3]){if (shi(a, b, c, d)){movechess(a, b, c, d);}elseprintf("你不能这样做!");}else if (map[a][b].id == redchess[3]){if (shi(a, b, c, d)){movechess(a, b, c, d);}elseprintf("你不能这样做!");}
}
int main()
{begining();while (1)//当正确的时候{coord();//输出棋盘win();BeginBatchDraw();/*这个函数用于开始批量绘图。执行后任何绘图操作都将暂时不输出到绘图窗口上,直到执行 FlushBatchDraw 或 EndBatchDraw 才将之前的绘图输出。*///运行BeginBatchDraw后,所有的绘图都不再显示在屏幕上,而是在内存中进行//封装的双缓存,避免闪屏/*那如果我们能让打印的过程不显示出来,只显示打印完后的显示缓冲区不就行了吗*/while (win() == 2)//平局状态,是不是还需要继续运行下去?{win();putimage(0, 0, &img);getbackground();//输出棋子MouseControl();//鼠标更改数据FlushBatchDraw();/*这个函数用于执行未完成的绘制任务。*/}putimage(0, 0, &img);getbackground();//输出棋子MouseControl();//鼠标更改数据FlushBatchDraw();/*这个函数用于执行未完成的绘制任务。*/if (win() == 0){printf("红方胜!\n");}else if (win() == 1){printf("黑方胜!\n");}}getchar();return 0;
}

总代码参考于:

(1条消息) 基于c语言的象棋游戏_m0_59564114的博客-CSDN博客_c语言象棋游戏代码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_38654.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

详解 Spring Boot 项目中的配置文件

目录 1. Spring Boot 项目中配日文件的作用是什么 2. Spring Boot 配置文件的两种格式 3. properties 配置文件 3.1 properties 配置文件的基本语法 3.2 properties 配置文件的分类 3.3 如何读取配置文件 3.4 properties 配置文件的优缺点分析 4. yml 配置文件 4.1 yml …

BP神经网络PID从Simulink仿真到PLC控制实现(含博途PLC完整SCL源代码)

单神经元自适应PID控制博途PLC完整源代码,请参看下面的文章链接: 博途PLC单神经元自适应PID控制_RXXW_Dor的博客-CSDN博客_单神经元pid控制1、单神经元作为构成神经网络的基本单位,具有自学习和自适应能力,且结构简单易于计算,传统的PID具有结构简单、调整方便和参数整定…

【软件测试】8年资深测试说出来我们的心声......

目录&#xff1a;导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09;前言 执着于手动的功能测…

SSM毕设项目 - 基于SSM的毕业设计管理系统(含源码+论文)

文章目录1 项目简介2 实现效果2.1 界面展示3 设计方案3.1 概述3.2 系统流程3.2.1 系统开发流程3.3.2 教师登录流程3.3.3 系统操作流程3.3 系统结构设计4 项目获取1 项目简介 Hi&#xff0c;各位同学好呀&#xff0c;这里是M学姐&#xff01; 今天向大家分享一个今年(2022)最新…

【Android App】实战项目之仿抖音的短视频分享App(附源码和演示视频 超详细必看)

需要全部代码请点赞关注收藏后评论区留言私信~~~ 与传统的影视行业相比&#xff0c;诞生于移动互联网时代的短视频是个全新行业&#xff0c;它制作方便又容易传播&#xff0c;一出现就成为大街小巷的时髦潮流。 各行各业的人们均可通过短视频展示自己&#xff0c;短小精悍的视频…

社区系统项目复盘-6

文章目录什么是Elasticsearch&#xff1f;Spring是怎么整合Elasticsearch的&#xff1f;开发社区搜索功能Elasticsearch实现全文搜索功能什么是Elasticsearch&#xff1f; Elasticsearch简介 一个分布式的、Restful风格的搜索引擎支持对各种类型的数据的检索搜索速度快&#xf…

基于粒子群算法和遗传算法优化的高速列车横向悬挂

目录 前言 1.高速列车模型 2.优化算法优化模糊PID流程 3.普通PID、优化算法模糊PID仿真对比 3.1 模糊控制器设计 3.2 仿真结果 3.2.1粒子群优化PID 3.2.2粒子群优化模糊PID 3.2.3遗传算法优化模糊PID 4.总结 前言 高速列车&#xff0c;是指最高行驶速度在200km/h 及以…

小知识· Zigbee 简介

1. 介绍 ZigBee是一种近距离、低复杂度、低功耗、低速率、低成本的双向无线通讯技术 ZigBee建立在IEEE 802.15.4标准&#xff08;定义了PHY和MAC层&#xff09;之上&#xff0c;ZigBee联盟对其网络层和应用层进行了标准化 ZigBee协议栈可分为五层 - 物理层&#xff08;PHY&a…

多进程并发服务器

TCP三次握手建立连接错误处理模块&#xff1a;wrap.c,函数声明&#xff1a;wrap.h并发服务器模型&#xff08;多进程&#xff0c;多线程&#xff09; 转换大小写程序 服务端 #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #incl…

Mybatis Plus 多租户id使用

本文就不多逼逼&#xff0c;直接进入正题。 什么是多租户 多租户技术&#xff08;Multi-TenancyTechnology&#xff09;又称多重租赁技术&#xff0c;简称SaaS&#xff0c;是一种软件架构技术&#xff0c;是实现如何在多用户环境下 &#xff08;此处的多用户一般是面向企业用…

Java SPI机制的使用和理解

前言&#xff1a; SPI(Service Provider Interface)&#xff0c;是JDK内置的一种服务提供发现机制&#xff0c;Java中 SPI 机制主要思想是将装配的控制权移到程序之外&#xff0c;在模块化设计中这个机制尤其重要&#xff0c;其核心思想就是解耦 1、大家都知道API&#xff0c;却…

【C++】STL —— map和set的模拟实现

目录 一、基础铺垫 二、基本结构分析 1. 节点结构分析 2. 模板参数中仿函数分析 三、正向迭代器 四、封装完成的红黑树 五、map的模拟实现 六、set的模拟实现 一、基础铺垫 在前面的博客中我们了解了map和set的基本使用&#xff0c;以及对二叉搜索树、AVL树和红黑树的…

IPv6进阶:IPv6 过渡技术之 NAT64(IPv6 节点主动访问 IPv4 节点-地址池方式)

实验拓扑 PC1是IPv4网络的一个节点&#xff0c;处于Trust安全域&#xff1b;PC2是IPv6网络的一个节点&#xff0c;处于Untrust安全域。 实验需求 完成防火墙IPv4、IPv6接口的配置&#xff0c;并将接口添加到相应的安全域&#xff1b;在防火墙上配置NAT64的IPv6前缀3001::/64&…

【毕业设计】30-基于单片机矿井瓦斯_气体浓度_烟雾浓度报警设计(原理图+源代码+仿真+答辩论文+答辩PPT)

【毕业设计】30-基于单片机矿井瓦斯/气体浓度/烟雾浓度报警设计&#xff08;原理图源代码仿真答辩论文答辩PPT&#xff09; 文章目录【毕业设计】30-基于单片机矿井瓦斯/气体浓度/烟雾浓度报警设计&#xff08;原理图源代码仿真答辩论文答辩PPT&#xff09;任务书设计说明书摘要…

网络套接字编程(UDP协议)

文章目录预备知识socket&#xff08;网络套接字&#xff09;编程接口简单的UDP网络程序增加多用户可以互相通信预备知识 网络字节序 大端存储&#xff1a;数据的高字节内容保存在内存的低地址处&#xff0c;数据的低字节内容保存在内存的高地址处 小端存储&#xff1a;数据的高…

global关键字、python实现ATM简单功能

目录 一.局部变量、全局变量 二.global关键字 演示 三.编写ATM程序 要求 详细步骤 存在问题 改进 完整代码 一.局部变量、全局变量 1.什么是局部变量 作用范围在函数内部&#xff0c;在函数外部无法使用 2.什么是全局变量 在函数内部和外部均可使用 3.如何将函数内定…

[附源码]SSM计算机毕业设计校园自行车租售管理系统JAVA

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

高等数学(第七版)同济大学 习题10-3 (前9题)个人解答

高等数学&#xff08;第七版&#xff09;同济大学 习题10-3&#xff08;前9题&#xff09; 函数作图软件&#xff1a;Mathematica 1.化三重积分I∭Ωf(x,y,z)dxdydz为三次积分&#xff0c;其中积分区域Ω分别是\begin{aligned}&1. \ 化三重积分I\iiint_{\Omega}f(x, \ y, …

【C++】类型转换

目录 一、C语言风格类型转换 二、C风格类型转换 1.static_case 2.reinterpret_case 3、const_case 4、dynamic_case 三、RTTI 总结 一、C语言风格类型转换 在C语言中&#xff0c;如果赋值运算符左右两侧类型不同&#xff0c;或者形参与实参类型不匹配&#xff0c;或者返…

【正点原子FPGA连载】 第二十章 LCD触摸屏实验摘自【正点原子】DFZU2EG/4EV MPSoC 之FPGA开发指南V1.0

1&#xff09;实验平台&#xff1a;正点原子MPSoC开发板 2&#xff09;平台购买地址&#xff1a;https://detail.tmall.com/item.htm?id692450874670 3&#xff09;全套实验源码手册视频下载地址&#xff1a; http://www.openedv.com/thread-340252-1-1.html 第二十章 LCD触摸…