P2482 [SDOI2010]猪国杀

花了6天时间切完了猪国杀,第2天基本写完了代码,跑了30分,后面4天一直在找bug。客观来讲,这道题的难度不是很大,但是在大模拟里面应该是很经典了:代码量巨多、内容巨复杂、坑巨多。题目传送门

首先花点时间把题目读懂,理一理思路,先定义数据结构,然后按照题目的意思一个一个写函数,最后就是输入数据,模拟游戏过程。
解题思路不难想,读懂题目就可以,具体方法都在代码里注释了。提醒一下这道题的几个坑点:
1.题目那句“数据保证牌的数量够用”真是坑死人了,前两个测试数据牌堆都是2000张,但是结束不了游戏,牌堆的牌摸完了以后,要反复摸最后一张牌。
2.无懈可击对锦囊的响应,可以根据锦囊的使用者和锦囊的目标设计不同的方法,但是最好是锦囊的使用者(群技能时应该是当前目标),因为锦囊的使用者(决斗或者无懈可击,是一定已经跳明身份的)。
3.楼主在写代码的时候有一个bug就是玩家死了以后继续使用手牌,所以玩家死了以后要把手牌数清零。
4.经过测试,释放群锦囊时,不论技能的目标轮到了谁,询问无懈可击时,都是从锦囊的使用者开始的。
5.我是在达成游戏结束条件时,立即保存游戏数据,所以如果在同一个玩家的回合中,主公和反贼同时胜利了,正确的做法应该是保存先胜利的数据,但是代码中后胜利的会覆盖前面的数据,所以在保存游戏数据时,必须判断一下游戏是否结束。
6.锦囊牌无论是否被无懈可击,都要丢弃,也就是要把丢弃锦囊牌的代码放前面,避免影响后续。
7.要考虑到装备武器后可以使用前面的杀,使用锦囊之后如果有人亮明身份,可能可以使用前面的决斗,即在装备武器和使用锦囊之后手牌牌序要重置。

下面是完整代码:

#include <bits/stdc++.h>
#define NMAX 11
#define MMAX 2010
using namespace std;
class Pig;
char card[MMAX];//牌堆数组
int card_index=0;//牌序
class End//游戏结束类
{
private:
    string result;//游戏结果
    int player_index;//玩家数
    char hand[NMAX][9999];//游戏结束时保存玩家手牌
    int hand_index[NMAX];//游戏结束时玩家手牌数
    bool suvive[NMAX];//游戏结束时玩家是否存活
    int Fnums;//反贼存活数量,用来判断主公胜利的条件
    Pig* player[NMAX];//玩家
    bool en;//游戏结束标记
    void reserve();//保存游戏结果
public:
    End(int Fnums,int playernums,Pig** a);
    void GetDead(int role);//获取死亡玩家的信息,判断游戏是否结束
    void Output();//结果输出
    bool IsEnd(){return en;}
};

