「SDOI2010」猪国杀 题解

总算是写完了这道模拟神题Orz……

体会到了面向对象思想和STL的强大之处。

以下是一些需要注意的地方:

  1. 当牌堆摸完后,要一直摸最后一张牌。
  2. 在处理南蛮入侵和万箭齐发时,如果有人胜利需要立即break。
  3. 在进入濒死状态吃桃后,需要把HP设为1。
  4. 类反猪这个状态只对主猪产生影响。
  5. 在主猪杀死忠猪后,已经弃光了所有的牌,就不需要再弃一遍当前要出的牌了。

不知道SDOI上有没有dalao做出来Orz

#include <bits/stdc++.h>

#ifdef DEBUG
#define printlog(args) cout << args << "." << endl
#else
#define printlog(args)
#endif

using namespace std;

const int MAXN = 20, MAXHP = 4;

struct Player {
    int id, image, hp;
    string role;
    list<string> hand;
    bool weapon, alive, used_k;
    Player();
    Player(int id);
    bool operator!=(const Player &rhs) const;
    bool operator==(const Player &rhs) const;
    void play_turn();
    bool play_card(string card);
    bool tear(string card);
    bool hostile(Player &target);
    bool ask_for_j(int future);
    void set_hostile(Player &target);
    void deal_damage(Player &target);
    void settle_kill(Player &target);
    void draw_card();
    friend ostream &operator<<(ostream &os, const Player &target);
} player[MAXN];

int N, M, nFP, winner;

int next(int x) {
    do x = x == N ? 1 : x + 1;
    while(!player[x].alive);
    return x;
}

Player::Player() {}

Player::Player(int id) : id(id), weapon(false), alive(true), hp(MAXHP), image(0) {
    cin >> role;
    if(role == "FP") nFP++;
    if(role == "MP") image = 2;
    for(int i = 1; i <= 4; i++) {
        string card; cin >> card;
        hand.push_back(card);
    }
}

bool Player::operator!=(const Player &rhs) const {
    return id != rhs.id;
}

bool Player::operator==(const Player &rhs) const {
    return id == rhs.id;
}

bool Player::hostile(Player &target) {
    return target.image == -1 && role == "MP" || target.image == -2 && (role == "MP" || role == "ZP") || target.image == 2 && role == "FP";
}

void Player::set_hostile(Player &target) {
    image = target.image > 0 ? -2 : 2;
    printlog("Player " << id << "'s image is now " << image);
}

bool Player::ask_for_j(int future) {
    Player *target = this;
    if((target->role == "FP" ? -2 : 2) == future && target->tear("J")) {
        target->image = future;
        printlog("Player " << target->id << " used card \"J\". Now his image is " << image);
        return !target->ask_for_j(-future);
    }
    do {
        target = &player[next(target->id)];
        if((target->role == "FP" ? -2 : 2) == future && target->tear("J")) {
            target->image = future;
            printlog("Player " << target->id << " used card \"J\". Now his image is " << target->image);
            return !target->ask_for_j(-future);
        }
    } while(target != this);
    return false;
}

