0014 UVA1589 象棋 Xiangqi

UVA1589 象棋 Xiangqi

问题

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

代码

#include <assert.h>
#include <iostream>
#include <vector>
#include <cstring>
#define _for(i, a, b) for(int i = (a); i < (b); ++i)
using namespace std;

struct Point
{
    int x, y;
    Point(int x = 0, int y = 0) : x(x), y(y) {}
};
typedef Point Vector;

Vector operator + (const Vector &A, const Vector &B) {return Vector(A.x + B.x, A.y + B.y);}
Vector operator - (const Vector &A, const Vector &B) {return Vector(A.x - B.x, A.y - B.y);}
Vector operator * (const Vector &A, int p) {return Vector(A.x * p, A.y * p);}
Vector operator / (const Vector &A, int p) {return Vector(A.x / p, A.y / p);}
bool operator == (const Vector &A,  const Vector &B) {return A.x == B.x && A.y == B.y;}
bool operator < (const Vector &A, const Vector &B) {return A.x < B.x || A.x == B.x && A.y < B.y;}
istream & operator >> (istream &is, Vector &A) {return is >> A.x >> A.y;}
ostream & operator << (ostream &os, const Vector &A) {return os << A.x << " " << A.y;}
bool inRange(int x, int leftOrUp,  int rightOrDown) 
{
    if(leftOrUp > rightOrDown) return inRange(x, rightOrDown, leftOrUp);
    return leftOrUp <= x && x <= rightOrDown;
}

Vector blackG, redG; // 将帅
char board[16][16];
vector<Vector> DIRS = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; // 四个方向
vector<Vector> HDIRS = {{-2, -1}, {-2, 1}, {-1, -2}, {1, -2}, {-1, 2}, {1, 2}, {2, -1}, {2, 1}};
vector<Vector> redPieces;
bool inBPalace(const Vector &bPos) {return inRange(bPos.x, 1, 3) && inRange(bPos.y, 4, 6);}

// p1能不能直接飞到p2,中间有sz个棋子
bool canFly(const Vector &p1, const Vector &p2, int sz = 0)
{
    bool v = (p1.x == p2.x), h = (p1.y == p2.y); // 判断是否在一条线上
    assert(v || h); assert(!(v && h)); // 确保在一条线上但又不重合
    int highX = min(p1.x, p2.x), lowX = max(p1.x, p2.x);
    int leftY = min(p1.y, p2.y), rightY = max(p1.y, p2.y);
    int cnt = 0;
    if(v) 
    {
        _for(y, leftY + 1, rightY)
            if(board[p1.x][y] && ++cnt > sz) return false;
        return cnt == sz;
    }
    _for(x, highX + 1, lowX)
        if(board[x][p1.y] && ++cnt > sz) return false;
    return cnt == sz;
}
// mine







// mine
// r 上面的红棋子会不会吃掉b上面的黑棋子
bool checkmate(const Vector &r, const Vector &b) 
{
    bool ans = true;
    switch(board[r.x][r.y]) 
    {
        case 'G': // general 将帅照面
            return r.y == b.y && canFly(r, b);
        case 'R': // chariot 车吃将
            return (r.x == b.x || r.y == b.y) && canFly(r, b);
        case 'H': // horse 马往各个方向尝试着跳
            for(const auto &HD : HDIRS)
            {
                Vector hPos = r + HD, legPos = r + HD / 2;
                if(hPos == b && board[legPos.x][legPos.y] == 0) return true;
            }
            return false;
        case 'C': // 炮打
            return (r.x == b.x || r.y == b.y) && canFly(r, b, 1);
        default:
            assert(false);
            break;
    }
    // return false;
}

bool canWin() {
    assert(inBPalace(blackG));
    if(blackG.y == redG.y && canFly(blackG, redG))return false;
    for(const auto &D : DIRS) 
    {
        Point bp = blackG + D;
        if(!inBPalace(bp)) continue; // 走出宫殿,不可以

        char back = board[bp.x][bp.y];
        board[bp.x][bp.y] = 0; // 红字可能被吃掉

        bool live = true; // 黑王状态(活,死)
        for(const auto &r : redPieces)
        {
            if(board[r.x][r.y] && checkmate(r, bp)) {
                live = false;
                break;
            }
        }
        board[bp.x][bp.y] = back;
        if(live) return false;
    }
    return true;
}

int main()
{
    int N;
    while(scanf("%d%d%d", &N, &(blackG.x), &(blackG.y)) == 3 && N) 
    // while((cin >> N >> blackG.x >> blackG.y) && N)
    {
        redPieces.clear();
        memset(board, 0, sizeof(board));
        _for(i, 0, N)
        {
            char type;
            Point p;
            // getchar();
            cin >> type;
            if(type == '\n') cin >> type;
            scanf("%d%d", &(p.x), &(p.y));            
            redPieces.push_back(p);
            board[p.x][p.y] = type;
            if(type == 'G') redG = p;
        }

        puts(canWin() ? "YES" : "NO");
    }
    return 0;
}

总结

注意输出输入格式

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值