AC于2022年8月9日,代码写了一个晚上
点击查看代码
#include <stdio.h>
#include <string.h>
const int N = 15, M = 2005;
struct Pig {
char type; // 类型
bool showed; // 暴露身份
bool fan_likely; // 被认为是类反猪
bool have_weapon; // 有猪哥连弩
bool alive; // 活着
int tili; // 体力
int card_count; // 拿过的牌的个数
char cards[M]; // 拿过的牌, 若用过,标记为X
bool Zhong() { return showed && type == 'Z'; } // 是否跳忠
bool Fan() { return showed && type == 'F'; } // 是否跳反
} pigs[N];
int n, m, card_index;
int FanPigCount; // 活着的反猪个数
char remain_cards[M];
char winner;
// 读入
void input() {
scanf("%d%d", &n, &m);
char tp[3], card[2];
for(int i = 1; i <= n; i ++) {
scanf("%s", tp);
pigs[i].type = *tp; // 猪的类型
pigs[i].card_count = 4; // 猪的牌
pigs[i].fan_likely = false; // 不是类反猪
pigs[i].have_weapon = false; // 没有武器
pigs[i].showed = i == 1; // 是否暴露
pigs[i].alive = true; // 还活着
pigs[i].tili = 4; // 初始体力
if(*tp == 'F') FanPigCount ++;
for(int j = 1; j <= 4; j ++)
scanf("%s", card), pigs[i].cards[j] = *card; // 原始的牌
}
for(int i = 1; i <= m; i ++)
scanf("%s", card), remain_cards[i] = *card; // 牌堆
}
// 拿一张牌
void get_a_card(int id) {
if(card_index != m) card_index ++; // 没有用完
pigs[id].cards[++ pigs[id].card_count] = remain_cards[card_index];
}
int next_alive(int id) {
for(int id2 = id + 1; id2 != id; id2 ++, id2 > n && (id2 = 1))
if(pigs[id2].alive) return id2;
return 0;
}
// 体力变为0时的处理
void killed(int id, int killer) {
// 先判断是否有桃子P(共性1)
for(int i = 1; i <= pigs[id].card_count; i ++) // 枚举是否有桃子
if(pigs[id].cards[i] == 'P') {
pigs[id].tili ++; // 体力++
pigs[id].cards[i] = 'X'; // 用过了
if(pigs[id].tili > 0) return; // 活了!
}
pigs[id].alive = false; // 死了
if(pigs[id].type == 'M') { // 主猪死亡
winner = 'F'; // 反猪胜利
} else if(pigs[id].type == 'Z') { // 忠猪死亡
if(pigs[killer].type == 'M') { // 主猪干的
pigs[killer].card_count = 0; // 牌没了
pigs[killer].have_weapon = false; // 装备没了
}
} else if(pigs[id].type == 'F') { // 反猪死亡
FanPigCount --;
if(FanPigCount == 0) // 反猪全完
winner = 'M'; // 主猪胜利
else get_a_card(killer), get_a_card(killer), get_a_card(killer); // 拿3张牌
}
}
// 吃桃子P, 共性1:吃掉
bool use_P(int id) {
if(pigs[id].tili < 4) {
pigs[id].tili ++;
return true; // 用了桃子
} return false;
}
// 闪D 若没有,则体力--
void use_D(int id) {
for(int i = 1; i <= pigs[id].card_count; i ++)
if(pigs[id].cards[i] == 'D') {
pigs[id].cards[i] = 'X'; // 被用了
return;
}
pigs[id].tili --;
}
// 杀K, 只能杀下一只猪
bool use_K(int id) {
if(pigs[id].type == 'M') { // 主猪用杀
int id2 = next_alive(id);
if(pigs[id2].Fan() || pigs[id2].fan_likely) { // 反猪或类反猪
use_D(id2); // 用闪回击
if(pigs[id2].tili <= 0) killed(id2, id); // 被杀了
return true; // 用了杀
}
} else if(pigs[id].type == 'Z') { // 忠猪
int id2 = next_alive(id);
if(pigs[id2].Fan()) {
pigs[id].showed = true, pigs[id].fan_likely = false; // 暴露身份
use_D(id2);
if(pigs[id2].tili <= 0) killed(id2, id);
return true;
}
} else if(pigs[id].type == 'F') { // 反猪
int id2 = next_alive(id);
if(pigs[id2].Zhong() || pigs[id2].type == 'M') { // 主猪或忠猪
pigs[id].showed = true, pigs[id].fan_likely = false; // 暴露身份
use_D(id2);
if(pigs[id2].tili <= 0) killed(id2, id);
return true;
}
}
return false;
}
// 无懈可击, id表示使用锦囊的猪, target 表示目标方 1表示主猪方, 2表示反猪方
bool use_J(int id, int target) {
int id2 = id; // 注意: 自己也可以用无懈可击
do {
if(pigs[id2].alive) {
if((pigs[id2].type == 'F' && target == 2) || (pigs[id2].type != 'F' && target == 1)) {
// 反猪帮反猪 或 忠猪帮主猪
for(int i = 1; i <= pigs[id2].card_count; i ++)
if(pigs[id2].cards[i] == 'J') {
pigs[id2].showed = true, pigs[id2].fan_likely = false; // 暴露身份
pigs[id2].cards[i] = 'X'; // 被用了
return !use_J(id2, 3 - target); // 轮到对方无懈可击
}
}
}
id2 ++, id2 > n && (id2 = 1);
} while(id2 != id);
return false; // 用不了
}
void swap(int &x, int &y) { static int z; z = x, x = y, y = z; }
void fight(int id, int id2) {
if(pigs[id].type == 'M' && pigs[id2].type == 'Z') { // 主猪和忠猪决斗: 忠猪绝不出牌
pigs[id2].tili --;
if(pigs[id2].tili <= 0) killed(id2, id);
} else { // 不遗余力出牌
int now = id2, other = id; // 现在出牌的人, 另一个人
while(true) {
bool found = false; // 找到杀并使用
for(int i = 1; i <= pigs[now].card_count; i ++)
if(pigs[now].cards[i] == 'K') {
pigs[now].cards[i] = 'X';
found = true;
break;
}
if(found) swap(now, other); // 轮流出牌
else {
pigs[now].tili --;
if(pigs[now].tili <= 0) killed(now, other); // 被杀了
return;
}
}
}
}
// 决斗F
bool use_F(int id) {
if(pigs[id].type == 'M') { // 主猪打反猪与类反猪
for(int id2 = id + 1; id2 != id; id2 ++, id2 > n && (id2 = 1))
if(pigs[id2].alive && (pigs[id2].Fan() || pigs[id2].fan_likely)) {
if(!pigs[id2].showed || !use_J(id, 2)) fight(id, id2); // fight:打架
return true; // 注意: 没有暴露身份的对手的不能用无懈可击
}
} else if(pigs[id].type == 'Z') { // 忠猪找反猪
for(int id2 = id + 1; id2 != id; id2 ++, id2 > n && (id2 = 1))
if(pigs[id2].alive && pigs[id2].Fan()) {
if(!pigs[id2].showed || !use_J(id, 2)) fight(id, id2);
pigs[id].showed = true; // 身份暴露
return true;
}
} else if(pigs[id].type == 'F') { // 反猪找主猪
if(!use_J(id, 1)) fight(id, 1); // 主猪身份明确, 可以使用无懈可击
pigs[id].showed = true; // 身份暴露
return true;
}
return false;
}
// 南猪入侵
bool use_N(int id) {
for(int id2 = id + 1; id2 != id; id2 ++, id2 > n && (id2 = 1))
if(pigs[id2].alive) {
if(pigs[id2].showed && use_J(id, pigs[id2].type == 'F' ? 2 : 1)) continue; // 被无懈可击了
bool hurt = true; // 对id2产生伤害
for(int i = 1; i <= pigs[id2].card_count; i ++)
if(pigs[id2].cards[i] == 'K') {
pigs[id2].cards[i] = 'X';
hurt = false;
break;
}
if(hurt) { // 造成伤害
pigs[id2].tili --;
if(pigs[id2].tili <= 0) killed(id2, id); // 被杀了
if(winner) return true; // 立即退出
if(id2 == 1 && !pigs[id].showed) pigs[id].fan_likely = true; // 主猪被未表明身份的伤害:类反猪
}
}
return true;
}
bool use_W(int id) {
for(int id2 = id + 1; id2 != id; id2 ++, id2 > n && (id2 = 1))
if(pigs[id2].alive) {
if(pigs[id2].showed && use_J(id, pigs[id2].type == 'F' ? 2 : 1)) continue; // 被无懈可击了
bool hurt = true; // 对id2产生伤害
for(int i = 1; i <= pigs[id2].card_count; i ++)
if(pigs[id2].cards[i] == 'D') {
pigs[id2].cards[i] = 'X';
hurt = false;
break;
}
if(hurt) { // 造成伤害
pigs[id2].tili --;
if(pigs[id2].tili <= 0) killed(id2, id); // 被杀了
if(winner) return true; // 立即退出
if(id2 == 1 && !pigs[id].showed) pigs[id].fan_likely = true; // 主猪被未表明身份的伤害:类反猪
}
}
return true;
}
int main() {
input();
while(true) for(int id = 1; id <= n; id ++) if(pigs[id].alive) {
get_a_card(id), get_a_card(id); // 摸牌
bool can_use_K = true;
for(int i = 1; i <= pigs[id].card_count; i ++) {
if(pigs[id].cards[i] == 'X') continue;
bool used_card = false; // 是否使用牌
if(pigs[id].cards[i] == 'P') used_card = use_P(id); // 能够吃桃子
else if(pigs[id].cards[i] == 'K') {
if(pigs[id].have_weapon) can_use_K = true; // 有武器: 能够用任意次杀
if(can_use_K) {
used_card = use_K(id); // 杀
if(used_card) can_use_K = false; // 用了
}
} else if(pigs[id].cards[i] == 'F') used_card = use_F(id);
else if(pigs[id].cards[i] == 'N') used_card = use_N(id);
else if(pigs[id].cards[i] == 'W') used_card = use_W(id);
else if(pigs[id].cards[i] == 'Z') used_card = pigs[id].have_weapon = true; // 猪哥连弩
if(used_card) pigs[id].cards[i] = 'X', i = 0; // 用过了, i=0是因为前面的牌可能可以用
if(!pigs[id].alive) break; // 猪死了, 完
if(winner) goto GAME_OVER; // 立即退出
}
}
GAME_OVER: printf("%cP\n", winner);
for(int id = 1; id <= n; id ++)
if(pigs[id].alive) {
for(int i = 1; i <= pigs[id].card_count; i ++)
if(pigs[id].cards[i] != 'X') printf("%c ", pigs[id].cards[i]);
putchar(10);
} else puts("DEAD");
return 0;
}