bool Player::play_card(string card) {
    if(card == "P") {
        if(hp == MAXHP) return false;
        hp++;
        printlog("Player " << id << " has used card \"P\". Now his HP is " << hp);
        return true;
    } else if(card == "K") {
        if(used_k && !weapon) return false;
        Player &target = player[next(id)];
        if(hostile(target)) {
            set_hostile(target);
            if(!target.tear("D")) deal_damage(target);
        } else return false;
        printlog("Player " << id << " has used card \"K\" to player " << target.id);
        return used_k = true;
    } else if(card == "D") {
        return false;
    } else if(card == "F") {
        Player *target = &player[id];
        if(role == "FP") target = &player[1];
        else {
            do target = &player[next(target->id)];
            while(!hostile(*target) && target->id != id);
            if(target == this) return false;
        }
        printlog("Player " << id << " has used card \"F\" to player " << target->id);
        set_hostile(*target);
        if(abs(target->image) == 2 && ask_for_j(target->image)) return true;
        if(role == "MP" && target->role == "ZP") {
            printlog("ZP " << id << " lost one HP due to MP's card \"F\"");
            deal_damage(*target);
            return true;
        }
        int turn = 1;
        while(true) {
            if((turn ? target : this)->tear("K")) turn ^= 1;
            else {
                (turn ? this : target)->deal_damage(turn ? *target : *this);
                break;
            }
        }
        return true;
    }
    else if(card == "N") {
        printlog("Player " << id << " used card \"N\"");
        for(Player *target = &player[next(id)]; target != this && !winner; target = &player[next(target->id)]) {
            if(abs(target->image) == 2 && ask_for_j(target->image)) {
                printlog("Someone used card \"J\" for player " << target->id << ", so he doesn't need to tear card \"K\"");
                continue;
            }
            printlog("Player " << target->id << " needs to tear card \"K\"");
            if(!target->tear("K")) deal_damage(*target);
        }
        return true;
    } else if(card == "W") {
        printlog("Player " << id << " used card \"W\"");
        for(Player *target = &player[next(id)]; target != this && !winner; target = &player[next(target->id)]) {
            if(abs(target->image) == 2 && ask_for_j(target->image)) {
                printlog("Someone used card \"J\" for player " << target->id << ", so he doesn't need to tear card \"D\"");
                continue;
            }
            printlog("Player " << target->id << " needs to tear card \"D\"");
            if(!target->tear("D")) deal_damage(*target);
        }
        return true;
    } else if(card == "J") {
        return false;
    } else if(card == "Z") {
        printlog("Player " << id << " equipped card \"Z\"");
        return weapon = true;
    }
    return false;
}

bool Player::tear(string card) {
    for(list<string>::iterator i = hand.begin(); i != hand.end(); i++)
        if(*i == card) {
            i = hand.erase(i);
            printlog("Player " << id << " teared card \"" << card << "\"");
            return true;
        }
    return false;
}

void Player::play_turn() {
    printlog("Player " << id << " has begun his turn");
    used_k = false;
    bool finished = false;
    for(int i = 1; i <= 2; i++) draw_card();
    while(!finished && alive && !winner) {
        finished = true;
        for(list<string>::iterator i = hand.begin(); i != hand.end(); i++) {
            if(play_card(*i)) {
                finished = false;
                if(!hand.empty()) i = hand.erase(i);
                break;
            }
        }
    }
    printlog("Player " << id << " has ended his turn");
}

void Player::deal_damage(Player &target) {
    target.hp--;
    printlog("Player " << id << " dealt 1 damage to player " << target.id << ". Now his HP is " << target.hp);
    if(!target.hp) {
        if(!target.tear("P")) settle_kill(target);
        else {
            target.hp = 1;
            printlog("Player " << target.id << " used card \"P\" so that he is alive");
        }
    }
    if(!image && target.role == "MP") {
        printlog("Player " << id << "'s image is now -1 because he dealt one damage to MP with an AOE");
        image = -1;
    }
}

void Player::settle_kill(Player &target) {
    printlog("Player " << id << " has killed player " << target.id);
    target.alive = false;
    if(target.role == "MP") { 
        winner = -1;
        printlog("FP has won the game");
    } else if(target.role == "FP")
        if(!(--nFP)) {
            winner = 1;
            printlog("MP has won the game");
        }
    if(winner) return;
    if(target.role == "FP") {
        printlog("Player " << id << " has drawn 3 cards because he killed FP " << target.id);
        for(int i = 1; i <= 3; i++) draw_card();
    } else if (target.role == "ZP" && role == "MP") {
        printlog("MP lost all his cards because he killed ZP " << target.id);
        hand.clear();
        weapon = false;
    }
}

void Player::draw_card() {
    static string last;
    cin >> last;
    printlog("Player " << id << " has drawn card \"" << last << "\"");
    hand.push_back(last);
}

ostream &operator<<(ostream &os, const Player &target) {
    if(target.alive)
        for(list<string>::const_iterator i = target.hand.begin(); i != target.hand.end(); i++) 
            os << *i << " ";
    else
        os << "DEAD";
    return os << endl;
}

void init() {
    scanf("%d%d", &N, &M);
    for(int i = 1; i <= N; i++) player[i] = Player(i);
}

int main() {
    init();
    Player *active = &player[1];
    while(!winner) {
        active->play_turn();
        active = &player[next(active->id)];
    }
    cout << (winner == 1 ? "MP" : "FP") << endl;
    for(int i = 1; i <= N; i++) cout << player[i];
}

发表评论

电子邮件地址不会被公开。 必填项已用*标注