距 NOI Online 还有 4 天的时候,我和@Tommy0103一起开黑写了这道大模拟,来折磨锻炼自己。

这是一篇C++ 面向对象编程的题解

题意分析

给你一个棋盘,要你模拟走棋,判断

  • 每一步棋是否合法
  • 走棋后是否将军
  • 走棋后是否吃掉了一方的王

简析

其实这很简单,直接模拟就好了。但这题码量较大,我们可以用一些特殊技巧。

技巧

C++和C相比最大的不同就是C++支持面向对象编程(OOP)。

OOP的三要素是:

  • 封装
  • 继承
  • 多态

我们可以利用封装来将程序拆成模块,让程序更清晰可读,同时利用继承和多态来实现程序的复用。

实现

首先我们定义了一个Enum(枚举),代表一个棋子是哪一方的。

enum Owner {
    Zero, Blue, Red
};

然后再定义一个Enum,代表一个棋子的类型(在程序判断中用)

enum Chess_Type {
    CTZero, CTCaptain, CTGuard, CTElephant, CTHorse, CTCar, CTDuck, CTSoldier
};

Enum声明的常量是全局的,为了避免重名我们在这里加上CT前缀。

然后我们定义一个基类,代表棋子。

struct Chess {
    Owner owner;
    Chess_Type type;
    Chess() {
        owner = Zero;
        type = CTZero;
    }
    Chess(Owner o) {
        owner = o;
        type = CTZero;
    }
    ~Chess() {}
    virtual int check(int x, int y, int gx, int gy) = 0;
    virtual void print() = 0;
};

我们将所有棋子都应该拥有的共同属性放在Chess类型里面,供继承用。

这里我们将check(int,int,int,int)函数和print()函数用virtual修饰,并在后面加上了=0代表这是一个纯虚函数,必须被子类重载。Chess类也因此不能创建Chess对象,只能建立指针。

然后我们再开一个类,并让它继承Chess类。

这里我用来举例的是ZeroChess类,代表的是棋盘上没有棋子的地方。

struct ZeroChess : Chess {
    ZeroChess() {
        owner = Zero;
        type = CTZero;
    }
    ZeroChess(Owner o) {
        owner = o;
        type = CTZero;
    }
    int check(int x, int y, int gx, int gy) {
        return 0;
    }
    void print() {
        printf("NA");
    }
};

可以看到继承的语法是在类型名后面加上:父类名1,父类名2...,然后子类就具有了父类里的所有函数和属性。同时,子类可以重载父类里所有用virtual修饰的函数,父类指针也可以指向子类对象,使其实际运行时的行为发生改变。

这就是多态!

但是多态在C++中只有在用指针访问时才能体现,所以我们只能用Chess指针数组代表棋盘,将 $mp_{i,j}$定义为指向 $(i,j)$处的棋子的指针,在代码中用mp[i][j] -> print();的方法调用。

代码

