总算是写完了这道模拟神题Orz……
体会到了面向对象思想和STL的强大之处。
以下是一些需要注意的地方:
- 当牌堆摸完后,要一直摸最后一张牌。
- 在处理南蛮入侵和万箭齐发时,如果有人胜利需要立即break。
- 在进入濒死状态吃桃后,需要把HP设为1。
- 类反猪这个状态只对主猪产生影响。
- 在主猪杀死忠猪后,已经弃光了所有的牌,就不需要再弃一遍当前要出的牌了。
不知道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];
}