UVa - 1589 : 逻辑判断

题目描述

判断任意红方车、马、炮、帅是否将死黑方单个将。

棋盘为横纵 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");
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容

  • 这是16年5月份编辑的一份比较杂乱适合自己观看的学习记录文档,今天18年5月份再次想写文章,发现简书还为我保存起的...
    Jenaral阅读 2,707评论 2 9
  • 不论年龄几何,都保存一份童心童趣。
    静的花田阅读 349评论 0 3
  • 今天是个值得纪念的日子,上个月的今天我决定开始减肥,到今天为止已经整整一个月了,一个月瘦了15斤。现在的我已经...
    你今天怎么样阅读 287评论 0 0
  • 我看了《鼠来宝》这部电影,里面有三只花甲鼠分别叫:艾尔文、西蒙、 西奥多。 西蒙很爱吃,他是最胖的一只,别人要一份...
    蓝色之冥阅读 1,708评论 0 3