题目描述
判断任意红方车、马、炮、帅是否将死黑方单个将。
棋盘为横纵 10 x 9 的交叉点,左上坐标为 (1,1) ,右下坐标为 (10,9) 。黑将可以走到的范围为 ([1, 3], [4, 6]) 。棋子走法等规则详见题述。
输入
输入含多个实例,总数不超过40组。每组实例包含红方将军时的局面。实例第一行分别为三个数字,表示红方棋子数 N (2 <= N <= 7) 、黑将的横坐标 X 、纵坐标 Y ;后接 N 行,每行包括字符 C (棋子类别, C(炮)、R(车)、H(马)、G(将)), 数字 x 和 y (棋子横、纵坐标) 。实例之间由空行隔开。N = X = Y = 0 表示输入结束,此组数据不处理。
输出
每组输出占一行,若能将死输出 "YES",否则输出 "NO" 。
样例
input
2 1 4
G 10 5
R 6 4
3 1 5
H 4 5
G 10 5
C 7 5
0 0 0
output
YES
NO
分析
这道题数据量非常小,但逻辑复杂。可以用面向对象的思路简化代码并增强可读性。
首先抽象出棋子类。由于没有持续走子的要求,只需要实现两种用于判断的方法:一是判断该棋子是否能走到位置A,二是判断棋子是否阻碍了一次移动。位置坐标可以用一个棋子表示,相对的,一次移动用两个棋子表示。
然后是棋盘类。棋盘类是输入数据的简单存储,同时实现判断当前局面是否将死的方法。
代码实现
首先写好棋子类。这是主要的细节处理部分。
struct Piece {
char name; int x, y;
Piece(int a, int b): name{'G'}, x{a}, y{b} {} // 构筑用于表示坐标的棋子
Piece(): name{}, x{}, y{} {
// 构筑实际棋子,从输入流读入
cin >> name >> x >> y;
}
bool capture(Piece &position) {
// 是否能走到某位置(吃子)
switch (name) {
case 'G': return y == position.y; break;
case 'C': // 炮无法进行简单判断,需要计数阻碍棋子的个数
// 炮同车
case 'R': return x == position.x || y == position.y; break;
case 'H': if (position.x == x + 1 || position.x == x - 1) {
return position.y == y + 2 || position.y == y - 2;
} else if (position.y == y + 1 || position.y == y - 1) {
return position.x == x + 2 || position.x == x - 2;
} break;
default: cerr << "unreachable branch\n"; break;
}
return false;
}
bool block(Piece &from, Piece &to) {
// 是否阻碍了一次移动(from -> to)
switch (from.name) {
case 'G': if (from.y == to.y && from.y == y) {
return (x > from.x && x < to.x) || (x < from.x && x > to.x);
} break;
case 'C': // 炮无法进行简单判断,需要计数阻碍棋子的个数
// 炮同车
case 'R': if (from.x == to.x && from.x == x) {
return (y > from.y && y < to.y) || (y < from.y && y > to.y);
} else if (from.y == to.y && from.y == y) {
return (x > from.x && x < to.x) || (x < from.x && x > to.x);
} break;
case 'H':
if (from.y + 2 == to.y && from.y + 1 == y && from.x == x) return true;
if (from.y - 2 == to.y && from.y - 1 == y && from.x == x) return true;
if (from.x + 2 == to.x && from.x + 1 == x && from.y == y) return true;
if (from.x - 2 == to.x && from.x - 1 == x && from.y == y) return true;
break;
default: cerr << "unreachable branch\n"; break;
}
return false;
}
};
然后是棋盘类。
struct Board {
int sz, x, y; vector<Piece> board;
Board() = default;
bool get() {
// 清空棋局,从输入读入一组数据
board.clear(); sz = x = y = 0;
cin >> sz >> x >> y;
for (int i = 0; i < sz; ++i) {
Piece p; board.push_back(p); // 读入一个棋子的数据
}
return sz != 0 || x != 0 || y != 0; // 只有全为0时终止循环
}
Piece position{x,y}; Piece &pos(int a, int b) {
// 构筑一个位置
position.x = a; position.y = b;
return position;
}
bool checkmate() {
// 是否将死
return bad_move(pos(x-1, y)) && bad_move(pos(x+1, y))
&& bad_move(pos(x, y-1)) && bad_move(pos(x, y+1));
}
int blocked(Piece &from, Piece &to) {
// 阻碍移动(from -> to)的棋子个数
int cnt{0}; for (Piece &p : board) {
if (p.block(from, to)) ++cnt;
}
return cnt;
}
bool bad_move(Piece &m) {
// 该位置是否不安全
if (m.x < 1 || m.x > 3 || m.y < 4 || m.y > 6) return true; // 超出范围
for (Piece &p : board) if (m.x != p.x || m.y != p.y) {
// 遍历有效棋子
if (p.capture(m)) {
if (blocked(p, m) == (p.name == 'C' ? 1 : 0)) return true;
}
}
return false;
}
};
主函数很简单。
int main() {
Board board;
while (board.get()) {
cout << (board.checkmate() ? "YES\n" : "NO\n");
}
}
总结
这道题的主要难度在于debug。
AC代码
#include <iostream>
#include <vector>
using namespace std;
struct Piece {
char name; int x, y;
Piece(int a, int b): name{'G'}, x{a}, y{b} {}
Piece(): name{}, x{}, y{} {
cin >> name >> x >> y;
}
bool capture(Piece &position) {
switch (name) {
case 'G': return y == position.y; break;
case 'C':
case 'R': return x == position.x || y == position.y; break;
case 'H': if (position.x == x + 1 || position.x == x - 1) {
return position.y == y + 2 || position.y == y - 2;
} else if (position.y == y + 1 || position.y == y - 1) {
return position.x == x + 2 || position.x == x - 2;
} break;
default: cerr << "unreachable branch\n"; break;
}
return false;
}
bool block(Piece &from, Piece &to) {
switch (from.name) {
case 'G': if (from.y == to.y && from.y == y) {
return (x > from.x && x < to.x) || (x < from.x && x > to.x);
} break;
case 'C':
case 'R': if (from.x == to.x && from.x == x) {
return (y > from.y && y < to.y) || (y < from.y && y > to.y);
} else if (from.y == to.y && from.y == y) {
return (x > from.x && x < to.x) || (x < from.x && x > to.x);
} break;
case 'H':
if (from.y + 2 == to.y && from.y + 1 == y && from.x == x) return true;
if (from.y - 2 == to.y && from.y - 1 == y && from.x == x) return true;
if (from.x + 2 == to.x && from.x + 1 == x && from.y == y) return true;
if (from.x - 2 == to.x && from.x - 1 == x && from.y == y) return true;
break;
default: cerr << "unreachable branch\n"; break;
}
return false;
}
};
struct Board {
int sz, x, y; vector<Piece> board;
Board() = default;
bool get() {
board.clear(); sz = x = y = 0;
cin >> sz >> x >> y;
for (int i = 0; i < sz; ++i) {
Piece p; board.push_back(p);
}
return sz != 0 || x != 0 || y != 0;
}
Piece position{x,y}; Piece &pos(int a, int b) {
position.x = a; position.y = b;
return position;
}
bool checkmate() {
return bad_move(pos(x-1, y)) && bad_move(pos(x+1, y))
&& bad_move(pos(x, y-1)) && bad_move(pos(x, y+1));
}
int blocked(Piece &from, Piece &to) {
int cnt{0}; for (Piece &p : board) {
if (p.block(from, to)) ++cnt;
}
return cnt;
}
bool bad_move(Piece &m) {
if (m.x < 1 || m.x > 3 || m.y < 4 || m.y > 6) return true;
for (Piece &p : board) if (m.x != p.x || m.y != p.y) {
if (p.capture(m)) {
if (blocked(p, m) == (p.name == 'C' ? 1 : 0)) return true;
}
}
return false;
}
};
int main() {
Board board;
while (board.get()) {
cout << (board.checkmate() ? "YES\n" : "NO\n");
}
}