class Pig//玩家类
{
private:
    char hand[9999];//手牌
    bool equipment;
    int blood;
    int role;//0:主公;1:忠诚;2:反贼
    bool exposed;//是否跳出
    bool suvived;//是否存活
    int hand_index;//手牌数
    int enemy_index;//敌人数
    int friends_index;//朋友数
    int enemy[NMAX];//敌人
    int friends[NMAX];//朋友
    Pig* player[NMAX];//玩家
    int player_index;//玩家数
    int id;//玩家序号
    bool IsEnemy(int n);//判断是否敌人
    bool IsFriends(int n);//判断是否朋友
    void SubBlood(int source);//掉血
public:
    End* en;//结束类对象
    Pig(string name,char card1,char card2,char card3,char card4,int num);
    void GetPlayer(int,Pig**);//初始化其他玩家
    void AddHand(int);//添加手牌
    void GetExpose(int num,int);//获取别人的跳出信息
    bool IsSuvived(){return suvived;}
    void GetDead(int num);//获取别的人死亡信息
    void Play();//出牌阶段
    void GetFucked(int source);//被杀
    int GetHand_index(){return hand_index;}
    char* GetHand(){return hand;}
    void AddEnd(End* aaa){en=aaa;}
    void Punish()//主公杀死忠臣掉牌
    {
        hand_index=0;
        equipment=false;
    }
    int GetRole(){return role;}
    bool Offer(int id,int type);//type=0:消极事件;type=1:积极事件
    void GetDuel(int source);//被决斗
    void GetAOE1(int source);//南蛮入侵
    void GetAOE2(int source);//万箭齐发
};
void Pig::GetAOE1(int source)//南蛮入侵
{
    bool flag=false;
    for(int i=0;i<hand_index;i++)//是否有杀
    {
        if(hand[i]=='K')
        {
            flag=true;
            for(int j=i;j<hand_index-1;j++)
                hand[j]=hand[j+1];
            hand_index--;
            break;
        }
    }
    if(!flag)
    {
        //如果是主公,在杀害来源没有跳的情况下,主猪会把伤害来源当作类反猪,加入敌人数组
        if(role==0&&(!IsFriends(source)&&!IsEnemy(source)))
        {
            enemy[enemy_index]=source;
            enemy_index++;
        }
        SubBlood(source);
    }
}

