LG2482 [SDOI2010]猪国杀

发布于 2019-11-13  3.95k 次阅读


Pig Country Kill

很古怪的翻译,不过它确实叫猪(Pig)国(Country)杀(Kill)。

我们来好好整理一下这道题目。题面虽较长,但内容基本清晰,只是有部分很Pig的操作部分,很容易让第一次看见这道题目的人百思不得其解。

先整理一下这道长长的题面。


First:人物

四位玩家,初始四张手牌,血量上限4,初始血量4,会告诉你整个牌堆的牌,每位玩家每个回合从牌堆顶部抽走两张牌,放在自己手牌的右侧。人物分主猪,忠猪,和反猪,主猪只有一只,反猪和忠猪可以有多只,反猪全死主猪获胜,主猪死亡反猪获胜


Second:关于出牌

从主猪开始逆时针旋转,就是沿序号为1 2 3 ... n的顺序依次出牌。每头猪在出牌的时候都会从左往右挨个判断每张牌是否可用,将可用的牌直接用掉。牌分为P(桃),K(杀),D(闪)和锦囊牌F(决斗),N(南猪入侵),W(万箭齐发),J(无懈可击)和装备牌Z(猪哥连弩)。具体操作会在下面贴代码的地方说明。


Third:猪的特性

有南猪入侵和万箭齐发一定用,有桃且生命值没满一定吃,有猪哥连弩一定装,受到杀,南猪入侵,万箭齐发可以用闪,杀,闪抵消一定抵消。


Forth:高级操作

跳忠和跳反,即表明自己是忠猪或是反猪,主猪开局直接跳,忠猪只会跳忠,反猪只会跳反。已经跳(后面我们将跳忠和跳反统称为跳,因为忠猪不会跳反,反猪不会跳忠)了的猪只会对同样跳了的同类献殷勤,同时对跳了的敌猪表敌意。跳反猪同时会对主猪表敌意,因为主猪和忠猪是统一阵营。


Fifth:献殷勤和表敌意

猪A对猪B使用了杀或是决斗,叫作猪A对猪B表敌意。猪A用无懈可击帮猪B抵挡住攻击性锦囊牌,叫作猪A对猪B献殷勤。猪C对猪B表敌意,被猪A用无懈可击抵挡住,叫作猪A对猪B先殷勤。猪C对猪B献殷勤,被猪A用无懈可击抵消,叫作猪A对猪B表敌意。


Sixth:某些猪的特性

主猪会竭力保护自己,会对跳忠猪献殷勤,对跳反猪表敌意。有“类反猪”一概念,所有对他产生伤害的猪都是“类反猪”(才有了样例中的美好结局),主猪同时会对类反猪表敌意;对忠猪来说,它会对跳反猪(没有类反猪)表敌意,角斗时如果对方是主猪,那么不会出杀,会自愿扣血,即使自己会死,会对主猪和已经跳忠的猪献殷勤;对反猪来说,如果能杀到主猪,一定对主猪表敌意(决斗一定打主猪),如果杀不到,对跳忠猪表敌意,对跳反猪一定献殷勤。

上面的情况如果可以同时有多个对象可以表敌意或献殷勤,选取逆时针找到的第一位。且如果能献殷勤或表敌意,一定做


Seventh:其他

如果主猪死亡,游戏结束。如果主猪杀死了忠猪,主猪所有的手牌(包括装备)全部弃置。如果反猪全部死亡,游戏结束。反猪死亡后,杀他的猪从牌堆处摸三张牌(即使他是反猪)。如果游戏结束,那么游戏直接在此时停止,接下来需要做的所有事情都被截止。杀只能打到自己正后面的那一头猪,决斗可以随便决斗。万箭齐发和南猪入侵对除自己以外的所有人顺时针使用。无懈可击可以对任何人使用,无懈可击可以使无懈可击无效,可以使决斗报废(不使任何一方受到伤害)。大部分手牌无法在非自己的回合使用,在自己濒死时(血量为0)可以使用桃(自己的),在自己的献殷勤对象被表敌意时可以出无懈可击,在自己的表敌意对象被献殷勤时可以出无懈可击。注意有的猪死去后会使一些猪之间的距离产生变化

游戏内容差不多就是这样了,如果看不懂,多看几遍也能理解,如果还是难以理解的话,可以往下看本人的AC代码以及解释,可以帮助你加深对本题的理解。


代码

定义

