题目链接:https://www.luogu.com.cn/problem/P2482
总结了几个坑点…
(这种改一改都能当课设交的东西真的有人比赛的时候写得出来吗)
- 使用锦囊牌时可能存在跳反或跳忠(打出无懈可击)的情况,一旦出现了有可能要从头检索是否有可使用的杀或决斗
- 装备诸葛连弩时同理;
- 对别人打出决斗自己可能会死,此时需要中断回合;
- 反猪的决斗一定是对主猪用的;
- 主猪杀了忠猪后,弃牌的时候不要忘了诸葛连弩;
- 同时不要忘了此时遍历的手牌已经没了;
- 但是不能直接中断回合,比如忠猪如果死于万箭齐发,那么在它之后还可能有反猪因此死掉,这种情况下主公会摸三张牌,回合仍可能继续;
- 角色死后不要鞭尸,南蛮入侵、万箭齐发等需要遍历玩家的情况记得跳过死者;
- 一有角色死亡就要记得计算距离;
- 距离是单向的;
- 牌堆如果没牌了会持续抽最后一张牌;
- 无懈可击可以无限连;
- 如果自身没有跳反/忠,那么无懈可击也不会对自己用
- 使用过和决斗和无懈可击的角色身份一定是明确的
- 反猪并不会帮助类反猪,如果忠猪被变成了类反猪被主猪决斗了那就只能挨打掉血
- 由于角色死亡可能导致游戏结束,因此每次有角色死透了都要康康死的是不是主公或最后一个反贼
附上Ac代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
struct Player
{
char card[2005];
int mp_sign[15];
int card_num=0,hp=4,card_cur=0,card_st=1;
bool mp,zp,fp,weapon,expose;
int wx,shan,atk;
int uwx,u_shan;
}player[15];
char card[2005];
int n,cur=0,fst_kill,fst_jd;
bool fp_ep,zp_ep;
void get_card(int i,char ch)//获取卡牌
{
player[i].card[++player[i].card_cur]=ch;
++player[i].card_num;
if(ch=='J')
++player[i].wx;
else if(ch=='D')
++player[i].shan;
}
int z_wx(const int &num,const int &n)//主公一派打出无懈
{
for(int k=num,i=0;i<n;++i,k=k+1>n?1:k+1)
{
if(player[k].zp&&player[k].wx!=0&&player[k].hp>0)//活的忠臣
{
if(!player[k].expose)
player[k].expose=zp_ep=true,player[1].mp_sign[k]=1;
--player[k].card_num,--player[k].wx,++player[k].uwx;
return k;
}
else if(player[k].mp&&player[k].wx!=0)//主公
{
--player[k].card_num,--player[k].wx,++player[k].uwx;
return k;
}
}
return -1;
}
int f_wx(const int &num,const int &n)//反贼一派打出无懈
{
for(int k=num,i=0;i<n;++i,k=k+1>n?1:k+1)
{
if(player[k].fp&&player[k].wx!=0&&player[k].hp>0)//活的反贼
{
if(!player[k].expose)
player[k].expose=fp_ep=true,player[1].mp_sign[k]=-1;
--player[k].card_num,--player[k].wx,++player[k].uwx;
return k;
}
}
return -1;
}
void dying(const int &num,const int &m,const int &j)//濒死状态
{
for(int i=player[j].card_st;i<=player[j].card_cur;++i)
{
if(player[j].card[i]=='P')//自救成功
{
++player[j].hp,--player[j].card_num,player[j].card[i]=0;
return ;
}
}
if(player[j].mp)
return ;
int a=-1;
for(int i=j-1>0?j-1:n;i!=j;i=i-1>0?i-1:n) //角色死亡导致距离改变
{
if(player[i].hp>0)
{
a=i;
break;
}
}
for(int i=j+1>n?1:j+1;i!=j;i=i+1>n?1:i+1)
{
if(player[i].hp>0)
{
player[a].atk=i;
break;
}
}
if(player[j].fp)//反贼死亡,击杀者摸牌
{
cur=min(m,cur+1),get_card(num,card[cur]);
cur=min(m,cur+1),get_card(num,card[cur]);
cur=min(m,cur+1),get_card(num,card[cur]);
return ;
}
if(player[j].zp&&player[num].mp)//主公杀死忠臣失去所有手牌
{
player[num].uwx=player[num].u_shan=0;
player[num].card_num=player[num].wx=player[num].shan=0;
player[num].card_st=player[num].card_cur+1;
player[num].weapon=false,fst_jd=fst_kill=0;
return ;
}
}
bool jd(const int &a,const int &b)决斗判定
{
while(true)
{
bool k_left=false;
for(int j=player[b].card_st;j<=player[b].card_cur;++j)
{
if(player[b].card[j]=='K')
{
player[b].card[j]=0,--player[b].card_num,k_left=true;
break;
}
}
if(k_left)
{
k_left=false;
for(int j=player[a].card_st;j<=player[a].card_cur;++j)
{
if(player[a].card[j]=='K')
{
player[a].card[j]=0,--player[a].card_num,k_left=true;
break;
}
}
if(!k_left)
return false;
}
else
return true;
}
}
bool get_atk_id(const int &atk,const int &num)
{
if(player[num].mp||player[num].zp)//攻击发起人为主或忠
{
if(player[atk].fp&&player[atk].expose)//对方为明反时动手
return false;
else if(player[num].mp&&player[num].mp_sign[atk]==-1)//主公会打类反
return false;
}
else//反贼能动手了
{
if((player[atk].zp&&player[atk].expose)||player[atk].mp)//当且仅当对方为明忠或主时动手
return false;
}
return true;//非敌对单位
}
bool z_f_wx(const int &num)//主公一排派先出无懈
{
int temp=num;
while(true)
{
temp=z_wx(temp,n);
if(temp==-1)
return false;
else
{
temp=f_wx(temp,n);
if(temp==-1)
return true;
}
}
}
bool f_z_wx(const int &num)//反贼一排派先出无懈
{
int temp=num;
while(true)
{
temp=f_wx(temp,n);
if(temp==-1)
return false;
else
{
temp=z_wx(temp,n);
if(temp==-1)
return true;
}
}
}
int main()
{
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
string s;
char ch;
bool atk_id;
int m,num=1,kill,num_fp=0,atk;
cin>>n>>m;
for(int i=1;i<=n;++i)//开局
{
cin>>s;
if(i!=n)
player[i].atk=i+1;
else
player[i].atk=1;
if(s=="MP")
player[i].mp=true;
else if(s=="ZP")
player[i].zp=true;
else
player[i].fp=true,++num_fp;
for(int j=1;j<=4;++j)
{
cin>>ch;
get_card(i,ch);
}
}
for(int i=1;i<=m;++i)
cin>>card[i];
if(num_fp==0)
goto game_over;
fp_ep=zp_ep=false;//一开始谁也没跳
while(true)
{
cur=min(m,cur+1),get_card(num,card[cur]);
cur=min(m,cur+1),get_card(num,card[cur]);
kill=fst_kill=fst_jd=0;//当前角色出杀数
atk=player[num].atk;//获取可杀对象
atk_id=get_atk_id(atk,num);//获取是否为非敌对单位
for(int i=player[num].card_st;i<=player[num].card_cur;++i)
{
if(atk!=player[num].atk)//可杀对象被aoe死了换人了
{
atk=player[num].atk;
bool temp=get_atk_id(atk,num);
if(temp!=atk_id)//敌对关系变化
{
if((kill<=0||player[num].weapon)&&atk_id)//还能出杀且对方为敌对单位
{
if(fst_kill!=0)//如果前面有没出的杀就跳回去出杀
i=fst_kill,fst_kill=0;
}
atk_id=temp;
}
}
else if(fp_ep||zp_ep)//有人跳了,检查可攻击对象是否已敌对
{
bool temp=get_atk_id(atk,num);
if(temp!=atk_id)//敌对关系变化
{
if((kill<=0||player[num].weapon)&&atk_id)//还能出杀且对方为敌对单位
{
if(fst_kill!=0)//如果前面有没出的杀就跳回去出杀
i=fst_kill,fst_kill=0;
}
atk_id=temp;
}
}
if((player[num].zp||num==1)&&fp_ep&&fst_jd!=0)//在主或忠的回合有人跳反了,且前面有决斗
{
i=min(i,fst_jd);
fst_jd=0;
}
if(player[num].card[i]=='J'||player[num].card[i]=='D'||player[num].card[i]==0)//响应牌或出过的牌
continue;
if(player[num].card[i]=='Z')//装备诸葛连弩
{
player[num].card[i]=0,--player[num].card_num;
if(!player[num].weapon)//此前未装备
{
player[num].weapon=true;
if(fst_kill!=0)//前边有杀,跳转
i=fst_kill-1,fst_kill=0;
}
}
else if(player[num].card[i]=='P')//你在想peach
{
if(player[num].hp<4)
player[num].card[i]=0,++player[num].hp,--player[num].card_num;
else
continue;
}
else if(player[num].card[i]=='N')//使用南蛮入侵
{
player[num].card[i]=0,--player[num].card_num;
for(int j=num+1>n?1:num+1;j!=num;j=j+1>n?1:j+1)//玩家结算
{
if(player[j].hp<=0)
continue;
if(player[j].mp||(player[j].zp&&player[j].expose))//受害者为明忠或主
{
if(z_f_wx(num))//无懈可击生效
continue;
else
{
bool sha_y=false;
for(int k=player[j].card_st;k<=player[j].card_cur;++k)
{
if(player[j].card[k]=='K')
{
--player[j].card_num;
player[j].card[k]=0;
sha_y=true;
break;
}
}
if(!sha_y)//没杀
{
--player[j].hp;
if(player[j].hp<=0)
{
dying(num,m,j);
if(player[1].hp<=0)
goto game_over;
else if(num==1&&player[j].zp)
i=player[num].card_cur;
}
if(j==1&&player[num].expose==false)//未明身份导致主公掉血视为类反
player[1].mp_sign[num]=-1;
}
else
continue;
}
}
else if(player[j].fp&&player[j].expose)//受害者为明反
{
if(f_z_wx(num))//无懈可击生效
continue;
else
{
bool sha_y=false;
for(int k=player[j].card_st;k<=player[j].card_cur;++k)
{
if(player[j].card[k]=='K')
{
--player[j].card_num;
player[j].card[k]=0;
sha_y=true;
break;
}
}
if(!sha_y)//没杀
{
--player[j].hp;
if(player[j].hp<=0)
{
dying(num,m,j);
if(player[j].hp<=0)
{
--num_fp;
if(num_fp<=0)
{
player[num].card_cur-=3;
player[num].card_num-=3;
goto game_over;
}
}
}
}
else
continue;
}
}
else //身份不明
{
bool sha_y=false;
for(int k=player[j].card_st;k<=player[j].card_cur;++k)
{
if(player[j].card[k]=='K')
{
--player[j].card_num;
player[j].card[k]=0;
sha_y=true;
break;
}
}
if(!sha_y)//没杀
{
--player[j].hp;
if(player[j].hp<=0)
{
dying(num,m,j);
if(player[j].hp<=0)
{
if(player[j].fp)
{
--num_fp;
if(num_fp<=0)
{
player[num].card_cur-=3;
player[num].card_num-=3;
goto game_over;
}
}
else if(num==1&&player[j].zp)//主杀忠
i=player[num].card_cur;
}
}
}
}
}
}
else if(player[num].card[i]=='W')//使用万箭齐发
{
player[num].card[i]=0,--player[num].card_num;
for(int j=num+1>n?1:num+1;j!=num;j=j+1>n?1:j+1)//玩家结算
{
if(player[j].hp<=0)
continue;
if(player[j].mp||(player[j].zp&&player[j].expose))//明忠或主
{
if((z_f_wx(num)))//无懈可击生效
continue;
else
{
if(player[j].shan>0)
{
--player[j].card_num;
--player[j].shan,++player[j].u_shan;
}
else//没闪
{
--player[j].hp;
if(player[j].hp<=0)
{
dying(num,m,j);
if(player[1].hp<=0)
goto game_over;
else if(num==1&&player[j].zp)//主杀忠
i=player[num].card_cur;
}
if(j==1&&player[num].expose==false)//未明身份导致主公掉血视为类反
player[1].mp_sign[num]=-1;
}
}
}
else if(player[j].fp&&player[j].expose)//明反
{
if(f_z_wx(num))//无懈可击生效
continue;
else
{
if(player[j].shan>0)
{
--player[j].card_num;
--player[j].shan,++player[j].u_shan;
}
else//没闪
{
--player[j].hp;
if(player[j].hp<=0)
{
dying(num,m,j);
if(player[j].hp<=0)
{
--num_fp;
if(num_fp<=0)
{
player[num].card_cur-=3;
player[num].card_num-=3;
goto game_over;
}
}
}
}
}
}
else //身份不明
{
if(player[j].shan>0)
{
--player[j].card_num;
--player[j].shan,++player[j].u_shan;
}
else//没闪
{
--player[j].hp;
if(player[j].hp<=0)
{
dying(num,m,j);
if(player[j].hp<=0)
{
if(player[j].fp)
{
--num_fp;
if(num_fp<=0)
{
player[num].card_cur-=3;
player[num].card_num-=3;
goto game_over;
}
}
else if(num==1&&player[j].zp)//主杀忠
i=player[num].card_cur;
}
}
}
}
}
}
else if(player[num].card[i]=='K')//有杀
{
if(((!player[num].weapon)&&kill>0)||atk_id)//出杀次数上限了或对方为非攻击对象
{
if(fst_kill==0)
fst_kill=i;
continue;
}
else
{
player[num].card[i]=0,--player[num].card_num,++kill;//杀人啦
if(player[atk].shan>0)//嘿嘿打不到
++player[atk].u_shan,--player[atk].shan,--player[atk].card_num;
else
{
--player[atk].hp;//夭寿了
if(player[atk].hp<=0)//死人啦
{
dying(num,m,atk);//看看还有救没有
if(player[atk].hp<=0)//救不了,告辞
{
if(player[atk].fp)//是个反贼
{
--num_fp;
if(num_fp<=0)//反贼死光了
{
player[num].card_cur-=3;
player[num].card_num-=3;
goto game_over;
}
}
else if(player[atk].zp)//对不起你是个好人
{
if(num==1&&player[atk].zp)//主杀忠
i=player[num].card_cur;
}
else if(player[atk].mp)//没了没了
goto game_over;
}
}
else if(atk==1)//检查是否有跳反
{
if(!player[num].expose)
player[num].expose=fp_ep=true;
}
}
}
}
else if(player[num].card[i]=='F')//决斗
{
if(player[num].mp)//主公
{
int temp=0;
for(int j=num+1>n?1:num+1;j!=num;j=j+1>n?1:j+1)
{
if(player[j].hp<=0)//起码得活着
continue;
if(player[num].mp_sign[j]==-1)//类反或明反
{
temp=j;
break;
}
}
if(temp!=0)
{
player[num].card[i]=0,--player[num].card_num;
if(player[temp].zp)//误伤主公的类反忠
{
--player[temp].hp;
if(player[temp].hp<=0)
{
dying(num,m,temp);
if(player[temp].hp<=0&&num==1&&player[atk].zp)//主杀忠
i=player[num].card_cur;
}
}
else if(player[temp].fp)//反贼
{
if(player[temp].expose&&f_z_wx(num))//明反被无懈救了
continue;
if(jd(num,temp))//主公赢了
{
--player[temp].hp;
if(player[temp].hp<=0)
{
dying(num,m,temp);
if(player[temp].hp<=0)
{
--num_fp;
if(num_fp<=0)
{
player[num].card_cur-=3;
player[num].card_num-=3;
goto game_over;
}
}
}
}
else//主公输了
{
--player[num].hp;
if(player[num].hp<=0)
{
dying(temp,m,num);
if(player[num].hp<=0)
goto game_over;
}
else if(!player[temp].expose)
player[temp].expose=fp_ep=true;
}
}
}
else
{
if(fst_jd==0)
fst_jd=i;
continue;
}
}
else if(player[num].zp)//忠臣
{
int temp=0;
for(int j=num+1>n?1:num+1;j!=num;j=j+1>n?1:j+1)
{
if(player[j].hp<=0)//死的不要
continue;
if(player[j].fp&&player[j].expose)//明反
{
temp=j;
break;
}
}
if(temp!=0)
{
player[num].card[i]=0,--player[num].card_num;
if(!player[num].expose)
player[num].expose=zp_ep=true,player[1].mp_sign[num]=1;
if(f_z_wx(num))
continue;
else
{
if(jd(num,temp))//忠臣赢了
{
--player[temp].hp;
if(player[temp].hp<=0)
{
dying(num,m,temp);
if(player[temp].hp<=0)
{
--num_fp;
if(num_fp<=0)
{
player[num].card_cur-=3;
player[num].card_num-=3;
goto game_over;
}
}
}
}
else//忠臣输了
{
--player[num].hp;
if(player[num].hp<=0)
{
dying(temp,m,num);
if(player[num].hp<=0)//不仅输了还被打死了
break;
}
}
}
}
else
{
if(fst_jd==0)
fst_jd=i;
continue;
}
}
else if(player[num].fp)//反贼
{
player[num].card[i]=0,--player[num].card_num;
if(!player[num].expose)
fp_ep=player[num].expose=true,player[1].mp_sign[num]=-1;
if(z_f_wx(num))//无懈可击生效
continue;
else
{
if(jd(num,1))//反贼赢了
{
--player[1].hp;
if(player[1].hp<=0)
{
dying(num,m,1);
if(player[1].hp<=0)
goto game_over;
}
}
else//反贼输了
{
--player[num].hp;
if(player[num].hp<=0)
{
dying(1,m,num);
if(player[num].hp<=0)
{
--num_fp;
if(num_fp<=0)
{
player[num].card_cur-=3;
player[num].card_num-=3;
goto game_over;
}
break;
}
}
}
}
}
}
}
do{
num=num+1>n?1:num+1;
}while(player[num].hp<=0);
}
game_over:
if(player[1].hp<=0)
cout<<"FP"<<endl;
else
cout<<"MP"<<endl;
for(int i=1;i<=n;++i)
{
if(player[i].hp<=0)
cout<<"DEAD"<<endl;
else
{
for(int j=player[i].card_st;j<=player[i].card_cur;++j)
{
if(player[i].card[j]=='D')
{
if(player[i].u_shan>0)
--player[i].u_shan;
else
cout<<"D ";
}
else if(player[i].card[j]=='J')
{
if(player[i].uwx>0)
--player[i].uwx;
else
cout<<"J ";
}
else if(player[i].card[j]!=0)
cout<<player[i].card[j]<<" ";
}
cout<<endl;
}
}
}