#include <bits/stdc++.h>
using namespace std;
inline int rd() {
    register int ans = 0, flag = 1;
    register char c = getchar();
    for (; c > '9' || c < '0'; c = getchar()) if (c == '-') flag = -1;
    for (; c >= '0' && c <= '9'; c = getchar()) ans = ans * 10 - '0' + c;
    return ans * flag;
}
enum Owner {
    Zero, Blue, Red
};
enum Chess_Type {
    CTZero, CTCaptain, CTGuard, CTElephant, CTHorse, CTCar, CTDuck, CTSoldier
};
struct Chess {
    Owner owner;
    Chess_Type type;
    Chess() {
        owner = Zero;
        type = CTZero;
    }
    Chess(Owner o) {
        owner = o;
        type = CTZero;
    }
    ~Chess() {}
    virtual int check(int x, int y, int gx, int gy) = 0;
    virtual void print() = 0;
};
struct ZeroChess : Chess {
    ZeroChess() {
        owner = Zero;
        type = CTZero;
    }
    ZeroChess(Owner o) {
        owner = o;
        type = CTZero;
    }
    int check(int x, int y, int gx, int gy) {
        return 0;
    }
    void print() {
        printf("NA");
    }
};
Chess *mp[11][10];
ZeroChess zero;
int captain_ox[] = {1, -1, 0, 0};
int captain_oy[] = {0, 0, 1, -1};
struct Captain : Chess {
    Captain() {
        owner = Zero;
        type = CTCaptain;
    }
    Captain(Owner o) {
        owner = o;
        type = CTCaptain;
    }
    ~Captain() {}
    int check(int x, int y, int gx, int gy) {
        if (gx < 0 || gx > 10) return 0;
        if (gy < 0 || gy > 9) return 0;
        register int flag = 0;
        for (register int i = 0; i < 4; ++i) {
            if (x + captain_ox[i] == gx && y + captain_oy[i] == gy) {
                flag = 1;
                break;
            }
        }
        if (!flag) return 0;
        if (mp[gx][gy] -> owner == owner) return 0;
        return 1;
    }
    void print() {
        printf("%s captain", owner == Zero ? "NA" : (owner == Blue ? "blue" : "red"));
    }
};
int guard_ox[] = {1, -1, 1, -1};
int guard_oy[] = {1, 1, -1, -1};
struct Guard : Chess {
    Guard() {
        owner = Zero;
        type = CTGuard;
    }
    Guard(Owner o) {
        owner = o;
        type = CTGuard;
    }
    ~Guard() {}
    int check(int x, int y, int gx, int gy) {
        // printf("%d %d %d %d\n", x, y, gx, gy);
        if (gx < 0 || gx > 10) return 0;
        if (gy < 0 || gy > 9) return 0;
        register int flag = 0;
        for (register int i = 0; i < 4; ++i) {
            if (x + guard_ox[i] == gx && y + guard_oy[i] == gy) {
                flag = 1;
                break;
            }
        }
        if (!flag) return 0;
        if (mp[gx][gy] -> owner == owner) return 0;
        return 1;
    }
    void print() {
        printf("%s guard", owner == Zero ? "NA" : (owner == Blue ? "blue" : "red"));
    }
};
int elephant_ox[] = {2, -2, 2, -2};
int elephant_oy[] = {2, 2, -2, -2};
struct Elephant : Chess {
    Elephant() {
        owner = Zero;
        type = CTElephant;
    }
    Elephant(Owner o) {
        owner = o;
        type = CTElephant;
    }
    ~Elephant() {}
    int check(int x, int y, int gx, int gy) {
        if (gx < 0 || gx > 10) return 0;
        if (gy < 0 || gy > 9) return 0;
        register int flag = 0;
        for (register int i = 0; i < 4; ++i) {
            if (x + elephant_ox[i] == gx && y + elephant_oy[i] == gy) {
                flag = 1;
                break;
            }
        }
        if (!flag) return 0;
        if (mp[(x + gx) >> 1][(y + gy) >> 1] -> owner != Zero) return 0;
        if (mp[gx][gy] -> owner == owner) return 0;
        return 1;
    }
    void print() {
        printf("%s elephant", owner == Zero ? "NA" : (owner == Blue ? "blue" : "red"));
    }
};
struct Horse : Chess {
    Horse() {
        owner = Zero;
        type = CTHorse;
    }
    Horse(Owner o) {
        owner = o;
        type = CTHorse;
    }
    ~Horse() {}
    int check(int x, int y, int gx, int gy) {
        if (gx < 0 || gx > 10) return 0;
        if (gy < 0 || gy > 9) return 0;
        register int flag = 0, sx = 0, sy = 0;
        for (register int i = 1; i >= -1; i -= 2) {
            for (register int j = 1; j >= -1; j -= 2) {
                if (x + (i << 1) == gx && y + j == gy) {
                    sx = i;
                    sy = j;
                    flag = 1;
                    goto end;
                }
                if (x + i == gx && y + (j << 1) == gy) {
                    sx = i;
                    sy = j;
                    flag = 2;
                    goto end;
                }
            }
        }
end:
        if (!flag) return 0;
        if (mp[gx][gy] -> owner == owner) return 0;
        --flag;
        if (flag) {
            return (mp[x][y + sy] -> owner == Zero);
        } else {
            return (mp[x + sx][y] -> owner == Zero);
        }
    }
    void print() {
        printf("%s horse", owner == Zero ? "NA" : (owner == Blue ? "blue" : "red"));
    }
};
struct Car : Chess {
    Car() {
        owner = Zero;
        type = CTCar;
    }
    Car(Owner o) {
        owner = o;
        type = CTCar;
    }
    ~Car() {}
    int check(int x, int y, int gx, int gy) {
        if (gx < 0 || gx > 10) return 0;
        if (gy < 0 || gy > 9) return 0;
        if (x != gx && y != gy) return 0;
        register int l = (x == gx ? y : x), r = (x == gx ? gy : gx);
        register int flag = (x == gx);
        if (l > r) swap(l, r);
        for (register int i = l + 1; i < r; ++i) {
            if (flag) {
                if (mp[x][i] -> owner != Zero) {
                    return 0;
                }
            } else {
                if (mp[i][y] -> owner != Zero) {
                    return 0;
                }
            }
        }
        if (mp[gx][gy] -> owner == owner) return 0;
        return 1;
    }
    void print() {
        printf("%s car", owner == Zero ? "NA" : (owner == Blue ? "blue" : "red"));
    }
};
struct Duck : Chess {
    Duck() {
        owner = Zero;
        type = CTDuck;
    }
    Duck(Owner o) {
        owner = o;
        type = CTDuck;
    }
    ~Duck() {}
    int check(int x, int y, int gx, int gy) {
        if (gx < 0 || gx > 10) return 0;
        if (gy < 0 || gy > 9) return 0;
        register int flag = 0, sx = 0, sy = 0;
        for (register int i = 1; i >= -1; i -= 2) {
            for (register int j = 1; j >= -1; j -= 2) {
                if (x + i * 3 == gx && y + (j << 1) == gy) {
                    sx = i;
                    sy = j;
                    flag = 1;
                    goto end;
                }
                if (x + (i << 1) == gx && y + j * 3 == gy) {
                    sx = i;
                    sy = j;
                    flag = 2;
                    goto end;
                }
            }
        }
end:
        if (!flag) return 0;
        if (mp[gx][gy] -> owner == owner) return 0;
        --flag;
        if (flag) {
            return ((mp[x + sx][y + (sy << 1)] -> owner == Zero) && (mp[x][y + sy] -> owner == Zero));
        } else {
            return ((mp[x + (sx << 1)][y + sy] -> owner == Zero) && (mp[x + sx][y] -> owner == Zero));
        }
    }
    void print() {
        printf("%s duck", owner == Zero ? "NA" : (owner == Blue ? "blue" : "red"));
    }
};
int soldier_ox[] = {1, -1, 1, -1, 1, -1, 0, 0};
int soldier_oy[] = {1, 1, -1, -1, 0, 0, 1, -1};
struct Soldier : Chess {
    Soldier() {
        owner = Zero;
        type = CTSoldier;
    }
    Soldier(Owner o) {
        owner = o;
        type = CTSoldier;
    }
    ~Soldier() {}
    int check(int x, int y, int gx, int gy) {
        if (gx < 0 || gx > 10) return 0;
        if (gy < 0 || gy > 9) return 0;
        register int flag = 0;
        for (register int i = 0; i < 8; ++i) {
            if (x + soldier_ox[i] == gx && y + soldier_oy[i] == gy) {
                flag = 1;
                break;
            }
        }
        if (!flag) return 0;
        if (mp[gx][gy] -> owner == owner) return 0;
        return 1;
    }
    void print() {
        printf("%s soldier", owner == Zero ? "NA" : (owner == Blue ? "blue" : "red"));
    }
};
inline int judge() {
    register int tmp = 0;
    for (register int i = 0; i < 10; ++i) {
        for (register int j = 0; j < 9; ++j) {
            if (mp[i][j] -> type == CTCaptain) ++tmp;
        }
    }
    return tmp < 2;
}
inline int check() {
    register int x = 0, y = 0;
    for (register int i = 0; i < 10; ++i) {
        for (register int j = 0; j < 9; ++j) {
            if (mp[i][j] -> type == CTCaptain && mp[i][j] -> owner == Blue) {
                x = i;
                y = j;
                goto end_blue;
            }
        }
    }
end_blue:
    for (register int i = 0; i < 10; ++i) {
        for (register int j = 0; j < 9; ++j) {
            if (mp[i][j] -> check(i, j, x, y)) {
                return 1;
            }
        }
    }
    x = 0;
    y = 0;
    for (register int i = 0; i < 10; ++i) {
        for (register int j = 0; j < 9; ++j) {
            if (mp[i][j] -> type == CTCaptain && mp[i][j] -> owner == Red) {
                x = i;
                y = j;
                goto end_red;
            }
        }
    }
end_red:
    for (register int i = 0; i < 10; ++i) {
        for (register int j = 0; j < 9; ++j) {
            if (mp[i][j] -> check(i, j, x, y)) {
                return 1;
            }
        }
    }
    return 0;
}
inline void init() {
    for (register int i = 0; i < 10; ++i) {
        for (register int j = 0; j < 9; ++j) {
            mp[i][j] = new ZeroChess;
        }
    }
    mp[0][0] = new Car(Red);
    mp[0][1] = new Horse(Red);
    mp[0][2] = new Elephant(Red);
    mp[0][3] = new Guard(Red);
    mp[0][4] = new Captain(Red);
    mp[0][5] = new Guard(Red);
    mp[0][6] = new Elephant(Red);
    mp[0][7] = new Horse(Red);
    mp[0][8] = new Car(Red);
    mp[2][0] = new Duck(Red);
    mp[2][8] = new Duck(Red);
    mp[3][0] = new Soldier(Red);
    mp[3][2] = new Soldier(Red);
    mp[3][4] = new Soldier(Red);
    mp[3][6] = new Soldier(Red);
    mp[3][8] = new Soldier(Red);
    mp[9][0] = new Car(Blue);
    mp[9][1] = new Horse(Blue);
    mp[9][2] = new Elephant(Blue);
    mp[9][3] = new Guard(Blue);
    mp[9][4] = new Captain(Blue);
    mp[9][5] = new Guard(Blue);
    mp[9][6] = new Elephant(Blue);
    mp[9][7] = new Horse(Blue);
    mp[9][8] = new Car(Blue);
    mp[7][0] = new Duck(Blue);
    mp[7][8] = new Duck(Blue);
    mp[6][0] = new Soldier(Blue);
    mp[6][2] = new Soldier(Blue);
    mp[6][4] = new Soldier(Blue);
    mp[6][6] = new Soldier(Blue);
    mp[6][8] = new Soldier(Blue);
}
int main() {
    init();
    register Owner now = Red;
    register int q = rd();
    register int sx, sy, tx, ty;
    register int game_over = 0;
    for (register int i = 1; i <= q; ++i) {
        sx = rd();
        sy = rd();
        tx = rd();
        ty = rd();
        if (sx < 0 || sx > 10) {
            printf("Invalid command\n");
            continue;
        }
        if (sy < 0 || sy > 9) {
            printf("Invalid command\n");
            continue;
        }
        if (game_over) {
            printf("Invalid command\n");
            continue;
        }
        if (mp[sx][sy] -> owner != now) {
            printf("Invalid command\n");
            continue;
        }
        if (mp[sx][sy] -> check(sx, sy, tx, ty) == 0) {
            printf("Invalid command\n");
            continue;
        }
        mp[sx][sy] -> print();
        putchar(';');
        mp[tx][ty] -> print();
        putchar(';');
        mp[tx][ty] = mp[sx][sy];
        mp[sx][sy] = new ZeroChess();
        now = (now == Red ? Blue : Red);
        game_over = judge();
        if (!game_over && check()) {
            printf("yes");
        } else {
            printf("no");
        }
        putchar(';');
        if (game_over) {
            printf("yes");
        } else {
            printf("no");
        }
        printf("\n");
    }
    return 0;
}