#include
#include
#include
#include
//头文件
using std::ios;
//用using namespace就不用这个了
//以下定义虽复杂,但是方便在程序中梳理思路,让我们不易混淆true和false的关系
#define CANNOT_USE_THIS_CARD true //不能使用这张牌
#define CAN_USE_THIS_CARD false //可以使用这张牌
#define THIS_PIG_IS_DEAD true //这头猪死了
#define THIS_PIG_IS_NOT_DEAD false //这头猪还没死
#define THIS_PIG_IS_JUMP true //这头猪已经跳了
#define THIS_PIG_IS_NOT_JUMP false //这头猪还没有跳
#define THIS_PIG_LIKE_BAD true //这头猪类反
#define THIS_PIG_DO_NOT_LIKE_BAD false //这头猪不类反
#define CROSSBOW_ON true //装备猪哥连弩
#define CROSSBOW_DOWN false //没有装备猪哥连弩
#define THIS_TURN_USED_KILL true //这一回合已经使用杀
#define THIS_TURN_DO_NOT_USE_KILL false //这一回合还没有使用过杀
struct card //对每一张卡牌制造的结构体
{
char which ;//牌的种类
bool use ;//牌是否已用
};
typedef std::vector::iterator myit; //这是牌堆的指针类型
class pig //对每头猪使用的类
{
private: //私有
int hp ;//生命值
bool use_kill ;//这个回合
bool crossbow ;//是否有装猪哥连弩
bool jumped ;//是否已跳
bool like_bad ;//是否类反
void die (int) ;//死掉了
void clear (void) ;//清空
void del (myit&) ;//删除某迭代器指向的玩意
myit find (char) ;//找某张牌
void cut (void) ;//拿一张牌
void use (card&) ;//用掉某张牌
void hurt (int) ;//受到伤害
bool canuse (char) ;//可以使用这张牌
int find_K (void) ;//找杀的对象
int find_F (void) ;//找人决斗
bool K_respond (void) ;//反应杀
bool N_respond (void) ;//反应南猪入侵
bool W_respond (void) ;//反应万箭齐发
bool ask_J (int) ;//询问是否出无懈可击
bool back_J (int) ;//反应无懈可击
public: //公共
pig (void) ;//析构函数
int num ;//序号
bool dead ;//死没死
std::string name ;//身份
std::vector cards ;//手牌
void myturn (void) ;//到我的回合了
void jump (void) ;//跳
void K (int) ;//杀
void F (int) ;//决斗
void N (void) ;//南猪入侵
void W (void) ;//万箭齐发
};
void gameover(std::string);//游戏结束
int n,m;//猪头数量和牌堆深度
int FP;//反猪数量
card stack[2005];//牌堆(之前想写栈发现不用那么做)
pig member[15];//每头猪
int top=1;//牌堆指针

定义完毕,接下来只要对着上面的定义实现每个函数就可以了。

虽然这里的宏定义名称非常长,但是在以下的代码中就可以将难以分辨的true & false用易于理解的标识符代替,使下文结构更加清晰,Debug时更加方便


主函数

int main()
{
ios::sync_with_stdio(false);//流优化
cin>>n>>m;//输入
for(register int i=1;i<=n;i++)
{
cin>>member[i].name;//输入猪头名字
member[i].num=i;//猪头序号
if(member[i].name=="FP") FP++;//反猪数量
for(register int j=1;j<=4;j++)
{
card c;
cin>>c.which;//每张手牌
c.use=CAN_USE_THIS_CARD;//可以用
member[i].cards.push_back(c);//手牌放置
}
}
for(top=1;top<=m;top++)
{//牌堆
card c;
cin>>c.which;//输入牌堆中每一张牌的信息
c.use=CAN_USE_THIS_CARD;//可以用
stack[top]=c;//把牌放进牌堆
}
top=1;//原来想写个stack,后来废了
int point=0;//轮到谁了
member[1].jump();//主猪跳出来
while(true)
{
point=point%n+1;//一个圈
if(member[point].dead==THIS_PIG_IS_DEAD) continue;//如果他死了,跳过
member[point].myturn();//这是他的回合
}
}

主函数结构基本清晰,处理了输入,牌堆,手牌,还有回合的问题。

打完了这些,游戏基本格局就以确定,接下来实现游戏内容。


游戏结束处理

void gameover(std::string who)//谁赢了
{//死掉了
cout<use==CANNOT_USE_THIS_CARD) continue;//如果这张牌已经使用过,那么不存在于牌堆
cout<which<<' ';//输出手牌的信息,然后打个空格
}
cout<

死亡处理

void pig::die(int who)
{//死了
this->dead=THIS_PIG_IS_DEAD;//这玩意死了
if(this->name=="MP")//如果主猪死了
{
gameover("FP");//反猪赢了
}
if(this->name=="FP") FP--;//如果反猪死了,总数减减
if(FP==0) gameover("MP");//如果反猪死光了
if(this->name=="FP")//如果杀死了是反猪
{
member[who].cut();//拿牌x1
member[who].cut();//拿牌x2
member[who].cut();//拿牌x3
}
if(this->name=="ZP"&&member[who].name=="MP")
{//如果主猪杀掉了忠猪
member[who].clear();//清空
}
return ;
}

