Uva- 1589 - Xiangqi

4 篇文章 0 订阅
3 篇文章 0 订阅

原文地址:https://blog.qjm253.cn/?p=384

象棋(Xiangqi, ACM/ICPC Fuzhou 2011, UVa1589)

原题地址:Uva1589

考虑一个象棋残局,其中红方有n(2≤n≤7)个棋子,黑方只有一个将。红方除了有一个帅(G)之外还有3种可能的棋子:车(R),马(H),炮(C),并且需要考虑“蹩马腿”(如图4-4所示)与将和帅不能照面(将、帅如果同在一条直线上,中间又不隔着任何棋子的情况下,走子的一方获胜)的规则。

输入所有棋子的位置,保证局面合法并且红方已经将军。你的任务是判断红方是否已经把黑方将死。关于中国象棋的相关规则请参见原题。

image

代码实现

/**
 * 1589 - Xiangqi
 */
#include <iostream>
#include <array>

using namespace std;

struct Point {
    int x, y;
    char type;
};

int hasPartition(const array<Point, 7> &reds, const Point &p1, const Point &p2, int redNum){
    int partitionNum = 0;
    if(p1.x != p2.x && p1.y != p2.y)    //都不在同一条线上,肯定没有分隔子
        return 0;
    else if(p1.x == p2.x){
        int spanY = p1.y - p2.y;
        for(int i = 0; i < redNum; i++){
            if(reds[i].x == p1.x && ((spanY > 0 && reds[i].y > p2.y && reds[i].y < p1.y) || (spanY < 0 && reds[i].y > p1.y && reds[i].y < p2.y)))
                ++partitionNum;
        }
    } else {
        int spanX = p1.x - p2.x;
        for(int i = 0; i < redNum; i++){
            if(reds[i].y == p1.y && ((spanX > 0&& reds[i].x > p2.x && reds[i].x < p1.x) || (spanX < 0 && reds[i].x > p1.x && reds[i].x < p2.x)))
                ++partitionNum;
        }
    }
    return partitionNum;
}

bool judgeG(const array<Point, 7> &reds, const Point &blackG, int redNum, int pos) {
    if(reds[pos].y != blackG.y)
        return false;
    return hasPartition(reds, blackG, reds[pos], redNum) == 0;
}

bool judgeR(const array<Point, 7> &reds, const Point &blackG, int redNum, int pos) {
    if(reds[pos].x != blackG.x && reds[pos].y != blackG.y)
        return false;
    return hasPartition(reds, reds[pos], blackG, redNum) == 0;
}

bool judgeC(const array<Point, 7> &reds, const Point &blackG, int redNum, int pos) {
    if(reds[pos].x != blackG.x && reds[pos].y != blackG.y)
        return false;
    return hasPartition(reds, reds[pos], blackG, redNum) == 1;
}

bool judgeH(const array<Point, 7> &reds, const Point &blackG, int redNum, int pos) {
    int subX = blackG.x - reds[pos].x;
    int subY = blackG.y - reds[pos].y;
    if(subX == 0 || subY == 0)
        return false;
    if(abs(subX) + abs(subY) != 3)      //在不考虑绊马脚的情况下是否可达
        return false;

    if(abs(subX) == 2){
        for(int i = 0; i < redNum; i++){
            if(reds[i].x == reds[pos].x + (subX / 2) && reds[i].y == reds[pos].y)   //检查是否绊马脚
                return false;
        }
    } else {
        for(int i = 0; i < redNum; i++){
            if(reds[i].y == reds[pos].y + (subY / 2) && reds[i].x == reds[pos].x)   //检查是否绊马脚
                return false;
        }
    }
    return true;
}

bool judge(const array<Point, 7> &reds, const Point &blackG, int redNum) {
    for (int i = 0; i < redNum; i++) {
        if(reds[i].x == blackG.x && reds[i].y == blackG.y)      //被吃掉的子
            continue;
        switch (reds[i].type) {
            case 'G':       //将
                if (judgeG(reds, blackG, redNum, i))
                    return true;
                break;
            case 'C':       //炮
                if (judgeC(reds, blackG, redNum, i))
                    return true;
                break;
            case 'H':       //马
                if (judgeH(reds, blackG, redNum, i))
                    return true;
                break;
            case 'R':       //车
                if (judgeR(reds, blackG, redNum, i))
                    return true;
                break;
            default:
                break;
        }
    }
    return false;
}

bool isInBound(const array<Point, 7> &reds, Point &blackG, int redNum){
    return blackG.y >= 4 && blackG.y <= 6 && blackG.x >= 1 && blackG.x <= 3;
}

bool doJudge(const array<Point, 7> &reds, const Point &blackG, int redNum){
    Point a{};
    a = blackG;
    if(!judge(reds, a, redNum))
        return false;
    a.x += 1;
    if(isInBound(reds, a, redNum) && !judge(reds, a, redNum))
        return false;
    a.x -= 2;
    if(isInBound(reds, a, redNum) && !judge(reds, a, redNum))
        return false;
    a.x += 1;
    a.y += 1;
    if(isInBound(reds, a, redNum) && !judge(reds, a, redNum))
        return false;
    a.y -= 2;
    return !(isInBound(reds, a, redNum) && !judge(reds, a, redNum));

}
int main() {
    int redNum;
    Point blackG{};
    array<Point, 7> reds{};
    while (cin >> redNum >> blackG.x >> blackG.y) {
        if (redNum == 0)
            break;
        for (int i = 0; i < redNum; i++)
            cin >> reds[i].type >> reds[i].x >> reds[i].y;
        cout << (doJudge(reds, blackG, redNum) ? "YES" : "NO") << endl;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值