Files
2026-07-15 16:34:53 +08:00

478 lines
13 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include <bits/stdc++.h>
using namespace std;
int n, m;
char js[15]; // 角色:M主猪, Z忠猪, F反猪
char p[15][10005]; // 手牌
int l[15], r[15]; // 手牌左右边界(闭区间)
vector<char> dui; // 牌堆(尾部为堆顶)
int stre[15]; // 体力值
int fro[15], nex[15]; // 双向链表,用于存活角色遍历
bool zgln[15]; // 是否装备诸葛连弩
bool tiao[15]; // 是否已跳身份(忠/反表明)
bool lei[15]; // 主猪的类反猪标记
char last_card = 'P'; // 牌堆最后一张(初始为桃,避免空堆摸到空字符)
inline char read()
{
char ch = getchar();
while (ch < 'A' || ch > 'Z')
ch = getchar();
return ch;
}
void init()
{
scanf("%d %d\n", &n, &m);
for (int i = 0; i < n; ++i)
{
js[i] = read();
read(); // 跳过空格
for (int j = 0; j < 4; ++j)
p[i][j] = read();
stre[i] = 4;
l[i] = 0;
r[i] = 3;
fro[i] = (i == 0) ? (n - 1) : (i - 1);
nex[i] = (i + 1) % n;
}
for (int i = 0; i < m; ++i)
dui.push_back(read());
reverse(dui.begin(), dui.end()); // 牌堆尾部为堆顶
}
int pd()
{
bool fp_alive = false;
for (int i = 0; i < n; ++i)
if (js[i] == 'F' && stre[i] > 0)
{
fp_alive = true;
break;
}
if (stre[0] <= 0)
return 2; // FP胜
if (!fp_alive)
return 1; // MP胜
return 0; // 未结束
}
void mp(int now, int cnt)
{
while (cnt--)
{
if (!dui.empty())
{
last_card = dui.back();
dui.pop_back();
}
p[now][++r[now]] = last_card;
}
}
void dealdead(int now, int from)
{
// 濒死求桃
if (stre[now] <= 0)
{
for (int j = l[now]; j <= r[now]; ++j)
if (p[now][j] == 'P')
{
stre[now]++;
p[now][j] = 0;
if (stre[now] > 0)
break;
}
}
if (stre[now] <= 0)
{
// 死亡处理:从存活链表中移除
if (now != 0)
{
nex[fro[now]] = nex[now];
fro[nex[now]] = fro[now];
}
// 奖惩:仅在游戏未结束时执行
if (pd() == 0)
{
if (js[now] == 'F')
{
mp(from, 3);
}
else if (js[now] == 'Z' && js[from] == 'M')
{
// 主猪弃掉所有手牌和装备
for (int j = l[from]; j <= r[from]; ++j)
p[from][j] = 0;
l[from] = 0;
r[from] = -1;
zgln[from] = false;
}
}
// 死亡猪自己的手牌全部弃置
for (int j = l[now]; j <= r[now]; ++j)
p[now][j] = 0;
l[now] = 0;
r[now] = -1;
zgln[now] = false;
}
}
/* ---------- 无懈可击相关函数 ---------- */
int findJ(int now)
{
for (int i = l[now]; i <= r[now]; ++i)
if (p[now][i] == 'J')
return i;
return -1;
}
void useJ(int now)
{
int pos = findJ(now);
if (pos != -1) p[now][pos] = 0;
}
// 判断 now 是否会对 target 使用无懈可击,isProtect=true 表示献殷勤,false 表示表敌意
bool canUseJ(int now, int target, bool isProtect)
{
if (isProtect)
{
// 献殷勤:不会对未表明身份的猪(包括自己),主猪视为已表明
if (!(tiao[target] || js[target] == 'M')) return false;
if (js[now] == 'M')
return (target == now) || (js[target] == 'Z' && tiao[target]);
else if (js[now] == 'Z')
return (target == 0) || (js[target] == 'Z' && tiao[target]);
else if (js[now] == 'F')
return (js[target] == 'F' && tiao[target]);
}
else
{
// 表敌意
if (js[now] == 'M')
return (js[target] == 'F' && tiao[target]);
else if (js[now] == 'Z')
return (js[target] == 'F' && tiao[target]);
else if (js[now] == 'F')
return (target == 0) || (js[target] == 'Z' && tiao[target]);
}
return false;
}
// 询问链:当前牌的使用者 user,目标 targetisProtect 表示当前牌是保护(true)还是攻击(false)
// 返回 true 表示当前牌被无懈可击抵消
bool askWJ(int user, int target, bool isProtect)
{
if (pd() != 0) return false;
int cur = user;
do
{
if (stre[cur] <= 0) { cur = nex[cur]; continue; }
if (findJ(cur) == -1) { cur = nex[cur]; continue; }
bool willProtect;
int jTarget;
if (!isProtect) // 当前牌是攻击(锦囊),出J是保护
{
willProtect = true;
jTarget = target;
}
else // 当前牌是保护(J),出J是攻击
{
willProtect = false;
jTarget = user;
}
if (canUseJ(cur, jTarget, willProtect))
{
useJ(cur); // 弃置最左的J
// 跳身份处理
if (willProtect) // 献殷勤
{
if (js[cur] == 'Z' && (jTarget == 0 || (js[jTarget] == 'Z' && tiao[jTarget])))
tiao[cur] = true, lei[cur] = false;
else if (js[cur] == 'F' && (js[jTarget] == 'F' && tiao[jTarget]))
tiao[cur] = true, lei[cur] = false;
// 主猪献殷勤不需跳身份
}
else // 表敌意
{
if (js[cur] == 'Z' && js[jTarget] == 'F' && tiao[jTarget])
tiao[cur] = true, lei[cur] = false;
else if (js[cur] == 'F' && (jTarget == 0 || (js[jTarget] == 'Z' && tiao[jTarget])))
tiao[cur] = true, lei[cur] = false;
// 主猪表敌意给已跳反猪,若目标有类反标记则清除
if (js[cur] == 'M' && js[jTarget] == 'F' && tiao[jTarget])
lei[jTarget] = false;
}
// 递归:询问是否有人无懈可击这张J
if (!askWJ(cur, jTarget, willProtect)) // 这张J没有被抵消 → 成功抵消当前牌
return true;
// 否则J被抵消,继续循环询问下一个猪
}
cur = nex[cur];
} while (cur != user);
return false;
}
/* ---------- 锦囊结算 ---------- */
void NW(int now, char KD) // 南蛮/万箭
{
int cur = nex[now];
while (cur != now)
{
if (stre[cur] <= 0) { cur = nex[cur]; continue; }
// 无懈可击抵消此次范围伤害
if (askWJ(now, cur, false))
{
cur = nex[cur];
continue;
}
bool kou = true;
for (int j = l[cur]; j <= r[cur]; ++j)
if (p[cur][j] == KD)
{
p[cur][j] = 0;
kou = false;
break;
}
if (kou)
{
stre[cur]--;
if (cur == 0 && !tiao[now])
lei[now] = 1;
dealdead(cur, now);
if (pd()) return;
}
cur = nex[cur];
}
}
void do_K(int now, int obj)
{
// 跳身份
if (js[now] == 'Z' && js[obj] == 'F' && tiao[obj])
tiao[now] = true, lei[now] = false;
if (js[now] == 'F' && (js[obj] == 'M' || (js[obj] == 'Z' && tiao[obj])))
tiao[now] = true, lei[now] = false;
bool kou = true;
for (int i = l[obj]; i <= r[obj]; ++i)
if (p[obj][i] == 'D')
{
p[obj][i] = 0;
kou = false;
break;
}
if (kou)
{
stre[obj]--;
dealdead(obj, now);
}
}
bool haveK(int now)
{
for (int i = l[now]; i <= r[now]; ++i)
if (p[now][i] == 'K')
{
p[now][i] = 0;
return true;
}
return false;
}
void do_F(int now, int obj)
{
// 跳身份
if (js[now] == 'Z' && js[obj] == 'F' && tiao[obj])
tiao[now] = true, lei[now] = false;
if (js[now] == 'F' && (js[obj] == 'M' || (js[obj] == 'Z' && tiao[obj])))
tiao[now] = true, lei[now] = false;
// 无懈可击抵消决斗
if (askWJ(now, obj, false))
return; // 决斗无效
bool turn = false; // false=obj先出杀
while (true)
{
int cur = turn ? now : obj;
int opp = turn ? obj : now;
if (js[cur] == 'Z' && js[opp] == 'M')
break;
if (haveK(cur))
turn = !turn;
else
break;
}
if (turn)
{
stre[now]--;
dealdead(now, obj);
}
else
{
stre[obj]--;
dealdead(obj, now);
}
}
void cp(int now)
{
bool usedK = false;
int F_target = -1;
while (pd() == 0 && stre[now] > 0)
{
int pos = -1;
for (int i = l[now]; i <= r[now]; ++i)
{
if (p[now][i] == 0) continue;
char c = p[now][i];
if (c == 'P' && stre[now] < 4)
{
pos = i; break;
}
if (c == 'Z')
{
pos = i; break;
}
if (c == 'N' || c == 'W')
{
pos = i; break;
}
if (c == 'K')
{
int obj = nex[now];
if (stre[obj] > 0)
{
bool ok = false;
if (js[now] == 'M')
ok = (js[obj] == 'F' && tiao[obj]) || (!tiao[obj] && lei[obj]);
else if (js[now] == 'Z')
ok = (js[obj] == 'F' && tiao[obj]);
else if (js[now] == 'F')
ok = (obj == 0) || (js[obj] == 'Z' && tiao[obj]);
if (ok && (!usedK || zgln[now]))
{
pos = i; break;
}
}
}
if (c == 'F')
{
int obj = -1;
if (js[now] == 'M')
{
for (int j = nex[now]; j != now; j = nex[j])
{
if (stre[j] <= 0) continue;
if ((js[j] == 'F' && tiao[j]) || (!tiao[j] && lei[j]))
{ obj = j; break; }
}
}
else if (js[now] == 'Z')
{
for (int j = nex[now]; j != now; j = nex[j])
{
if (stre[j] <= 0) continue;
if (js[j] == 'F' && tiao[j])
{ obj = j; break; }
}
}
else if (js[now] == 'F')
{
if (stre[0] > 0) obj = 0;
else
{
for (int j = nex[now]; j != now; j = nex[j])
{
if (stre[j] <= 0) continue;
if (js[j] == 'M' || (js[j] == 'Z' && tiao[j]))
{ obj = j; break; }
}
}
}
if (obj != -1)
{
pos = i;
F_target = obj; // 保存目标
break;
}
}
// 跳过 J(无懈可击不能主动使用)
}
if (pos == -1) break;
char card = p[now][pos];
p[now][pos] = 0;
if (card == 'P')
{
stre[now]++;
}
else if (card == 'Z')
{
zgln[now] = true;
}
else if (card == 'N')
{
NW(now, 'K');
if (pd()) break;
}
else if (card == 'W')
{
NW(now, 'D');
if (pd()) break;
}
else if (card == 'K')
{
do_K(now, nex[now]);
usedK = true;
if (pd()) break;
}
else if (card == 'F')
{
if (F_target != -1 && stre[F_target] > 0)
{
do_F(now, F_target);
if (pd()) break;
}
F_target = -1;
}
}
}
int main()
{
init();
for (int i = 0; pd() == 0; i = nex[i])
{
if (stre[i] <= 0) continue;
mp(i, 2);
cp(i);
}
printf("%s\n", pd() == 1 ? "MP" : "FP");
for (int i = 0; i < n; ++i)
{
if (stre[i] <= 0)
printf("DEAD\n");
else
{
bool first = true;
for (int j = l[i]; j <= r[i]; ++j)
if (p[i][j] != 0)
{
if (!first) printf(" ");
printf("%c", p[i][j]);
first = false;
}
printf("\n");
}
}
return 0;
}