手牌的清空、删除、寻找和拿牌等

void pig::clear(void)
{
this->cards.clear();//自己的手牌清空
this->crossbow=CROSSBOW_DOWN;//把弩卸掉
return ;
}
void pig::del(myit& it)
{//删除某张牌
it->use=CANNOT_USE_THIS_CARD;//删除这个迭代器指向的牌,让它不可用
return ;
}
myit pig::find(char which)
{//寻找某张牌
for(myit it=this->cards.begin();it!=this->cards.end();it++)
{//搜索每一张牌
if(it->use==CANNOT_USE_THIS_CARD) continue;//如果用过了
if(it->which==which) return it;//如果这是我要找的牌
}
return this->cards.end();//找不到,输出vector的end
}
void pig::cut(void)
{
this->cards.push_back(stack[top++]);//把牌堆上面的拿掉
if(top>m) top=m;//好像有数据说牌不够
return;
}
void pig::use(card& c)
{//用某张牌
if(c.which=='K')
{//如果这是杀
int who;
who=this->find_K();//找一个人来杀
if(who!=0)//如果找到了
{
c.use=CANNOT_USE_THIS_CARD;//用掉
this->K(who);//杀它
}
}
else if(c.which=='P')
{//如果这是桃
if(this->hp<4)//如果它的生命值没有满
{
c.use=CANNOT_USE_THIS_CARD;//用掉
this->hp++;//生命值加一点
}
}
else if(c.which=='F')
{//如果这是决斗
int who;
who=this->find_F();//找个人来决斗
if(who!=0)//如果找到了
{
c.use=CANNOT_USE_THIS_CARD;//用掉
this->F(who);//决斗他
}
}
else if(c.which=='N')
{//南猪入侵
c.use=CANNOT_USE_THIS_CARD;//用掉
this->N();//使用南猪入侵
}
else if(c.which=='W')
{//万箭齐发
c.use=CANNOT_USE_THIS_CARD;//用掉
this->W();//使用万箭齐发
}
else if(c.which=='Z')
{//猪哥连弩
c.use=CANNOT_USE_THIS_CARD;//用掉
this->crossbow=CROSSBOW_ON;//装上
}
}
void pig::hurt(int who)//谁杀的
{
this->hp--;//受到伤害
if(this->hp==0)//如果他死了
{
myit t=this->find('P');//找桃
if(t==this->cards.end()) this->die(who);//找不到,死掉
else
{
this->del(t);//找到了,用掉
this->hp++;//生命值加一点
}
}
}
bool pig::canuse(char c)
{//判断能否使用
if(c=='P'&&this->hp<4) return true;//如果是桃子且生命值未满
if((c=='K'&&this->find_K()!=0)||(c=='F'&&this->find_F()!=0)||c=='N'||c=='W'||c=='Z') return true;//如果可以用
return false;//不然就不该用
}

以上内容理解起来都较为简单,下面的代码难度会有所提高

寻找'杀'的目标

对于主猪、忠猪和反猪来说,他们的目的不同,但杀的距离都相同,为$1$,对于每头猪,我们找到他后方的第一头猪(也是它唯一能杀到的一头猪),判断是否应该对它用杀,如果该用,返回这头猪的编号;如果不该用,直接结束函数,返回$0$(表示没有找到杀的猪)。

主猪要找的是跳反猪和类反猪,忠猪要找的是跳反猪,反猪要找的是跳忠猪或是主猪。

int pig::find_K(void)
{//找个人来杀
if(this->use_kill==THIS_TURN_USED_KILL&&this->crossbow==CROSSBOW_DOWN) return 0;//如果这回合已经用过了杀而没有装过猪哥连弩
if(this->name=="MP")
{//我是主猪
for(register int point=this->num%n+1;point!=this->num;point=point%n+1)
{//逆时针寻找
if(member[point].dead==THIS_PIG_IS_DEAD) continue;//如果死掉了,跳过去
if(member[point].like_bad==THIS_PIG_LIKE_BAD||(member[point].name=="FP"&&member[point].jumped==THIS_PIG_IS_JUMP))
{//如果这猪是类反猪或是已经跳反
return point;//就决斗他
}//否则继续找
else return 0;
}
}
else if(this->name=="ZP")
{//我是忠猪
for(register int point=this->num%n+1;point!=this->num;point=point%n+1)
{//逆时针寻找
if(member[point].dead==THIS_PIG_IS_DEAD) continue;//这玩意死了,跳过去
if(member[point].name=="FP"&&member[point].jumped==THIS_PIG_IS_JUMP)
{//如果这是已经跳反的猪头
return point;//就杀他
}
else return 0;
}
}
else if(this->name=="FP")
{//我是反猪
for(register int point=this->num%n+1;point!=this->num;point=point%n+1)
{//逆时针寻找
if(member[point].dead==THIS_PIG_IS_DEAD) continue;//如果死掉了,先过去
if(member[point].name!="FP"&&member[point].jumped==THIS_PIG_IS_JUMP)//找到第一头猪,如果它跳忠或是是主猪
{
return point;//杀他
}
else
{
return 0;//杀不到
}
}
}
return 0;
}