void Pig::GetAOE2(int source)//万箭齐发
{
    bool flag=false;
    for(int i=0;i<hand_index;i++)//是否有闪
    {
        if(hand[i]=='D')
        {
            flag=true;
            for(int j=i;j<hand_index-1;j++)
                hand[j]=hand[j+1];
            hand_index--;
            break;
        }
    }
    if(!flag)
    {
        //如果是主公,在杀害来源没有跳的情况下,主猪会把伤害来源当作类反猪,加入敌人数组
        if(role==0&&!IsFriends(source)&&!IsEnemy(source))
        {
            enemy[enemy_index]=source;
            enemy_index++;
        }
        SubBlood(source);
    }
}
void Pig::GetDuel(int source)//被决斗
{
    if(role==1&&source==0) SubBlood(source);//如果是忠臣并且决斗对象是主公,不出杀
    else
    {
        bool flag=false;
        for(int i=0;i<hand_index;i++)//响应杀
        {
            if(hand[i]=='K')
            {
                flag=true;
                for(int j=i;j<hand_index-1;j++)
                    hand[j]=hand[j+1];
                hand_index--;
                break;
            }
        }
        if(flag)//如果有杀的话,决斗对象需要继续出杀,相当于使用一张决斗(不需要询问无懈可击的决斗)
        {
            player[source]->GetDuel(id);
        }
        else SubBlood(source);
    }
}
void End::reserve()//保存游戏结束时的状态
{
    for(int i=0;i<player_index;i++)
    {
        suvive[i]=player[i]->IsSuvived();
        hand_index[i]=player[i]->GetHand_index();
        char* h=player[i]->GetHand();
        for(int j=0;j<hand_index[i];j++)
            hand[i][j]=h[j];
    }
}
bool Pig::Offer(int id,int type)//响应无懈可击,id:响应的对象,type:事件类型,1代表积极,0代表消极
{
    bool flag=false;
    if(IsFriends(id)&&type==0)//如果是朋友并且这是一件消极事件
    {
        for(int i=0;i<hand_index;i++)//寻找无懈可击
        {
            if(hand[i]=='J')
            {
                flag=true;
                for(int j=i;j<hand_index-1;j++)
                    hand[j]=hand[j+1];
                hand_index--;
                if(!exposed)//判断是否跳明身份,因为使用无懈可击将导致身份跳明
                {
                    exposed=true;
                    for(int j=0;j<player_index;j++)
                    {
                        if(player[j]->IsSuvived())
                        {
                            player[j]->GetExpose(role,this->id);
                        }
                    }
                }
                for(int j=this->id+1;j<this->id+player_index;j++)//询问是否响应无懈可击
                {
                    if(player[j%player_index]->IsSuvived()&&player[j%player_index]->Offer(id,1))
                    {
                        flag=false;
                        break;
                    }
                }
                break;
            }
        }
    }
    else if(IsEnemy(id)&&type==1)//如果是敌人并且这是一件积极事件
    {
        for(int i=0;i<hand_index;i++)
        {
            if(hand[i]=='J')
            {
                flag=true;
                for(int j=i;j<hand_index-1;j++)
                    hand[j]=hand[j+1];
                hand_index--;
                if(!exposed)
                {
                    exposed=true;
                    for(int j=0;j<player_index;j++)
                    {
                        if(player[j]->IsSuvived())
                        {
                            player[j]->GetExpose(role,this->id);
                        }
                    }
                }
                for(int j=this->id+1;j<this->id+player_index;j++)
                {
                    if(player[j%player_index]->IsSuvived()&&player[j%player_index]->Offer(id,0))
                    {
                        flag=false;
                        break;
                    }
                }
                break;
            }
        }
    }
    return flag;
}
End::End(int Fnums,int playernums,Pig** a)
{
    this->Fnums=Fnums;
    player_index=playernums;
    for(int i=0;i<playernums;i++)
        player[i]=a[i];
    en=false;
}
void End::GetDead(int role)
{
    if(IsEnd()) return;
    if(role==0)
    {
        en=true;
        result="FP";
        reserve();
    }
    else if(role==2)
    {
        Fnums--;
        if(Fnums==0)
        {
            en=true;
            result="MP";
            reserve();
        }
    }
}
void End::Output()
{
    cout<<result<<endl;
    for(int i=0;i<player_index;i++)
    {
        if(suvive[i])
        {
            for(int j=0;j<hand_index[i]-1;j++)
            {
                cout<<hand[i][j]<<" ";
            }
            if(hand_index[i]!=0) cout<<hand[i][hand_index[i]-1];
            cout<<endl;
        }
        else cout<<"DEAD"<<endl;
    }
}
Pig::Pig(string name,char card1,char card2,char card3,char card4,int num)
{
    hand[0]=card1;
    hand[1]=card2;
    hand[2]=card3;
    hand[3]=card4;
    id=num;
    player_index=0;
    equipment=false;
    blood=4;
    suvived=true;
    hand_index=4;
    friends_index=0;
    enemy_index=0;
    if(name=="MP")
    {
        role=0;
        exposed=true;
    }
    else if(name=="ZP")
    {
        role=1;
        exposed=false;
    }
    else
    {
        role=2;
        exposed=false;
    }
}
void Pig::GetPlayer(int num,Pig** a)
{
    player_index=num;
    for(int i=0;i<num;i++)
    {
        player[i]=a[i];
    }
}
void Pig::AddHand(int num)//添加手牌
{
    if(card_index>=1999)
    {
        if(num==2)
        {
            hand[hand_index]=card[1999];
            hand[hand_index+1]=card[1999];
            hand_index+=2;
        }
        else if(num==3)
        {
            hand[hand_index]=card[1999];
            hand[hand_index+1]=card[1999];
            hand[hand_index+2]=card[1999];
            hand_index+=3;
        }
        return;
    }
    else if(card_index==1998)
    {
        if(num==3)
        {
            hand[hand_index]=card[1998];
            hand[hand_index+1]=card[1999];
            hand[hand_index+2]=card[1999];
            hand_index+=3;
            card_index+=3;
            return;
        }
    }
    for(int i=hand_index,j=card_index;i<hand_index+num;i++,j++)
        hand[i]=card[j];
    hand_index+=num;
    card_index+=num;
}
void Pig::GetExpose(int num,int id)//收到其他玩家的身份信息,num:玩家身份,id:玩家序号
{
    if(role==0&&IsEnemy(id))//如果该玩家是忠臣但是被主公当作了类反猪,那么需要从敌人数组删除而加入朋友数组
    {
        if(num==1)
        {
            for(int i=0;i<enemy_index;i++)
            {
                if(enemy[i]==id)
                {
                    for(int j=i;j<enemy_index-1;j++)
                        enemy[j]=enemy[j+1];
                    enemy_index--;
                    break;
                }
            }
            friends[friends_index]=id;
            friends_index++;
        }
        return;
    }
    if(num==0||num==1)
    {
        if(role==1||role==0)
        {
            friends[friends_index]=id;
            friends_index++;
        }
        else
        {
            enemy[enemy_index]=id;
            enemy_index++;
        }
    }
    else
    {
        if(role==0||role==1)
        {
            enemy[enemy_index]=id;
            enemy_index++;
        }
        else
        {
            friends[friends_index]=id;
            friends_index++;
        }
    }
}
bool Pig::IsEnemy(int n)
{
    for(int i=0;i<enemy_index;i++)
    {
        if(enemy[i]==n) return true;
    }
    return false;
}
bool Pig::IsFriends(int n)
{
    for(int i=0;i<friends_index;i++)
    {
        if(friends[i]==n) return true;
    }
    return false;
}
void Pig::GetDead(int num)//有玩家死亡时,需要将其从敌人/朋友队列中删除
{
    if(IsFriends(num))
    {
        for(int i=0;i<friends_index;i++)
        {
            if(friends[i]==num)
            {
                for(int j=i;j<friends_index-1;j++)
                    friends[j]=friends[j+1];
                friends_index--;
                break;
            }
        }
    }
    else if(IsEnemy(num))
    {
        for(int i=0;i<enemy_index;i++)
        {
            if(enemy[i]==num)
            {
                for(int j=i;j<enemy_index-1;j++)
                    enemy[j]=enemy[j+1];
                enemy_index--;
                break;
            }
        }
    }
}
void Pig::Play()//出牌阶段
{
    int fuck_num=0;//记录出杀的次数
    for(int i=0;i<hand_index;)
    {
        if(hand[i]=='P')
        {
            if(blood<4)
            {
                blood++;
                for(int j=i;j<hand_index-1;j++)
                    hand[j]=hand[j+1];
                hand_index--;
            }
            else i++;
            continue;
        }
        else if(hand[i]=='K')
        {
            if(fuck_num==1&&!equipment)
            {
                i++;
                continue;
            }
            else
            {
                int target;
                for(int j=id+1;j<id+player_index;j++)
                {
                    if(player[j%player_index]->IsSuvived())
                    {
                        target=j%player_index;
                        break;
                    }
                }
                if(IsEnemy(target))
                {
                    for(int j=i;j<hand_index-1;j++)
                        hand[j]=hand[j+1];
                    hand_index--;
                    fuck_num++;
                    player[target]->GetFucked(this->id);
                    if(!exposed)//杀会导致亮明身份
                    {
                        exposed=true;
                        for(int j=0;j<player_index;j++)
                        {
                            if(player[j]->IsSuvived()) player[j]->GetExpose(this->role,this->id);
                        }
                    }
                }
                else i++;
                continue;
            }
        }
        else if(hand[i]=='F')
        {
            int target=-1;
            if(role==2) target=0;
            else
            {
                for(int j=this->id+1;j<this->id+player_index;j++)
                {
                    if(player[j%player_index]->IsSuvived()&&IsEnemy(j%player_index))
                    {
                        target=j%player_index;
                        break;
                    }
                }
            }
            if(target==-1)
            {
                i++;
                continue;
            }
            for(int j=i;j<hand_index-1;j++)
                hand[j]=hand[j+1];
            hand_index--;
            if(!exposed)//决斗会导致亮明身份
            {
                exposed=true;
                for(int j=0;j<player_index;j++)
                {
                    if(player[j]->IsSuvived()) player[j]->GetExpose(this->role,this->id);
                }
            }
            bool flag=false;
            for(int j=this->id+1;j<this->id+player_index;j++)//询问无懈可击
            {
                if(player[j%player_index]->IsSuvived()&&player[j%player_index]->Offer(target,0))
                {
                    flag=true;
                    break;
                }
            }
            if(!flag)
            {
                player[target]->GetDuel(this->id);
            }
            i=0;
            continue;
        }
        else if(hand[i]=='N')
        {
            for(int j=i;j<hand_index-1;j++)
                hand[j]=hand[j+1];
            hand_index--;
            for(int j=this->id+1;j<player_index+this->id;j++)
            {
                if(player[j%player_index]->IsSuvived())
                {
                    bool flag=false;
                    for(int k=this->id;k<this->id+player_index;k++)//询问无懈可击
                    {
                        if(player[k%player_index]->IsSuvived()&&player[k%player_index]->Offer(j%player_index,0))
                        {
                            flag=true;
                            break;
                        }
                    }
                    if(!flag)
                    {
                        player[j%player_index]->GetAOE1(this->id);
                    }
                }
            }
            i=0;
            continue;
        }
        else if(hand[i]=='W')
        {
            for(int j=i;j<hand_index-1;j++)
                hand[j]=hand[j+1];
            hand_index--;
            for(int j=this->id+1;j<this->id+player_index;j++)
            {
                if(player[j%player_index]->IsSuvived())
                {
                    bool flag=false;
                    for(int k=this->id;k<this->id+player_index;k++)
                    {
                        if(player[k%player_index]->IsSuvived()&&player[k%player_index]->Offer(j%player_index,0))
                        {
                            flag=true;
                            break;
                        }
                    }
                    if(!flag)
                    {
                        player[j%player_index]->GetAOE2(this->id);
                    }
                }
            }
            i=0;
            continue;
        }
        else if(hand[i]=='Z')
        {
            for(int j=i;j<hand_index-1;j++)
                hand[j]=hand[j+1];
            hand_index--;
            equipment=true;
            i=0;
            continue;
        }
        else
        {
            i++;
            continue;
        }
    }
}
void Pig::GetFucked(int source)
{
    bool flag=false;
    for(int i=0;i<hand_index;i++)
    {
        if(hand[i]=='D')
        {
            flag=true;
            for(int j=i;j<hand_index-1;j++)
                hand[j]=hand[j+1];
            hand_index--;
            break;
        }
    }
    if(!flag)
    {
        SubBlood(source);
    }
}
void Pig::SubBlood(int source)
{
    blood--;
    if(blood==0)
    {
        bool flag=false;
        for(int i=0;i<hand_index;i++)
        {
            if(hand[i]=='P')
            {
                flag=true;
                for(int j=i;j<hand_index-1;j++)
                    hand[j]=hand[j+1];
                hand_index--;
                blood++;
                break;
            }
        }
        if(!flag)
        {
            suvived=false;
            hand_index=0;//手牌数清零
            for(int i=0;i<player_index;i++)//向其他玩家宣告死亡
            {
                if(player[i]->IsSuvived()) player[i]->GetDead(this->id);
            }
            en->GetDead(this->role);//向游戏结束类传递死亡信息
            if(this->role==2)
            {
                player[source]->AddHand(3);
            }
            if(this->role==1&&player[source]->GetRole()==0)
            {
                player[source]->Punish();
            }
        }
    }
}
int main()
{
    int N,M;
    cin>>N>>M;
    Pig* pig[NMAX];
    int Fnums=0;
    for(int i=0;i<N;i++)
    {
        string role;
        cin>>role;
        if(role=="FP") Fnums++;
        char card1,card2,card3,card4;
        cin>>card1>>card2>>card3>>card4;
        pig[i]=new Pig(role,card1,card2,card3,card4,i);
    }
    for(int i=0;i<M;i++)
    {
        cin>>card[i];
    }
    for(int i=0;i<N;i++)
    {
        pig[i]->GetPlayer(N,pig);
        pig[i]->GetExpose(0,0);
    }
    End en(Fnums,N,pig);
    for(int i=0;i<N;i++)
    {
        pig[i]->AddEnd(&en);
    }
    while(!en.IsEnd())
    {
        for(int i=0;i<N;i++)
        {
            if(pig[i]->IsSuvived())
            {
                pig[i]->AddHand(2);
                pig[i]->Play();
            }
        }
    }
    en.Output();
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值