算法习题---4-1象棋(UVa1589)
一:题目
在黑方只有一个“将”的情况下,红方只有(车、马、炮)(可以多个)、帅的情况下,判断黑方是否被将死
(一)题目详解
其中棋盘按照坐标方式表示,左上角为(1,1),列数最大9,行数最大10
G 表示 将帅
R 表示 车
H 表示 马
C 表示 炮
(二)样例输入
2 1 4 //第一行第一个数字:表示红方有2个棋子 第二三个表示黑方“将”位置在(1,4) G 10 5 //表示红方“帅”在(10,5) R 6 4 //表示红方“车”在(6,4) 空行表示一次输入结束 3 1 5 //第一行第一个数字:表示红方有3个棋子 第二三个表示黑方“将”位置在(1,5) H 4 5 //表示红方“马”在(4,5) G 10 5 //表示红方“帅”在(10,5) C 7 5 //表示红方“炮”在(7,5) 0 0 0 //全0表示结束
二:代码实现
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <string.h> #define N 7 int Num; //用于保存获取的个数 int xq[N][3]; //棋盘数据
进行棋盘、坐标数据获取
int getData(int* r,int* c) { int n; int i=0; //进行数据获取 while (1) { //获取数据起始位置 scanf("%d %d %d", &n, r, c); //n在(2,7)之间 Num = n; if (n == 0) return -1; //全部结束 //获取数据,填充棋盘 while (n--) { getchar(); scanf("%c %d %d", (char*)&xq[i][0], &xq[i][1], &xq[i][2]); i++; } return 1; //本次输入结束 } }
判断中间是否有棋子,返回棋子个数
int judgeCaseInMid(int r1,int c1, int r2, int c2) { int j,min,max,count=0; min = max = 0; if (r1 == r2) //判断行上是否同行中间有棋子 { c1 > c2 ? min = c2, max = c1 : min = c1, max = c2; for (j = 0; j < Num; j++) if (xq[j][1] == r1 && (xq[j][2]>min&&xq[j][2] < max)) count++; //有中间棋子 } if (c1 == c2) //判断列上是否同列中间有棋子 { r1 > r2 ? min = r2, max = r1 : min = r1, max = r2; for (j = 0; j < Num; j++) if (xq[j][2] == c1 && (xq[j][1]>min&&xq[j][1] < max)) count++; //有中间棋子 } return count; //返回棋子个数 }
单独将马拿出来处理:因为马特殊
//判断马是否将死黑方 (r1,c1)为马,(r2,c2)为敌将 bool judgeCaseForHorse(int r1, int c1, int r2, int c2) { //利用勾股定理 int a, b; a = r1 - r2; b = c1 - c2; if (a*a + b*b == 5) { //考虑别马腿 if ((r1 - r2) == 2) { for (int i = 0; i < Num; i++) if (xq[i][1] == r1 - 1 && xq[i][2] == c1) return false; } if ((r1 - r2) == -2) { for (int i = 0; i < Num; i++) if (xq[i][1] == r1 + 1 && xq[i][2] == c1) return false; } if ((c1 - c2) == 2) { for (int i = 0; i < Num; i++) if (xq[i][1] == c1 - 1 && xq[i][2] == r1) return false; } if ((c1 - c2) == -2) { for (int i = 0; i < Num; i++) if (xq[i][1] == c1 + 1 && xq[i][2] == r1) return false; } return true; } return false; }
判断黑方将下一步是否可以走
//G是将 R是车 C是炮 H是马 int judgeCKByNextByte(int r, int c) { int i; //遍历棋盘红方数据,判断是否将死这一步 for (i = 0; i < Num;i++) { switch (xq[i][0]) { case 'G': //判断将 //判断黑方是否在同一列 if (xq[i][2] == c) if (!judgeCaseInMid(r, c, xq[i][1], xq[i][2])) return 1; //将死 break; case 'R': //判断车 //车可以横向纵向走 //先判断是否在同一行或者同一列 if (xq[i][1] == r || xq[i][2] == c) //同行/列 //判断是否中间有棋子 if (!judgeCaseInMid(r, c, xq[i][1], xq[i][2])) return 1; //将死 break; case 'C': //判断炮 if (xq[i][1] == r || xq[i][2] == c) //同行/列 //判断是否中间有棋子 if (1==judgeCaseInMid(r, c, xq[i][1], xq[i][2])) return 1; //将死 break; case 'H': //判断马 if (judgeCaseForHorse(xq[i][1], xq[i][2], r, c)) return 1; break; } } return 0; }
判断是否将死黑方
bool judgeCK(int r, int c) { //判断将的运行空间(1,4)->(1,6) // (2,4)->(2,6) // (3,4)->(3,6) if (r >= 1 && r < 3)//向下走 if (judgeCKByNextByte(r+1, c) == 0) return false; //未将死 if (r > 1 && r <= 3)//向上走 if (judgeCKByNextByte(r - 1, c) == 0) return false; //未将死 if (c >= 4 && c < 6)//向右走 if (judgeCKByNextByte(r, c + 1) == 0) return false; //未将死 if (c > 4 && c <= 6)//向左走 if (judgeCKByNextByte(r, c - 1) == 0) return false; //未将死 if ((r == 1 && c == 4) || (r == 2 && c == 5))//右下走 if (judgeCKByNextByte(r + 1, c + 1) == 0) return false; //未将死 if ((r == 3 && c == 6) || (r == 2 && c == 5))//左上走 if (judgeCKByNextByte(r - 1, c - 1) == 0) return false; //未将死 if ((r == 1 && c == 6) || (r == 2 && c == 5))//左下走 if (judgeCKByNextByte(r + 1, c - 1) == 0) return false; //未将死 if ((r == 3 && c == 4) || (r == 2 && c == 5))//右上走 if (judgeCKByNextByte(r - 1, c + 1) == 0) return false; //未将死 return true; //将死 }
主函数
int main() { int row, col; freopen("data.in", "r", stdin); freopen("data.out", "w", stdout); while (1) { //进行数据输入 if (getData(&row, &col) == -1) return 0; //进行数据处理,判断是否将死 if (judgeCK(row, col)) printf("YES\n"); else printf("NO\n"); } freopen("CON", "r", stdin); freopen("CON", "w", stdout); return 0; }