寻找'决斗'的目标

与'杀'类似,对于主猪、忠猪和反猪来说,他们寻找决斗目标的目的也不同,但考虑到决斗牌无距离限制,所以我们可以直接攻击游戏上存活的任何一头猪。

主猪杀的是逆时针下去的第一头跳反猪或类反猪,忠猪杀的是逆时针下去的第一头跳反猪,反猪直接杀主猪

int pig::find_F(void)
{//找一个人来决斗
if(this->name=="MP")
{//我是主猪
for(register int point=this->num%n+1;point!=this->num;point=point%n+1)
{//逆时针寻找
if(member[point].dead==THIS_PIG_IS_DEAD) continue;//如果死掉了,跳过去
if(member[point].like_bad==THIS_PIG_LIKE_BAD||(member[point].name=="FP"&&member[point].jumped==THIS_PIG_IS_JUMP))
{//如果这猪是类反猪或是已经跳反
return point;//就决斗他
}//否则继续找
}
}
else if(this->name=="ZP")
{//我是忠猪
for(register int point=this->num%n+1;point!=this->num;point=point%n+1)
{//逆时针寻找
if(member[point].dead==THIS_PIG_IS_DEAD) continue;//这玩意死了,跳过去
if(member[point].name=="FP"&&member[point].jumped==THIS_PIG_IS_JUMP)
{//如果这是已经跳反的猪头
return point;//就决斗他
}
}
}
else if(this->name=="FP")
{//我是反猪
return 1;//杀主猪
}
return 0;
}

攻击的反应函数

任何被使用杀、南猪入侵、万箭齐发的猪都会在背后运行这些函数。

杀的反应函数寻找手牌中是否有闪,南猪入侵的反应函数寻找手牌中是否有杀,万箭齐发的反应函数寻找手牌中是否有杀。

bool pig::K_respond(void)
{//杀的反应
myit it=this->find('D');//找一找有没有闪
if(it==this->cards.end()) return false;//没有闪,反应无效
this->del(it);//删掉闪
return true;//有效反应
}
bool pig::N_respond(void)
{//回应南猪入侵
myit it=this->find('K');//找一找杀
if(it==this->cards.end()) return false;//找不到
this->del(it);//删掉它
return true;
}
bool pig::W_respond(void)
{//回应万箭齐发
myit it=this->find('D');//找闪
if(it==this->cards.end()) return false;//没找到
this->del(it);//用掉它
return true;
}

接下来重点中的重点了

无懈可击

这里我们写两个递归函数,先看我们第一个函数,这个函数是被攻击性锦囊攻击的人调用的函数,形参表明谁伤害的自己,寻找逆时针(注意从自己开始,不是从自己后面的那一位开始,因为自己如果跳了也是会保护自己的)找到的第一头有无懈可击的同类,让它来帮你出无懈可击。

如果这头猪还没有跳是不可以寻求帮助的

bool pig::ask_J(int who)//找人给我挡牌,who对我发起攻击
{//询问无懈可击
bool check=true;
if(this->jumped==THIS_PIG_IS_NOT_JUMP) return false;//如果没有跳,那就不用
for(register int point=who;point!=who||check==true;point=point%n+1)
{//逆时针查询
if(member[point].dead==THIS_PIG_IS_DEAD) continue;//如果死掉了
check=false;
if(this->name!="FP"&&member[point].name=="FP") continue;//如果有敌意,不用
if(this->name=="FP"&&member[point].name!="FP") continue;//如果要打上,不用
myit it=member[point].find('J');//找找无懈可击
if(it!=member[point].cards.end())
{
member[point].del(it);//删掉这张牌
member[point].jump();//跳
return !member[point].back_J(this->num);//对抗一下
}
}
return false;
}

考虑到上方的献殷勤可能会被表敌意给无效掉,所以才有了下面这个函数。调用过上面的函数的猪都要让帮他出牌的那头猪继续做下面的工作

内容:找到逆时针的第一头有无懈可击的敌猪,让它对自己的无懈可击出无懈可击。

其实你测过几个例子就会发现,每当主猪受到伤害后,忠猪和反猪两阵营一定有一方一张无懈可击都没有了,这是为什么?

真的是Pig思维啊

