题解:P11878 城堡中的皇后

· · 题解

主要思路

一道没有什么思路难度的大模拟(打磨你)。

对于棋盘记录,0 表示没有棋子;白兵、白马、白象、白车、白后、白王分别为 1 \sim 6;黑王、黑后、黑车、黑象、黑马、黑兵分别为 -6 \sim -1

对于 FEN 到棋盘的转换,可以每一部分,可以记录一个 col 变量并设数值为 1。如果这一段的第 i 个字符是数字,则让 col 加上这个数字;反之则在棋盘对应位置做转换并记录。最后不管当前是哪种字符,都 col \gets col + 1

转换完成后,遍历棋盘,只要这个位置有棋子并且不是王,就判断当前棋子是否能将军对面的王;如果所有棋子都不能,就输出 none

AC Code

#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

typedef long long ll;
typedef long double db;
const int INT_INF = 0x3f3f3f3f;
const ll LL_INF = 0x3f3f3f3f3f3f3f3f;
inline ll _abs(ll a) { if (a < 0) return -a; return a; }
const int dx[8] = {-1, -2, -2, -1, 1, 2, 2, 1}, dy[8] = {-2, -1, 1, 2, 2, 1, -1, -2};
// ----------------------------

// ----------------------------
int board[10][10];
// ----------------------------
bool pawn(int x, int y, int f) {
    if (f == 1) {
        return (board[x - 1][y - 1] == -6 || board[x - 1][y + 1] == -6);
    }
    return (board[x + 1][y - 1] == 6 || board[x + 1][y + 1] == 6);
}

bool knight(int x, int y, int f) {
    int nx, ny;
    for (int i = 0; i < 8; i++) {
        nx = x + dx[i];
        ny = y + dy[i];
        if (board[nx][ny] == 6 * -f) return true;
    }
    return false;
}

bool bishop(int x, int y, int f) {
    int nx = x - 1;
    int ny = y - 1;
    while (nx > 0 && ny > 0 && board[nx][ny] == 0) {
        nx--;
        ny--;
    }  // 找到斜线上第一个棋子
    if (board[nx][ny] == 6 * -f) return true;
    nx = x - 1;
    ny = y + 1;
    while (nx > 0 && ny <= 8 && board[nx][ny] == 0) {
        nx--;
        ny++;
    }
    if (board[nx][ny] == 6 * -f) return true;
    nx = x + 1;
    ny = y - 1;
    while (nx <= 8 && ny > 0 && board[nx][ny] == 0) {
        nx++;
        ny--;
    }
    if (board[nx][ny] == 6 * -f) return true;
    nx = x + 1;
    ny = y + 1;
    while (nx <= 8 && ny <= 8 && board[nx][ny] == 0) {
        nx++;
        ny++;
    }
    if (board[nx][ny] == 6 * -f) return true;
    return false;
}

bool rook(int x, int y, int f) {
    int nx = x - 1;
    int ny = y;
    while (nx > 0 && board[nx][ny] == 0) nx--; // 找到直线上第一个棋子
    if (board[nx][ny] == 6 * -f) return true;
    nx = x + 1;
    ny = y;
    while (nx <= 8 && board[nx][ny] == 0) nx++;
    if (board[nx][ny] == 6 * -f) return true;
    nx = x;
    ny = y - 1;
    while (ny > 0 && board[nx][ny] == 0) ny--;
    if (board[nx][ny] == 6 * -f) return true;
    nx = x;
    ny = y + 1;
    while (ny <= 8 && board[nx][ny] == 0) ny++;
    if (board[nx][ny] == 6 * -f) return true;
    return false;
}

int transform(char c) {
    if (c == 'P') return 1;
    if (c == 'N') return 2;
    if (c == 'B') return 3;
    if (c == 'R') return 4;
    if (c == 'Q') return 5;
    if (c == 'K') return 6; 
    if (c == 'p') return -1;
    if (c == 'n') return -2;
    if (c == 'b') return -3;
    if (c == 'r') return -4;
    if (c == 'q') return -5;
    if (c == 'k') return -6; 
    return 0;
}

void write(bool f) {
    if (f) cout << "CHECK\n";
    else cout << "check\n";
}

int main() {
    int t; cin >> t;
    // ----------------------------
    bool flag;
    string fen;
    int idx, col;
    while (t--) {
        cin >> fen;
        idx = -1;
        memset(board, 0, sizeof board);
        for (int i = 1; i <= 8; i++) {
            idx++;
            col = 1;
            while (idx < (int)fen.length() && fen[idx] != '/') {
                if (isdigit(fen[idx])) col += fen[idx] - '0';
                else board[i][col++] = transform(fen[idx]);
                idx++;
            }
        }
        flag = false;
        for (int i = 1; i <= 8 && !flag; i++) {
            for (int j = 1; j <= 8; j++) {
                if (_abs(board[i][j]) == 1) { // 判断这个棋子是否为兵,白黑都可以
                    if (pawn(i, j, board[i][j] / _abs(board[i][j]))) {
                        flag = true;
                        write(board[i][j] > 0);
                        break;
                    }
                }
                else if (_abs(board[i][j]) == 2) {
                    if (knight(i, j, board[i][j] / _abs(board[i][j]))) {
                        flag = true;
                        write(board[i][j] > 0);
                        break;
                    }
                }
                else if (_abs(board[i][j]) == 3) {
                    if (bishop(i, j, board[i][j] / _abs(board[i][j]))) {
                        flag = true;
                        write(board[i][j] > 0);
                        break;
                    }
                }
                else if (_abs(board[i][j]) == 4) {
                    if (rook(i, j, board[i][j] / _abs(board[i][j]))) {
                        flag = true;
                        write(board[i][j] > 0);
                        break;
                    }
                }
                else if (_abs(board[i][j]) == 5) { // 后就是结合了象与车的走法,所以不需要单独再写一个函数
                    if (bishop(i, j, board[i][j] / _abs(board[i][j])) ||
                        rook(i, j, board[i][j] / _abs(board[i][j]))) {
                            flag = true;
                            write(board[i][j] > 0);
                            break;
                        }
                }
            }
        }
        if (!flag) cout << "none\n";
    }
    return 0;
}