@我的象棋
小熊猫C++
这是我的第一个编辑器
学习编辑了一些小游戏
- 我的象棋
/*
2022.4.18 重写象棋
*/
#include <stdio.h>
#include <windows.h>
#include <graphics.h>
#define GZ 65 //棋盘格子大小
#define BIAN 90 //棋盘边到屏幕边距离
#define X(i) (BIAN+GZ*i) //i表示0~8 横向坐标
#define Y(i) (BIAN+GZ*i) //i表示0~9 纵向坐标
#define R (GZ/2-5) //棋子圆形半径
#define Row 10 //棋盘行
#define Col 9 //棋盘列
#define Num 32 //棋子总数
#define weight X(8) + X(3) //窗口宽
#define high Y(9) + BIAN //窗口高
char mz[] = {'1', '2', '3', '4', '5', '6', '7', '8', '9'};
const char *nz[] = {"一", "二", "三", "四", "五", "六", "七", "八", "九"};
enum Pieces {NONE = -1, 车, 马, 象, 士, 将, 炮, 兵, 車, 馬, 相, 仕, 帅, 砲, 卒}; //NONE表示无棋子
const char *chessName[] = {"车", "马", "象", "士", "将", "炮", "兵", "車", "馬", "相", "仕", "帅", "砲", "卒"}; //[0~13]
bool is_Select; //选棋子
bool zoudong; //是否走动
bool gameover; //判断是否游戏结束
bool flag; //黑红交替用
enum {zou, chi};
//int steps = 0; //步数 steps
//棋盘格点元素
typedef struct QMap {
int x, y, Name, ID;
DWORD type;
} QMap; //定义棋盘名
//棋盘矩阵元素
typedef struct {
QMap data[Num];
int m, n, num;
} chessMartix; //定义棋盘矩阵
QMap Map[Row][Col]; //棋盘 Map[10][9]
QMap M[Num - 1]; //32个棋子 M[0~31]
//-------------------------------------------------
QMap N[Num - 3]; //存放被吃棋子最多29个 栈N[0~28]
int top = -1; //栈顶数
//入栈N[]
int pushN(QMap *O, int top, QMap E) {
O[++(top)] = E;
printf("被吃棋子:%s top=%d\n", chessName[N[top].Name], top);
return top;
}
//出栈N[]
int popN(int top) {
if (top == -1) {
printf("空栈");
return -1;
}
printf("top=%d\n", top);
top--;
return top;
}
//--------------------------------------------------
//棋谱链表节点结构 前指针,后指针,ID,走前坐标,走后坐标,是走是吃。
typedef struct qipulink {
struct qipulink *prior;
int zouchi;
int ID;
int x;
int y;
int cx;
int cy;
struct qipulink *next;
} link;
//初始化棋谱链 开始只有一个没用的首节点
link *initqipu(link *qipu) {
//创建棋谱首元节点
qipu = (link*)malloc(sizeof(link));
//对节点初始化
qipu->prior = NULL;
qipu->zouchi = zou;
qipu->ID = -2;
qipu-> cx = -1;
qipu-> cy = -1;
qipu-> x = -2;
qipu-> y = -2;
qipu->next = NULL;
return qipu;
}
//插入棋谱链新节点
link *insterLink(link *qipu, int x, int y, int cx, int cy, int ID, int zouchi) {
//创建新节点
link *temp = (link*)malloc(sizeof(link));
temp->prior = NULL;
temp->next = NULL;
temp->x = x;
temp->y = y;
temp->cx = cx;
temp->cy = cy;
temp->ID = ID;
temp->zouchi = zouchi;
//定义新指针p 指向qipu
link* p = qipu;
if (p == NULL) {
p = temp;
printf("初始化失败!\n");
} else {
//链接新节点 到qipu尾部
while (p->next) { //找到p尾结点
p = p->next;
}
temp->next = p->next;
temp->prior = p;
p->next = temp;
}
return p;
}
//控制台棋谱链显示
void displayqipu(link *qipu) {
link *temp = qipu;
while (temp != NULL) {
if (temp->next == NULL) {
printf("[%d %d] [%d %d] [%d]\n", temp-> x, temp-> y, temp->cx, temp->cy, temp->zouchi);
} else {
printf("[%d %d] [%d %d] [%d] <=> ", temp-> x, temp-> y, temp->cx, temp->cy, temp->zouchi);
}
temp = temp->next;
}
printf("-----------------------------------------------------\n\n");
}
//初始化 Map[][], main{ chessMartix *Q}
void initMap(chessMartix* Q) {
//初始化棋子M[]
for (int j = 0; j < Num; j++) { //0~31 x,y,id,name,type
int temp = 0; //记录0~31棋子编号对应的象棋名字编号
if (j < 16) { //----------前16个棋子--------------
if (j < 4) {
temp = j; //0 1 2 3 4
} else if (j < 9) {
temp = 8 - j; //3 2 1 0
} else if (j == 9 || j == 10) {
temp = 5; //5
} else {
temp = 6; //6
}
M[j].type = BLACK; //为黑色
} else { //-----------后16个棋子---------------
int k = j - 16;
if (k < 4) {
temp = 7 + k; //7 8 9 10 11
} else if (k < 9) {
temp = 7 + 8 - k; //10 9 8 7
} else if (k == 9 || k == 10) {
temp = 7 + 5; //12
} else {
temp = 7 + 6; //13
}
M[j].type = RED; //为红色
}
M[j].Name = temp; /*象棋名字编号0 1 2 3 4 3 2 1 0 5 6 7 8 9 10 11 10 9 8 7 12 13*/
M[j].ID = j; //0~31
M[j].x = 0;
M[j].y = 0;
}
//初始化棋盘Map[][],以及各棋子的位置颜色
for (int j = 0; j < Row; j++) {
for (int i = 0; i < Col; i++) {
Map[j][i].Name = -1;
Map[j][i].ID = -1;
Map[j][i].x = i;
Map[j][i].y = j;
}
}
for (int j = 0; j < Row; j++) {
for (int i = 0; i < Col; i++) {
//--------------------------------------------
if (j == 0) { //0 1 2 3 4 3 2 1 0
Map[j][i].Name = M[i].Name;
Map[j][i].ID = M[i].ID;
}
if (j == 2 && i == 1) { // 5
Map[j][i].Name = M[9].Name;
Map[j][i].ID = M[9].ID;
}
if ((j == 2 && i == 7)) { // 5
Map[j][i].Name = M[10].Name;
Map[j][i].ID = M[10].ID;
}
if (j == 3 && i < 5) { //6 6 6 6 6
Map[j][(i * 2)].Name = M[11 + i].Name;
Map[j][(i * 2)].ID = M[11 + i].ID;
}
//------------------------------------------------
if (9 - j == 0) { //7 8 9 10 11 10 9 8 7
Map[j][i].Name = M[16 + i].Name;
Map[j][i].ID = M[16 + i].ID;
}
if (9 - j == 2 && i == 1) { // 12
Map[j][i].Name = M[16 + 9].Name;
Map[j][i].ID = M[16 + 9].ID;
}
if ((9 - j == 2 && i == 7)) { // 12
Map[j][i].Name = M[16 + 10].Name;
Map[j][i].ID = M[16 + 10].ID;
}
if (9 - j == 3 && i < 5) { //13 13 13 13 13
Map[j][i * 2].Name = M[16 + 11 + i].Name;
Map[j][i * 2].ID = M[16 + 11 + i].ID;
}
}
}
for (int j = 0; j < Row; j++) {
for (int i = 0; i < Col; i++) {
if (Map[j][i].ID < 16 && Map[j][i].ID >= 0) {
Map[j][i].type = BLACK;
} else if (Map[j][i].ID < Num && Map[j][i].ID >= 16) {
Map[j][i].type = RED;
} else {
Map[j][i].type = BLUE;
}
}
}
//初始化矩阵Q 稀疏矩阵存储32个棋子
int nn = 0;
for (int j = 0; j < Row; j++) {
for (int i = 0; i < Col; i++) {
if (Map[j][i].Name != -1) {
Q->data[nn].Name = Map[j][i].Name;
Q->data[nn].ID = Map[j][i].ID;
Q->data[nn].y = j;
Q->data[nn].x = i;
nn++;
}
}
}
}
//控制台矩阵显示1
void displayQ(chessMartix * Q) {
for (int i = 0; i < Q->n; i++) {
for (int j = 0; j < Q->m; j++) {
int value = 0;
for (int k = 0; k < Q->num; k++) {
if (i == Q->data[k].y && j == Q->data[k].x) {
printf("%-4d", Q->data[k].Name);
value = 1;
break;
}
}
if (value == 0) {
printf("* ");
}
}
printf("\n\n");
}
}
//隐藏控制台光标功能
void recursor() {
HANDLE hout;
hout = GetStdHandle(STD_OUTPUT_HANDLE);
COORD coord;
coord.X = 0;
coord.Y = 0;
SetConsoleCursorPosition(hout, coord);
}
//控制台显示2
void show() {
//system("cls");
recursor();
for (int i = 0; i < Row; i++) {
for (int j = 0; j < Col; j++) {
printf("%-4d", Map[i][j].ID);
}
printf("\n\n");
}
printf("top=%d\a\n\n", top); // \a是响铃符
}
//画棋盘
void huaqipan() {
setcolor(GREEN);
for (int x = X(0); x <= X(8); x += GZ) {
line(x, Y(0), x, Y(4)); /*上半和下半【竖】*/
line(x, Y(5), x, Y(9));
}
line(X(0), Y(4), X(0), Y(5)); /*【左】【竖】*/
line(X(8), Y(4), X(8), Y(5)); /*【右】【竖】*/
for (int y = Y(0); y <= Y(9); y += GZ) {
line(X(0), y, X(8), y); /*【行】*/
}
for (int i = X(1); i <= X(7); i += GZ * 6) {
for (int j = Y(2); j <= Y(7); j += GZ * 5) {
/*画星号【行】*/
line(i - GZ / 4, j - GZ / 16, i - GZ / 16, j - GZ / 16);
line(i + GZ / 4, j - GZ / 16, i + GZ / 16, j - GZ / 16);
line(i - GZ / 4, j + GZ / 16, i - GZ / 16, j + GZ / 16);
line(i + GZ / 4, j + GZ / 16, i + GZ / 16, j + GZ / 16);
/*画星号【竖】*/
line(i - GZ / 16, j - GZ / 16, i - GZ / 16, j - GZ / 4);
line(i + GZ / 16, j - GZ / 16, i + GZ / 16, j - GZ / 4);
line(i - GZ / 16, j + GZ / 16, i - GZ / 16, j + GZ / 4);
line(i + GZ / 16, j + GZ / 16, i + GZ / 16, j + GZ / 4);
}
}
line(X(3), Y(2), X(5), Y(0)); /*上【将位】*/
line(X(3), Y(0), X(5), Y(2));
line(X(3), Y(7), X(5), Y(9)); /*下帅位*/
line(X(3), Y(9), X(5), Y(7));
setfillcolor(CYAN);
bar(X(0) + GZ / 40, Y(4) + GZ / 40, X(8) - GZ / 40, Y(5) - GZ / 40); /*棋盘中间*/
rectangle(X(0) - BIAN / 2, Y(0) - BIAN + 10, X(8) + BIAN / 2, Y(9) + BIAN - 10); /*棋盘外框*/
rectangle(X(0) - BIAN / 2 + 3, Y(0) - BIAN + 10 + 3, X(8) + BIAN / 2 - 3, Y(9) + BIAN - 10 - 3); /*棋盘外框*/
//棋盘纵向编号标注
for (int i = 0; i < Col; i++) {
//{"一", "二", "三", "四", "五", "六", "七", "八", "九"};
setcolor(RED);
setfont(GZ / 3, 0, "隶书");
outtextxy(X(i) - BIAN * 1 / 8, Y(10) - BIAN * 4 / 10, nz[8 - i]);
//{'1', '2', '3', '4', '5', '6', '7', '8', '9'};
setfont(GZ / 2, 0, "隶书");
setcolor(EGERGB(0x4E, 0xC9, 0xB0));
outtextxy(X(i) - BIAN * 1 / 10, Y(0) - BIAN * 8 / 10, mz[i]);
}
setbkmode(TRANSPARENT);
setcolor(RED);
setfont(GZ / 2, 0, "隶书");
outtextxy(X(2) + 5, Y(4) + GZ / 4, "楚河 汉界"); /*字体坐标*/
setfont(GZ, 0, "隶书");
outtextxy(X(9) + BIAN / 2, GZ / 4, "中国"); /*标题输出*/
outtextxy(X(9) + BIAN / 2, GZ + GZ / 4, "象棋");
setcolor(WHITE); /*棋谱输出区*/
rectangle(X(10) - GZ / 3, Y(3), X(12) - GZ / 3, Y(9));
}
//画单个棋子
void huaqizi(int y, int x, const char* zi, DWORD hh) {
setcolor(MEDIUMSPRINGGREEN);
setfillcolor(GREENYELLOW);
fillellipse(X(x), Y(y), R, R, NULL);
setfillcolor(YELLOW);
fillellipse(X(x), Y(y), R - 4, R - 4, NULL);
setcolor(hh);
setfont(GZ * 6 / 10, 0, "隶书");
outtextxy(X(x) - (GZ * 6 / 10) / 2, Y(y) - (GZ * 6 / 10) / 2, zi);
}
//画选中棋子
void xuanqizi(int x, int y, const char* zi, int hh) {
setcolor(MEDIUMSPRINGGREEN);
setfillcolor(BLACK);
fillellipse(X(x), Y(y), R, R, NULL);
setfillcolor(YELLOW);
fillellipse(X(x), Y(y), R - 4, R - 4, NULL);
setfont(GZ * 6 / 10, 0, "隶书");
setcolor(hh);
outtextxy(X(x) - (GZ * 6 / 10) / 2, Y(y) - (GZ * 6 / 10) / 2, zi);
}
//画所有棋子1
void draw() {
cleardevice();
huaqipan();
for (int i = 0; i < Row; i++) {
for (int j = 0; j < Col; j++) {
if (Map[i][j].Name != -1 ) {
huaqizi(i, j, chessName[Map[i][j].Name], Map[i][j].type);
}
}
}
}
//画所有棋子2
void draw1(chessMartix * Q) {
huaqipan();
for (int k = 0; k < Q->num; k++) {
huaqizi(Q->data[k].y, Q->data[k].x, chessName[Q->data[k].Name], Map[Q->data[k].y][Q->data[k].x].type);
}
}
//画选择“再来”“退出”
void drawxuanze(int i) {
setcolor(WHITE);
if (i == 2) { //标注 退出
rectangle(X(10) + GZ * 7 / 10, Y(1) + GZ * 2 / 10, X(11) + GZ * 6 / 10, Y(1) + GZ * 7 / 10 );
} else if (i == 3) { //标注 再来
rectangle(X(9) + GZ * 7 / 10, Y(1) + GZ * 2 / 10, X(10) + GZ * 6 / 10, Y(1) + GZ * 7 / 10 );
} else if (i == 1) { //不 标注
setcolor(BLACK);
rectangle(X(10) + GZ * 7 / 10, Y(1) + GZ * 2 / 10, X(11) + GZ * 6 / 10, Y(1) + GZ * 7 / 10 );
rectangle(X(9) + GZ * 7 / 10, Y(1) + GZ * 2 / 10, X(10) + GZ * 6 / 10, Y(1) + GZ * 7 / 10 );
}
}
//棋谱长度
int qipulength(link* qipu) {
int length = 0;
link* p = qipu->next;
while (p) {
p = p->next;
length++;
}
return length;
}
//画棋谱 棋谱输出
void huaqipu(link *qipu) {
setfont(GZ / 4, 0, "隶书");
setcolor(WHITE);
char str1[30];
link* temp = qipu->next;
int m = qipulength(qipu);
int num_rows = 18; //显示qipu的总行数
if (m > num_rows) {
while (temp->next) {
temp = temp->next;
}
int x = num_rows;
while (--x) {
temp = temp->prior;
}
for (int i = 0; i < num_rows; i++) { // qipu显示超过18行时
if (temp->ID >= 0 && temp->ID < 16) { // 黑棋
if (temp->y == temp->cy) { // 平着走
sprintf(str1, "%s %c 平 %c", chessName[M[temp->ID].Name], mz[(temp->x)], mz[(temp->cx )]);
} else if (temp->cx == temp->x) { // 竖着走
if (temp->cy > temp->y) {
sprintf(str1, "%s %c 进 %c", chessName[M[temp->ID].Name], mz[(temp->x)], mz[(temp->cy - temp->y) - 1]);
} else {
sprintf(str1, "%s %c 退 %c", chessName[M[temp->ID].Name], mz[(temp->x)], mz[(temp->y - temp->cy) - 1]);
}
} else { // 斜着走
if (temp->cy > temp->y) {
sprintf(str1, "%s %c 进 %c", chessName[M[temp->ID].Name], mz[(temp->x)], mz[(temp->cx )]);
} else {
sprintf(str1, "%s %c 退 %c", chessName[M[temp->ID].Name], mz[(temp->x)], mz[(temp->cx )]);
}
}
}
if (temp->ID >= 16 && temp->ID < 32) { // 红棋
if (temp->y == temp->cy) { // 平着走
sprintf(str1, "%s %s 平 %s", chessName[M[temp->ID].Name], nz[8 - (temp->x)], nz[8 - (temp->cx)]);
} else if (temp->cx == temp->x) { // 竖着走
if (temp->cy < temp->y) {
sprintf(str1, "%s %s 进 %s", chessName[M[temp->ID].Name], nz[8 - (temp->x)], nz[(temp->y - temp->cy) - 1]);
} else {
sprintf(str1, "%s %s 退 %s", chessName[M[temp->ID].Name], nz[8 - (temp->x)], nz[(temp->cy - temp->y) - 1]);
}
} else { // 斜着走
if (temp->cy < temp->y) {
sprintf(str1, "%s %s 进 %s", chessName[M[temp->ID].Name], nz[8 - (temp->x)], nz[8 - (temp->cx)]);
} else {
sprintf(str1, "%s %s 退 %s", chessName[M[temp->ID].Name], nz[8 - (temp->x)], nz[8 - (temp->cx)]);
}
}
}
xyprintf(X(10) + GZ / 10, Y(3) + GZ / 10 + (GZ / 4 + 5) * i, str1);
temp = temp->next;
}
} else {
for (int i = 0; i < m; i++) { // qipu显示不满18行时
if (temp->ID >= 0 && temp->ID < 16) { // 黑棋
if (temp->y == temp->cy) { // 平着走
sprintf(str1, "%s %c 平 %c", chessName[M[temp->ID].Name], mz[(temp->x)], mz[(temp->cx)]);
} else if (temp->cx == temp->x) { // 竖着走
if (temp->cy > temp->y) {
sprintf(str1, "%s %c 进 %c", chessName[M[temp->ID].Name], mz[(temp->x)], mz[(temp->cy - temp->y) - 1]);
} else {
sprintf(str1, "%s %c 退 %c", chessName[M[temp->ID].Name], mz[(temp->x)], mz[(temp->y - temp->cy) - 1]);
}
} else { // 斜着走
if (temp->cy > temp->y) {
sprintf(str1, "%s %c 进 %c", chessName[M[temp->ID].Name], mz[(temp->x)], mz[(temp->cx)]);
} else {
sprintf(str1, "%s %c 退 %c", chessName[M[temp->ID].Name], mz[(temp->x)], mz[(temp->cx)]);
}
}
}
if (temp->ID >= 16 && temp->ID < 32) { // 红棋
if (temp->y == temp->cy) { // 平着走
sprintf(str1, "%s %s 平 %s", chessName[M[temp->ID].Name], nz[8 - (temp->x)], nz[8 - (temp->cx)]);
} else if (temp->cx == temp->x) { // 竖着走
if (temp->cy < temp->y) {
sprintf(str1, "%s %s 进 %s", chessName[M[temp->ID].Name], nz[8 - (temp->x)], nz[(temp->y - temp->cy) - 1]);
} else {
sprintf(str1, "%s %s 退 %s", chessName[M[temp->ID].Name], nz[8 - (temp->x)], nz[(temp->cy - temp->y) - 1]);
}
} else { // 斜着走
if (temp->cy < temp->y) {
sprintf(str1, "%s %s 进 %s", chessName[M[temp->ID].Name], nz[8 - (temp->x)], nz[8 - (temp->cx)]);
} else {
sprintf(str1, "%s %s 退 %s", chessName[M[temp->ID].Name], nz[8 - (temp->x)], nz[8 - (temp->cx)]);
}
}
}
xyprintf(X(10) + GZ / 10, Y(3) + GZ / 10 + (GZ / 4 + 5) * i, str1);
temp = temp->next;
}
}
}
//走吃棋子
void zouchi(link * qipu, int x, int y, int cx, int cy) {
int zouchi;
QMap temp;
temp = Map[y][x];
//判断是走是吃,并保存被吃棋子
if (Map[cy][cx].Name != NONE && Map[y][x].type != Map[cy][cx].type) {
zouchi = chi;
top = pushN(N, top, Map[cy][cx]); //被吃棋子存入N[]
} else {
zouchi = zou;
}
//走棋子后的元素变更
Map[cy][cx] = temp ; //新棋位改为新棋子颜色 ID Name
Map[cy][cx].x = cx; //取得新坐标
Map[cy][cx].y = cy;
Map[y][x].Name = NONE; //旧棋位 跟新为 NONE
Map[y][x].ID = NONE;
zoudong = true; //棋子已走动
qipu = insterLink(qipu, x, y, cx, cy, temp.ID, zouchi); //登记入棋谱
}
//游戏结束
void Gameover() { //根据棋盘中 将 帅 的存在,给出gameover的值 true
int i = 1;
int j = 1;
for (int m = 0; m < Row; m++) {
for (int n = 0; n < Col; n++) {
if (Map[m][n].Name == 4) { //数组Map中找到4,表示红将还没死
i = 0;
}
if (Map[m][n].Name == 11) { //数组Map中找到11,表示黑将还没死
j = 0;
}
}
}
//游戏结束后给出结果和选择
if (i || j) {
setfont(GZ * 6 / 10, 0, "隶书");
if (i) { //i=1 则黑棋胜
setcolor(RED);
outtextxy(X(9) + GZ / 2, Y(2), "=红旗胜=");
}
if (j) { //j=1 则红棋胜
setcolor(BLUE);
outtextxy(X(9) + GZ / 2, Y(2), "=黑旗胜=");
}
setcolor(WHITE);
setfont(GZ * 3 / 10, 0, "隶书"); //改变字体大小
outtextxy(X(9) + GZ * 5 / 10, Y(1) + GZ * 3 / 10, " 再来");
outtextxy(X(9) + GZ * 15 / 10, Y(1) + GZ * 3 / 10, " 退出");
gameover = true;
}
}
//走(车 炮)判断
int is_go1(int x, int y, int cx, int cy) {
int count = NONE; //返回值 走棋子之间的棋子数 0 1 表示车可以走吃,0 2 表示砲可以走吃。
if (y == cy && x < cx) {
for (int i = x ; i <= cx; i++) {
if (Map[y][i].Name != NONE) {
count++;
};
}
} else if (y == cy && x > cx) {
for (int i = x ; i >= cx; i--) {
if (Map[y][i].Name != NONE) {
count++;
};
}
} else if (x == cx && y < cy) {
for (int i = y ; i <= cy; i++) {
if (Map[i][x].Name != NONE) {
count++;
};
}
} else if (x == cx && y > cy) {
for (int i = y ; i >= cy; i--) {
if (Map[i][x].Name != NONE) {
count++;
};
}
}
return count;
}
//走(马) 判断
int is_go2(int x, int y, int cx, int cy) {
int count = NONE;
if (5 == (abs(x - cx)*abs(x - cx) + abs(y - cy)*abs(y - cy))) { //马可以走的八个点的距离为5
if (((2 == (x - cx)) && (Map[y][x - 1].Name != NONE)) ||
((2 == (cx - x)) && (Map[y][x + 1].Name != NONE)) ||
((2 == (y - cy)) && (Map[y - 1][x].Name != NONE)) ||
((2 == (cy - y)) && (Map[y + 1][x].Name != NONE))) { //憋马脚的四个情况
count = NONE;
} else if (Map[cy][cx].Name != NONE) {
count = 1; //吃
} else {
count = 0; //走
}
}
return count;
}
//走(象)判断
int is_go3(int x, int y, int cx, int cy) {
int count = NONE;
if (8 == (abs(x - cx)*abs(x - cx) + abs(y - cy)*abs(y - cy))) { //象可以走的四个点的距离为8
if (((2 == (x - cx) && 2 == (y - cy)) && (Map[y - 1][x - 1].Name != NONE)) ||
((2 == (cx - x) && 2 == (y - cy)) && (Map[y - 1][x + 1].Name != NONE)) ||
((2 == (cx - x) && 2 == (cy - y)) && (Map[y + 1][x + 1].Name != NONE)) ||
((2 == (x - cx) && 2 == (cy - y)) && (Map[y + 1][x - 1].Name != NONE))) { //憋象眼的四个情况
count = NONE;
} else if (Map[cy][cx].Name != NONE) {
count = 1; //吃
} else {
count = 0; //走
}
}
return count;
}
//走(士)判断
int is_go4(int x, int y, int cx, int cy) {
int count = NONE;
if (2 == (abs(x - cx)*abs(x - cx) + abs(y - cy)*abs(y - cy)) &&
(cx <= 5 && cx >= 3) && ((cy >= 0 && cy <= 2) || (cy <= 9 && cy >= 7))) { //士可以走的四个点的距离为2
if (Map[cy][cx].Name != NONE) {
count = 1; //吃
} else {
count = 0; //走
}
}
return count;
}
//检查是否对老将了
int duilaojiang() {
int count = 0;
int x, y;
int cx, cy;
for (int m = 0; m < Row; m++) { //从Map中找出(将)与(帅)的坐标并记录
for (int n = 0; n < Col; n++) {
if (Map[m][n].Name == 4) {
x = n;
y = m;
}
if (Map[m][n].Name == 11) {
cx = n;
cy = m;
}
}
}
if (x == cx) { //检查(将)与(帅)之间有没有棋子 count=2 为没棋子,即为对老将了
for (int i = y; i <= cy; i++) {
if (Map[i][x].Name != NONE) {
count++;
}
}
}
return count;
}
//走(将)判断
int is_go5(int x, int y, int cx, int cy) {
int count = NONE;
//对老将且目标棋位只能是有棋子,即只能将吃帅或帅吃将,不能走到其他没棋子的位置
if (duilaojiang() == 2 && Map[cy][cx].Name != NONE) {
count = 2;
}
//将可以走的四个点的距离为1 且将帅的走动范围在田字格内
if (1 == (abs(x - cx)*abs(x - cx) + abs(y - cy)*abs(y - cy)) &&
(cx <= 5 && cx >= 3) && ((cy >= 0 && cy <= 2) || (cy <= 9 && cy >= 7))) {
if (Map[cy][cx].Name != NONE ) {
if (Map[y][x].type != Map[cy][cx].type) {
count = 1; //吃
}
} else {
count = 0; //走
}
}
return count;
}
//走(兵)判断
int is_go6(int x, int y, int cx, int cy) {
int count = NONE;
//卒只能向前的1个点走且过河后可以横着走的距离为1
if ((1 == (abs(x - cx)*abs(x - cx) + abs(y - cy)*abs(y - cy)))) { //能走一格,有四个点
if (M[Map[y][x].ID].type == BLACK && y < 5 && x == cx) { //黑棋 y<5表示没过河,x==cx表示只能竖着走
if (cy > y) { //黑棋 向前走
if (Map[cy][cx].Name != NONE) {
count = 1; //吃
} else {
count = 0; //走
}
} else { //不能后退
count = NONE;
}
} else if (Map[y][x].type == BLACK && y > 4) { //黑棋过河后 不限制x==cx 就可以横着走
if (cy >= y) { //cy>=y表示可以向前走,可以横着走,不能后退
if (Map[cy][cx].Name != NONE) {
count = 1; //吃
} else {
count = 0; //走
}
} else { //不能后退
count = NONE;
}
} else if (Map[y][x].type == RED && y > 4 && x == cx) { //红棋没过河处理
if (cy < y) {
if (Map[cy][cx].Name != NONE) {
count = 1; //吃
} else {
count = 0; //走
}
} else {
count = NONE;
}
} else if (Map[y][x].type == RED && y < 5) { //红棋过河处理
if (cy <= y) {
if (Map[cy][cx].Name != NONE) {
count = 1; //吃
} else {
count = 0; //走
}
} else {
count = NONE;
}
}
}
return count;
}
//走棋子
void zouqizi(link * qipu, int x, int y, int cx, int cy) {
zoudong = false; //走过了,为了flag红黑棋的选择
int n, n1, n2, n3, n4, n5;
switch (Map[y][x].Name) {
case 车:
case 車:
n = is_go1(x, y, cx, cy); //走棋子n==0 //吃棋子n==1
if (n == 0 || (n == 1 && Map[y][x].type != Map[cy][cx].type)) { //是对方棋子才能走
zouchi(qipu, x, y, cx, cy);
break;
}
break;
case 马:
case 馬:
n1 = is_go2(x, y, cx, cy); //走棋子n1==0 //吃棋子n1==1
if (n1 == 0 || (n1 == 1 && Map[y][x].type != Map[cy][cx].type)) {
zouchi(qipu, x, y, cx, cy);
break;
}
break;
case 象:
case 相:
n2 = is_go3(x, y, cx, cy); //走棋子n2==0 //吃棋子n2==1
if (n2 == 0 || (n2 == 1 && Map[y][x].type != Map[cy][cx].type)) {
zouchi(qipu, x, y, cx, cy);
break;
}
break;
case 士:
case 仕:
n3 = is_go4(x, y, cx, cy); //走棋子n3==0 //吃棋子n3==1
if (n3 == 0 || (n3 == 1 && Map[y][x].type != Map[cy][cx].type)) {
zouchi(qipu, x, y, cx, cy);
break;
}
break;
case 将:
case 帅:
n4 = is_go5(x, y, cx, cy); //对老将n4==2 //走棋子n4==0 //吃棋子n4==1
if ((n4 == 2) || (n4 == 0) || (n4 == 1 )) {
zouchi(qipu, x, y, cx, cy);
break;
}
break;
case 卒:
case 兵:
n5 = is_go6(x, y, cx, cy); //走棋子n5==0 //吃棋子n5==1
if (n5 == 0 || (n5 == 1 && Map[y][x].type != Map[cy][cx].type)) {
zouchi(qipu, x, y, cx, cy);
break;
}
break;
case 炮:
case 砲:
n = is_go1(x, y, cx, cy); //走棋子0 //吃棋子2
if (n == 0 || (n == 2 && Map[y][x].type != Map[cy][cx].type)) {
zouchi(qipu, x, y, cx, cy);
}
break;
default:
break;
}
}
//悔棋刪链尾结点
link* deleteqipu(link * qipu) {
link* temp = qipu;
while (temp->next) { //移动指针temp到qiup的最后一个节点
temp = temp->next;
}
temp->prior->next = temp->next; //temp的上一个节点的next 指向 temp的下一个节点
free(temp); //释放节点temp
return qipu;
}
//悔棋
void huiqi(link * qipu) {
QMap ctemp; //临时棋盘交换点
link* temp = qipu; //临时qipu节点
if (temp || temp->ID != -2) { //temp不空,或不是首元结点
while (temp->next) {
temp = temp->next;
}
ctemp = Map[temp->cy][temp->cx]; //存储交换点
Map[temp->y][temp->x] = ctemp ;
Map[temp->y][temp->x].x = temp->x;
Map[temp->y][temp->x].y = temp->y;
if (1 == temp->zouchi) {
Map[temp->cy][temp->cx] = N[top]; //从栈N[]中恢复被吃棋子
top = popN(top);
} else {
Map[temp->cy][temp->cx].Name = NONE; //恢复为无棋子
Map[temp->cy][temp->cx].ID = NONE; //恢复为无棋子
}
qipu = deleteqipu(qipu); //恢复新棋谱
zoudong = true; //已悔棋
} else {
printf("已悔棋到顶!");
}
}
//开始下棋
void mouseMap(link * qipu, chessMartix * Q) {
hui:
qipu = initqipu(qipu);
initMap(Q);
show();
draw();
gameover = false; //true表示游戏结束,false表示游戏未结束
flag = true; //true表示黑棋子, false表示红棋子
is_Select = true; //true表示先选棋子,false表示后落棋子
mouse_msg msg; //开始鼠标操作 定义鼠标名
for (; is_run(); delay_fps(50)) {
Gameover(); //1.检查是否结束 获取gameover值
while (mousemsg()) {
msg = getmouse(); //2.获取鼠标信息
}
//3.点击鼠标坐标msg.x,msg.y转为棋盘坐标i,j
int i = (int)(msg.x - BIAN + R) / GZ; //棋子的横坐标
int j = (int)(msg.y - BIAN + R) / GZ; //棋子的纵坐标
//4.gameover=true后的操作
int A = 1;
while (gameover == true) {
if (((msg.x > (X(10) + GZ * 7 / 10)) && (msg.x < (X(11) + GZ * 6 / 10)))
&& ((msg.y > Y(1) + GZ * 2 / 10) && (msg.y < Y(1) + GZ * 7 / 10))) {
A = 2;
drawxuanze(A); //标注 退出
} else if (((msg.x > (X(9) + GZ * 7 / 10)) && (msg.x < (X(10) + GZ * 6 / 10)))
&& ((msg.y > Y(1) + GZ * 2 / 10) && (msg.y < Y(1) + GZ * 7 / 10))) {
A = 3;
drawxuanze(A); //标注 再来
} else {
A = 1; //取消 标注
drawxuanze(A);
}
//左键点击后
if (A == 3 && msg.is_left() && msg.is_down()) { //选再来后
gameover = false; //游戏重新开始
free(qipu); //释放qipu
top = -1; //栈N回到栈顶
goto hui; //选再来后,回到游戏初始代码
} else if (A == 2 && msg.is_left() && msg.is_down()) { //选退出后
free(qipu); //释放qipu
closegraph(); //选退出 关闭窗口
} else {
break;
}
}
//5.下棋未结束时 在棋盘范围内 左键按下
if (msg.is_left() && msg.is_down() && i < 9 && j < 10 && gameover != true) {
//Ai();
int x, y; // 需要保存所选棋子坐标和棋子编号
if (flag == true ) { // 黑棋先走
if (is_Select == true) { // 选棋子
if ( Map[j][i].Name != NONE && Map[j][i].type == BLACK) {
xuanqizi(i, j, chessName[Map[j][i].Name], Map[j][i].type);
y = j;
x = i;
is_Select = false;
Sleep(150);
}
} else if (is_Select == false) { //落棋子
zouqizi(qipu, x, y, i, j);
Sleep(150);
show();
displayqipu(qipu);
cleardevice();
draw();
huaqipu(qipu);
is_Select = true;
if (zoudong == false) {
flag = true;
} else {
flag = false;
PlaySound(TEXT(".//image/click.wav"), NULL, SND_FILENAME | SND_ASYNC);
}
}
}
//再走紅棋
else if (flag == false) {
//选棋子
if (is_Select == true) {
if ( Map[j][i].Name != NONE && Map[j][i].type == RED) {
xuanqizi(i, j, chessName[Map[j][i].Name], Map[j][i].type);
y = j;
x = i;
is_Select = false;
Sleep(150);
}
}
//落棋子
else if (is_Select == false) {
zouqizi(qipu, x, y, i, j);
Sleep(200);
show();
displayqipu(qipu);
cleardevice();
draw();
huaqipu(qipu);
is_Select = true;
if (zoudong == false) {
flag = false;
} else {
flag = true;
PlaySound(TEXT(".//image/click.wav"), NULL, SND_FILENAME | SND_ASYNC);
}
}
}
}
//6.下棋未结束时在棋盘范围内 按下右键 悔棋
else if (msg.is_right() && msg.is_down() && i < 9 && j < 10 && gameover != true) {
if (qipu->next != NULL) {
huiqi(qipu);
Sleep(200);
show();
displayqipu(qipu);
cleardevice();
draw();
huaqipu(qipu);
if (flag == true) {
flag = false;
PlaySound(TEXT(".//image/click.wav"), NULL, SND_FILENAME | SND_ASYNC);
} else {
flag = true;
PlaySound(TEXT(".//image/click.wav"), NULL, SND_FILENAME | SND_ASYNC);
}
}
}
}
}
void mouseQ(link * qipu) {
//鼠标操作前定义条件
gameover = false; //true表示游戏结束,false表示未游戏结束
flag = true; //true表示黑棋子, false表示红棋子
is_Select = true; //true表示先选棋子,false表示后落棋子
//开始鼠标操作
mouse_msg msg;
for (; is_run(); delay_fps(20)) {
//检查是否结束
Gameover();
//获取鼠标信息
while (mousemsg()) {
msg = getmouse();
}
//点击鼠标坐标msg.x,msg.y转为棋盘坐标i,j
int i = (int)(msg.x - BIAN + R) / GZ; //棋子的横坐标
int j = (int)(msg.y - BIAN + R) / GZ; //棋子的纵坐标
//下棋未结束时在-------棋盘范围内-----左键按下---走棋子
if (msg.is_left() && msg.is_down() && i < 9 && j < 10 && gameover != true) {
//Ai();
int x, y; // 需要保存所选棋子坐标和棋子编号
if (flag == true ) { // 黑棋先走
if (is_Select == true) { // 选棋子
if ( Map[j][i].Name != NONE && Map[j][i].type == BLACK) {
xuanqizi(i, j, chessName[Map[j][i].Name], Map[j][i].type);
y = j;
x = i;
is_Select = false;
Sleep(150);
}
} else if (is_Select == false) { //落棋子
zouqizi(qipu, x, y, i, j);
Sleep(200);
show();
cleardevice();
draw();
is_Select = true;
if (zoudong == false) {
flag = true;
} else {
flag = false;
PlaySound(TEXT(".//image/click.wav"), NULL, SND_FILENAME | SND_ASYNC);
}
}
}
//再走紅棋
else if (flag == false) {
//选棋子
if (is_Select == true) {
for (int m = 0; m < Row; m++) {
for (int n = 0; n < Col; n++) {
if (Map[m][n].x == i && Map[m][n].y == j && Map[m][n].Name != NONE && Map[m][n].type == RED) {
xuanqizi(n, m, chessName[Map[m][n].Name], Map[m][n].type);
y = m;
x = n;
is_Select = false;
Sleep(150);
}
}
}
}
//落棋子
else if (is_Select == false) {
zouqizi(qipu, x, y, i, j);
Sleep(200);
show();
cleardevice();
draw();
is_Select = true;
if (zoudong == false) {
flag = false;
} else {
flag = true;
PlaySound(TEXT(".//image/click.wav"), NULL, SND_FILENAME | SND_ASYNC);
}
}
}
}
//下棋未结束时在棋盘范围内右键按下 悔棋
else if (msg.is_right() && msg.is_down() && i < 9 && j < 10 && gameover != true) {
if (qipu->next == NULL) {
gameover = true;
break;
} else {
huiqi(qipu);
Sleep(200);
show();
cleardevice();
draw();
}
}
}
}
int main() {
system("mode con: cols=55 lines=50");
initgraph(weight, high);
//棋盘矩阵Q 代替 Map[][]存储棋子
chessMartix Q;
Q.n = 10;
Q.m = 9;
Q.num = 32;
//定义棋谱链
link *qipu = NULL;
//窗口界面操作
mouseMap(qipu, &Q);
closegraph();
return 0;
}