bool pig::back_J(int to)
{//无懈可击的对抗
for(register int point=this->num%n+1;point!=this->num;point=point%n+1)
{//逆时针扫描
if(member[point].dead==THIS_PIG_IS_DEAD) continue;//已逝者先行
if(this->name!="FP"&&member[point].name=="ZP") continue;//如果同类,不打
if(this->name=="FP"&&member[point].name=="FP") continue;//如果同类,不打
if(this->name=="ZP"&&member[point].name!="FP") continue;//如果友好,不打
myit it=member[point].find('J');//找一张无懈可击
if(it!=member[point].cards.end())
{
member[point].del(it);//用它
member[point].jump();//同时自己得跳
return !member[to].ask_J(point);//再回击一下(很骚啊)
}
}
return false;
}

补一个构造函数

pig::pig(void)
{
this->hp=4;//生命值
this->dead=THIS_PIG_IS_NOT_DEAD;//没死
this->jumped=THIS_PIG_IS_NOT_JUMP;//有没有跳
this->crossbow=CROSSBOW_DOWN;//有没有装弩
this->like_bad=THIS_PIG_DO_NOT_LIKE_BAD;//是否类反
this->use_kill=THIS_TURN_DO_NOT_USE_KILL;//这回合没有使用过杀
}

再补一个回合函数

基于本人在最上面$class$里面写的独特的从$private$到$public$的顺序,加上本人的强迫症(必须按照声明的顺序实现函数),所以下方的函数都比较 *

这个回合函数很模拟,按照题意,摸两张牌,从左到右扫一遍手牌,对每张牌来个判断,能通过判断的牌用掉。

注意用掉一张牌后需要从头开始再扫一遍手牌,这是为什么?

如果手牌是KKKKZKK,那么你就会知道为什么要这么做了。

void pig::myturn(void)
{
this->cut();//拿牌x1
this->cut();//拿牌x2
bool check=true;//有牌拿
while(check)
{//只要不结束
check=false;//有没有用牌
for(myit it=this->cards.begin();it!=this->cards.end();it++)
{//在手牌中从左到右扫一遍
if(it->use==CANNOT_USE_THIS_CARD) continue;//如果不能用了
if(canuse(it->which)==false) continue;//判断一下现在能不能用
use(*it);//用它
if(this->dead==THIS_PIG_IS_DEAD) return;//如果这玩意死了
it=this->cards.begin()-1;//从头开始重新扫
check=true;//用过牌了
}
}
member[this->num].use_kill=THIS_TURN_DO_NOT_USE_KILL;//重置是否用过杀
return;
}

考虑到忠猪只会跳忠,反猪只会跳反,所以我们只要知道这头猪的身份以及他有没有跳就可以得知它是跳忠还是跳反,所以只需要对每头猪都开一个$bool$标识表示这头猪有没有跳。

void pig::jump(void)
{//跳
this->jumped=THIS_PIG_IS_JUMP;//开启标识
return ;
}

嗯,**接下来的一些操作也比较重要 ,反正没有无懈可击难就对了 **

考虑到杀必然会使出杀者跳。因为杀主猪的猪一定是反猪,杀忠猪的猪也是跳反猪,杀反猪的猪一定是忠猪或是主猪。所以只要你用了杀,你就跳了。

其次,跳了之后你就可以取消类反标识了(即使你跳反了,取消了标识依旧被打)。

然后,就没有什么花头了,杀的人在前面函数中已经选定,照着打就可以了。

void pig::K(int to)
{//杀
if(this->use_kill==THIS_TURN_USED_KILL&&this->crossbow==false) return;//如果这回合使用过杀而没有使用猪哥连弩
this->jump();//必然跳
this->like_bad=THIS_PIG_DO_NOT_LIKE_BAD;//取消类反(即使成为跳反猪)
this->use_kill=THIS_TURN_USED_KILL;//用过杀了
if(member[to].K_respond()==false)
{//如果对方没有对杀产生有效反应
member[to].hurt(this->num);//伤它一滴血
}
}

决斗

与杀相似,只要你用了决斗你就必然跳,注意如果忠猪被主猪使用无懈可击,它会直接扛上一点伤害,然后结束决斗

此外还需注意记录到底是谁出的最后一张杀,决定了谁受到另一方的伤害。

void pig::F(int to)
{//决斗
#ifdef DEBUG
printf("%d对%d使用了决斗\n",this->num,to);
#endif
this->jump();//先跳再说
this->like_bad=THIS_PIG_DO_NOT_LIKE_BAD;//类反猪取消
if(member[to].ask_J(this->num)==true) return;//询问无懈可击,如果使用,跳过
if(this->name=="MP"&&member[to].name=="ZP")
{//如果主猪对忠猪用
member[to].hurt(this->num);//忠猪受伤
return;
}
int who;//判定谁提供伤害
while(true)
{
myit t;
t=member[to].find('K');//找杀
if(t==member[to].cards.end())//没找到
{
who=2;//我对你产生伤害
break;
}
else member[to].del(t); //用掉这张牌
t=this->find('K');//从我这里找杀
if(t==this->cards.end())
{
who=1;//你对我产生伤害
break;
}
else this->del(t);//删掉这张牌
}
if(who==2)
{//你伤了我
member[to].hurt(this->num);//伤害函数
}
if(who==1)
{//我伤了你
this->hurt(to);//伤害函数
}
}

南猪入侵

然后就是南猪入侵了。从出牌者的下一位开始,逆时针旋转一周,对每个人进行无懈可击判定和南猪入侵回应判定。

void pig::N(void)
{//南猪入侵
#ifdef DEBUG
printf("%d使用了南猪入侵\n",this->num);
#endif
for(register int point=this->num%n+1;point!=this->num;point=point%n+1)
{//逆时针查询
if(member[point].dead==THIS_PIG_IS_DEAD) continue;//死掉了,跳过去
if(member[point].ask_J(this->num)==true) continue;//看看有没有无懈可击
if(member[point].N_respond()==false)
{//判断是否反应
member[point].hurt(this->num);//受到伤害
if(member[point].name=="MP"&&this->jumped==THIS_PIG_IS_NOT_JUMP)
{//如果主猪受到了攻击且该猪没有跳
this->like_bad=THIS_PIG_LIKE_BAD;//定义为类反猪
}
}
}
}

万箭齐发

跟南猪入侵大体相同,就是改了几个字。

void pig::W(void)
{//万箭齐发
#ifdef DEBUG
printf("%d使用了万箭齐发\n",this->num);
#endif
for(register int point=this->num%n+1;point!=this->num;point=point%n+1)
{//逆时针搜索
if(member[point].dead==THIS_PIG_IS_DEAD) continue;//如果死了,跳过
if(member[point].ask_J(this->num)==true) continue;//询问是否有无懈可击
if(member[point].W_respond()==false)//回应万箭齐发
{
member[point].hurt(this->num);//受到伤害
if(member[point].name=="MP"&&this->jumped==THIS_PIG_IS_NOT_JUMP)
{//主猪受到攻击,这头猪没有跳
this->like_bad=THIS_PIG_LIKE_BAD;//定义为类反猪
}
}
}
}

本题完整代码

#include <iostream>
#include <fstream>
#include <vector>
#include <cstdlib>
using std::cout;
using std::endl;
using std::cin;
using std::ios;
#define CANNOT_USE_THIS_CARD true
#define CAN_USE_THIS_CARD false
#define THIS_PIG_IS_DEAD true
#define THIS_PIG_IS_NOT_DEAD false
#define THIS_PIG_IS_JUMP true
#define THIS_PIG_IS_NOT_JUMP false
#define THIS_PIG_LIKE_BAD true
#define THIS_PIG_DO_NOT_LIKE_BAD false
#define CROSSBOW_ON true
#define CROSSBOW_DOWN false
#define THIS_TURN_USED_KILL true
#define THIS_TURN_DO_NOT_USE_KILL false
struct card
{
char which ;
bool use ;
};
typedef std::vector<card>::iterator myit;
class pig
{
private:
int hp ;
bool use_kill ;
bool crossbow ;
bool jumped ;
bool like_bad ;
void die (int) ;
void clear (void) ;
void del (myit&) ;
myit find (char) ;
void cut (void) ;
void use (card&) ;
void hurt (int) ;
bool canuse (char) ;
int find_K (void) ;
int find_F (void) ;
bool K_respond (void) ;
bool N_respond (void) ;
bool W_respond (void) ;
bool ask_J (int) ;
bool back_J (int) ;
public:
pig (void) ;
int num ;
bool dead ;
std::string name ;
std::vector<card> cards ;
void myturn (void) ;
void jump (void) ;
void K (int) ;
void F (int) ;
void N (void) ;
void W (void) ;
};
void gameover(std::string);
int n,m;
int FP;
card stack[2005];
pig member[15];
int top=1;
int main()
{
ios::sync_with_stdio(false);
cin>>n>>m;
for(register int i=1;i<=n;i++)
{
cin>>member[i].name;
member[i].num=i;
if(member[i].name=="FP") FP++;
for(register int j=1;j<=4;j++)
{
card c;
cin>>c.which;
c.use=CAN_USE_THIS_CARD;
member[i].cards.push_back(c);
}
}
for(top=1;top<=m;top++)
{
card c;
cin>>c.which;
c.use=CAN_USE_THIS_CARD;
stack[top]=c;
}
top=1;
int point=0;
member[1].jump();
while(true)
{
point=point%n+1;
if(member[point].dead==THIS_PIG_IS_DEAD) continue;
member[point].myturn();
}
}
void gameover(std::string who)
{
cout<<who<<std::endl;
for(register int i=1;i<=n;i++)
{
if(member[i].dead==THIS_PIG_IS_DEAD) cout<<"DEAD";
else for(myit it=member[i].cards.begin();it!=member[i].cards.end();it++)
{
if(it->use==CANNOT_USE_THIS_CARD) continue;
cout<<it->which<<' ';
}
cout<<std::endl;
}
exit(0);
}
void pig::die(int who)
{
this->dead=THIS_PIG_IS_DEAD;
if(this->name=="MP")
gameover("FP");
if(this->name=="FP") FP--;
if(FP==0) gameover("MP");
if(this->name=="FP")
{
member[who].cut();
member[who].cut();
member[who].cut();
}
if(this->name=="ZP"&&member[who].name=="MP")
member[who].clear();
return;
}
void pig::clear(void)
{
this->cards.clear();
this->crossbow=CROSSBOW_DOWN;
return;
}
void pig::del(myit& it)
{
it->use=CANNOT_USE_THIS_CARD;
return;
}
myit pig::find(char which)
{
for(myit it=this->cards.begin();it!=this->cards.end();it++)
{
if(it->use==CANNOT_USE_THIS_CARD) continue;
if(it->which==which) return it;
}
return this->cards.end();
}
void pig::cut(void)
{
this->cards.push_back(stack[top++]);
if(top>m) top=m;
return;
}
void pig::use(card& c)
{
if(c.which=='K')
{
int who;
who=this->find_K();
if(who!=0)
{
c.use=CANNOT_USE_THIS_CARD;
this->K(who);
}
}
else if(c.which=='P')
{
if(this->hp<4)
{
c.use=CANNOT_USE_THIS_CARD;
this->hp++;
}
}
else if(c.which=='F')
{
int who;
who=this->find_F();
if(who!=0)
{
c.use=CANNOT_USE_THIS_CARD;
this->F(who);
}
}
else if(c.which=='N')
{
c.use=CANNOT_USE_THIS_CARD;
this->N();
}
else if(c.which=='W')
{
c.use=CANNOT_USE_THIS_CARD;
this->W();
}
else if(c.which=='Z')
{
c.use=CANNOT_USE_THIS_CARD;
this->crossbow=CROSSBOW_ON;
}
return;
}
void pig::hurt(int who)
{
this->hp--;
if(this->hp==0)
{
myit t=this->find('P');
if(t==this->cards.end()) this->die(who);
else
{
this->del(t);
this->hp++;
}
}
return;
}
bool pig::canuse(char c)
{
if(c=='P'&&this->hp<4) return true;
if((c=='K'&&this->find_K()!=0)||(c=='F'&&this->find_F()!=0)||c=='N'||c=='W'||c=='Z') return true;//濡傛灉鍙互鐢?
return false;
}
int pig::find_K(void)
{
if(this->use_kill==THIS_TURN_USED_KILL&&this->crossbow==CROSSBOW_DOWN) return 0;//濡傛灉杩欏洖鍚堝凡缁忕敤杩囦簡鏉€鑰屾病鏈夎杩囩尓鍝ヨ繛寮?
if(this->name=="MP")
for(register int point=this->num%n+1;point!=this->num;point=point%n+1)
{
if(member[point].dead==THIS_PIG_IS_DEAD) continue;
if(member[point].like_bad==THIS_PIG_LIKE_BAD||(member[point].name=="FP"&&member[point].jumped==THIS_PIG_IS_JUMP))
return point;
else return 0;
}
else if(this->name=="ZP")
for(register int point=this->num%n+1;point!=this->num;point=point%n+1)
{
if(member[point].dead==THIS_PIG_IS_DEAD) continue;
if(member[point].name=="FP"&&member[point].jumped==THIS_PIG_IS_JUMP)
return point;
else return 0;
}
else if(this->name=="FP")
for(register int point=this->num%n+1;point!=this->num;point=point%n+1)
{
if(member[point].dead==THIS_PIG_IS_DEAD) continue;
if(member[point].name!="FP"&&member[point].jumped==THIS_PIG_IS_JUMP)
return point;
else return 0;
}
return 0;
}
int pig::find_F(void)
{
if(this->name=="MP")
for(register int point=this->num%n+1;point!=this->num;point=point%n+1)
{
if(member[point].dead==THIS_PIG_IS_DEAD) continue;
if(member[point].like_bad==THIS_PIG_LIKE_BAD||(member[point].name=="FP"&&member[point].jumped==THIS_PIG_IS_JUMP))
return point;
}
else if(this->name=="ZP")
for(register int point=this->num%n+1;point!=this->num;point=point%n+1)
{
if(member[point].dead==THIS_PIG_IS_DEAD) continue;
if(member[point].name=="FP"&&member[point].jumped==THIS_PIG_IS_JUMP)
return point;
}
else if(this->name=="FP") return 1;
return 0;
}
bool pig::K_respond(void)
{
myit it=this->find('D');
if(it==this->cards.end()) return false;
this->del(it);
return true;
}
bool pig::N_respond(void)
{
myit it=this->find('K');
if(it==this->cards.end()) return false;
this->del(it);
return true;
}
bool pig::W_respond(void)
{
myit it=this->find('D');
if(it==this->cards.end()) return false;
this->del(it);
return true;
}
bool pig::ask_J(int who)
{
bool check=true;
if(this->jumped==THIS_PIG_IS_NOT_JUMP) return false;
for(register int point=who;point!=who||check==true;point=point%n+1)
{
if(member[point].dead==THIS_PIG_IS_DEAD) continue;
check=false;
if(this->name!="FP"&&member[point].name=="FP") continue;
if(this->name=="FP"&&member[point].name!="FP") continue;
myit it=member[point].find('J');
if(it!=member[point].cards.end())
{
member[point].del(it);
member[point].jump();
return !member[point].back_J(this->num);
}
}
return false;
}
bool pig::back_J(int to)
{
for(register int point=this->num%n+1;point!=this->num;point=point%n+1)
{
if(member[point].dead==THIS_PIG_IS_DEAD) continue;
if(this->name!="FP"&&member[point].name=="ZP") continue;
if(this->name=="FP"&&member[point].name=="FP") continue;
if(this->name=="ZP"&&member[point].name!="FP") continue;
myit it=member[point].find('J');
if(it!=member[point].cards.end())
{
member[point].del(it);
member[point].jump();
return !member[to].ask_J(point);
}
}
return false;
}
pig::pig(void)
{
this->hp=4;
this->dead=THIS_PIG_IS_NOT_DEAD;
this->jumped=THIS_PIG_IS_NOT_JUMP;
this->crossbow=CROSSBOW_DOWN;
this->like_bad=THIS_PIG_DO_NOT_LIKE_BAD;
this->use_kill=THIS_TURN_DO_NOT_USE_KILL;
return;
}
void pig::myturn(void)
{
this->cut();
this->cut();
bool check=true;
while(check)
{
check=false;
for(myit it=this->cards.begin();it!=this->cards.end();it++)
{
if(it->use==CANNOT_USE_THIS_CARD) continue;
if(canuse(it->which)==false) continue;
use(*it);
if(this->dead==THIS_PIG_IS_DEAD) return;
it=this->cards.begin()-1;
check=true;
}
}
member[this->num].use_kill=THIS_TURN_DO_NOT_USE_KILL;
return;
}
void pig::jump(void)
{
this->jumped=THIS_PIG_IS_JUMP;
return;
}
void pig::K(int to)
{
if(this->use_kill==THIS_TURN_USED_KILL&&this->crossbow==false) return;
this->jump();
this->like_bad=THIS_PIG_DO_NOT_LIKE_BAD;
this->use_kill=THIS_TURN_USED_KILL;
if(member[to].K_respond()==false)
member[to].hurt(this->num);
return;
}
void pig::F(int to)
{
this->jump();
this->like_bad=THIS_PIG_DO_NOT_LIKE_BAD;
if(member[to].ask_J(this->num)==true) return;
if(this->name=="MP"&&member[to].name=="ZP")
{
member[to].hurt(this->num);
return;
}
int who;
while(true)
{
myit t;
t=member[to].find('K');
if(t==member[to].cards.end())
{
who=2;
break;
}
else member[to].del(t);
t=this->find('K');
if(t==this->cards.end())
{
who=1;
break;
}
else this->del(t);
}
if(who==2)
member[to].hurt(this->num);
if(who==1)
this->hurt(to);
return;
}
void pig::N(void)
{
for(register int point=this->num%n+1;point!=this->num;point=point%n+1)
{
if(member[point].dead==THIS_PIG_IS_DEAD) continue;
if(member[point].ask_J(this->num)==true) continue;
if(member[point].N_respond()==false)
{
member[point].hurt(this->num);
if(member[point].name=="MP"&&this->jumped==THIS_PIG_IS_NOT_JUMP)
{
this->like_bad=THIS_PIG_LIKE_BAD;
}
}
}
return;
}
void pig::W(void)
{
for(register int point=this->num%n+1;point!=this->num;point=point%n+1)
{
if(member[point].dead==THIS_PIG_IS_DEAD) continue;
if(member[point].ask_J(this->num)==true) continue;
if(member[point].W_respond()==false)
{
member[point].hurt(this->num);
if(member[point].name=="MP"&&this->jumped==THIS_PIG_IS_NOT_JUMP)
this->like_bad=THIS_PIG_LIKE_BAD;
}
}
return;
}
view raw LG2482.cpp hosted with ❤ by GitHub


我缓慢吐出一串啊吧啊吧并不再想说话