【模擬】【bzoj1972】【SDOI2010】豬國殺

1972:[SDOI2010]豬國殺

【題目描述】

《豬國殺》是一種多豬牌類回合制遊戲,一共有三種角色:主豬,忠豬,反豬。每局遊戲主豬有且只有一隻,忠豬和反豬可以有多隻,每隻豬扮演一種角色。

遊戲目的:

主豬(MP):自己存活的情況下消滅所有的反豬。

忠豬(ZP):不惜一切保護主豬,勝利條件與主豬相同。

反豬(AP):殺死主豬。

遊戲過程:

遊戲開始時候,每個玩家手裏都會有4張牌,且體力上限和初始體力都是4。

開始遊戲時,從主豬開始,按照逆時針方向(數據中就是按照編號從1,2,3..n,1..的順序)依次行動。

每個玩家自己的回合可以分爲4個階段:

◎摸牌階段:從牌堆頂部摸兩張牌,依次放到手牌的最右邊;

◎出牌階段:你可以使用0張到任意張牌,每次使用牌的時候都使用最靠左的能夠使用的牌。當然,要滿足如下規則:

1.如果沒有豬哥連弩,每個出牌階段只能使用一次“殺”來攻擊;

2.任何牌被使用後被棄置(武器是裝備上);

被棄置的牌以後都不能再用,即與遊戲無關;

各種牌介紹:

每張手牌用一個字母表示,字母代表牌的種類。

◎基本牌:

『桃(P)』:在自己的回合內,如果自己的體力值不等於體力上限,那麼使用一個桃可以爲自己補充一點體力,否則不能使用桃;桃只能對自己使用;在自己的回合外,如果自己的血變爲0或者更低,那麼也可以使用;

『殺(K)』:在自己的回合內,對攻擊範圍內除自己以外的一名角色使用。如果沒有被『閃』抵消,則造成1點傷害。無論有無武器,殺的攻擊範圍都是1;

『閃(D)』:當你受到殺的攻擊時,可以棄置一張閃來抵消殺的效果;

◎錦囊牌:

『決鬥(F)』:出牌階段,對除自己以外任意一名角色使用,由目標角色先開始,自己和目標角色輪流棄置一張殺,首先沒有殺可棄的一方受到1點傷害,另一方視爲此傷害的來源;

『南豬入侵(N)』:出牌階段,對除你以外所有角色使用,按逆時針順序從使用者下家開始依次結算,除非棄置一張殺,否則受到1點傷害;

『萬箭齊發(W)』:和南豬入侵類似,不過要棄置的不是殺而是閃;

『無懈可擊(J)』:在目標錦囊生效前抵消其效果。每次有一張錦囊即將生效時,從使用這張錦囊的豬開始,按照逆時針順序,依次得到使用無懈可擊的機會;

效果:用於決鬥時,決鬥無效並棄置;用於南豬入侵或萬箭齊發時,當結算到某個角色時才能使用,當前角色不需棄置牌並且不會受到傷害(僅對一個角色產生效果);用於無懈可擊時,成爲目標的無懈可擊被無效。

◎裝備牌:

『豬哥連弩(Z)』:武器,攻擊範圍1,出牌階段你可以使用任意張殺;

同一時刻最多隻能裝一個武器;如果先前已經有了一把武器,那麼之後再裝武器的話,會棄置以前的武器來裝現在的武器;

特殊事件及概念解釋:

◎傷害來源:殺、南豬入侵、萬箭齊發的傷害來源均是使用該牌的豬,決鬥的傷害來源如上;

◎距離:兩隻豬的距離定義爲沿着逆時針方向間隔的豬數+1。即初始時1和2的距離爲1,但是2和1的距離就是n-1。注意一個角色的死亡會導致一些豬距離的改變;

◎玩家死亡:如果該玩家的體力降到0或者更低,並且自己手中沒有足夠的桃使得自己的體力值回到1,那麼就死亡了,死亡後所有的牌(裝備區,手牌區)被棄置;

◎獎勵與懲罰:反豬死亡時,最後一個傷害來源處(即使是反豬)立即摸三張牌。忠豬死亡時,如果最後一個傷害來源是主豬,那麼主豬所有裝備牌、手牌被棄置;

◎注意,一旦達成勝利條件,遊戲立刻結束,因此即使會摸3張牌或者還有牌可以用也不用執行了。

現在,我們已經知道每隻豬的角色、手牌,還有牌堆初始情況,並且假設每個角色會按照如下的行爲準則進行遊戲,你需要做的就是告訴小豬iPig最後的結果。

幾種行爲:

◎獻殷勤:使用無懈可擊擋下南豬入侵、萬箭齊發、決鬥;使用無懈可擊抵消表敵意;

◎表敵意:對某個角色使用殺、決鬥;使用無懈可擊抵消獻殷勤;

◎跳忠:即通過行動表示自己是忠豬。跳忠行動就是對主豬或對某隻已經跳忠的豬獻殷勤,或者對某隻已經跳反的豬表敵意;

◎跳反:即通過行動表示自己是反豬。跳反行動就是對主豬或對某隻已經跳忠的豬表敵意,或者對某隻已經跳反的豬獻殷勤;

忠豬不會跳反,反豬也不會跳忠;不管是忠豬還是反豬,能夠跳必然跳;

行動準則:

共性:每個角色如果手裏有桃且生命值未滿,那麼必然吃掉;有南豬入侵、萬箭齊發、必然使用;有裝備必然裝上;受到殺時,有閃必然棄置;響應南豬入侵或者萬箭齊發時候,有殺/閃必然棄置;不會對未表明身份的豬獻殷勤(包括自己);

特性:

◎主豬:主豬會認爲沒有跳身份,且用南豬入侵/萬箭齊發對自己造成傷害的豬是“類反豬”(沒傷害到不算,注意“類反豬”並沒有表明身份),如果之後跳了,那麼主豬會重新認識這隻豬;對於每種表敵意的方式,對逆時針方向能夠執行到的第一隻“類反豬”或者已跳反豬表;如果沒有,那麼就不表敵意;決鬥時會不遺餘力棄置殺;如果能對已經跳忠的豬或自己獻殷勤,那麼一定獻;如果能夠對已經跳反的豬表敵意,那麼一定表;

◎忠豬:對於每種表敵意的方式,對逆時針方向能夠執行到的第一隻已經跳反的豬表,如果沒有,那麼就不表敵意;決鬥時,如果對方是主豬,那麼不會棄置殺,否則,會不遺餘力棄置殺;如果有機會對主豬或者已經跳忠的豬獻殷勤,那麼一定獻;

◎反豬:對於每種表敵意的方式,如果有機會則對主豬表,否則,對逆時針方向能夠執行到的第一隻已經跳忠的豬表,如果沒有,那麼就不表敵意;決鬥時會不遺餘力棄置殺;如果有機會對已經跳反的豬獻殷勤,那麼一定獻;

限於iPig只會用P++語言寫A + B,他請你用Pigcal(Pascal)、P(C)或P++(C++)語言來幫他預測最後的結果。

【輸入】

輸入文件第一行包含兩個正整數n(2 <= n <= 10) 和m( m <= 2000),分別代表玩家數和牌堆中牌的數量。數據保證牌的數量夠用。

接下來n行,每行5個字符串,依次表示對第i只豬的角色和初始4張手牌描述。編號爲1的肯定是主豬。

再接下來一行,一共m個字符串,按照從牌堆頂部到牌堆底部的順序描述每張牌。

所有的相鄰的兩個字符串都嚴格用1個空格隔開,行尾沒有多餘空格。

【輸出】

輸出數據第一行包含一個字符串代表遊戲結果。如果是主豬勝利,那麼輸出“MP”,否則輸出“FP”。數據保證遊戲總會結束。 接下來n行,第i行是對第i只豬的手牌描述(注意只需要輸出手牌),按照手牌從左往右的順序輸出,相鄰兩張牌用一個空格隔開,行末尾沒有多餘空格。如果這隻豬已陣亡,那麼只要輸出“DEAD”即可。注意如果要輸出手牌而沒有手牌的話,那麼只需輸出一個空行。

【樣例輸入】

3 10
MP D D F F
ZP N N N D
FP J J J J
F F D D J J F F K D

【樣例輸出】

FP
DEAD
DEAD
J J J J J D

【提示】

樣例1說明:第一回合主豬沒有目標可以表敵意;接下來忠豬使用了3張南豬入侵,主豬掉了3點體力,並認爲該角色爲類反豬,3號角色儘管手裏有無懈可擊,但是因爲自己未表明身份,所以同樣不能對自己用,乖乖掉3點體力;下一回合反豬無牌可出;接下來主豬對着類反豬爆發,使用4張決鬥,忠豬死亡,結果主豬棄掉所有牌;下來反豬摸到一張殺直接殺死主豬獲勝。
數據說明:一共20組測試數據,每個點5分。10%的數據沒有錦囊牌,另外20%的數據沒有無懈可擊。

【題解】

模擬。
注意以下幾個點
1.對於錦囊牌,先用無懈可擊再判定。
2.除了桃以外的所有牌在使用後局面可能會發生一些變化,所以重新從左往右掃正在出牌階段的豬的手牌。
3.注意忠豬是不會對類反豬表敵意的。
4.掃的時候注意跳過已經死了的豬。

#include<cstdio>
#include<cstdlib>
#include<algorithm>
const char Num_to_char[9]={0,'P','K','D','F','N','W','J','Z'};
int char_to_Num[305];
struct Pig{
  int card[20005],num,now;
  //1-P 2-K 3-D 4-F 5-N 6-W 7-J 8-Z
  bool is_used[20005];
  int blood,upper_limit_blood;
  //血量,血量上限 
  int role;
  //1-MP 2-ZP 3-FP
  int other_role_look;
  //0-Unknow 1-忠豬 2-類反豬 3-反豬 
  int state;
  //1-DEAD
  int equipment;
  //1-Z
}P[15];
int N,M,Now_Card,Card[2005],Num[4],Nxt[15],Lst[15],Stack[2005],top;
bool Attk=0,Use_card=0;
void discard(int id,int Card_id){P[id].is_used[Card_id]=1;}
void getcard(int id,int n){for (int i=1;i<=n;i++) P[id].card[++P[id].num]=Card[Now_Card=(Now_Card==M+1?M:Now_Card)],Now_Card++;}
void gameover(int win){
    if (win==1) printf("MP\n");
    else printf("FP\n");
    for (int i=1;i<=N;i++){
        if (P[i].state==1){printf("DEAD\n");continue;}
        int Now=1;
        while (P[i].is_used[Now]) Now++;
        if (Now<=P[i].num) printf("%c",Num_to_char[P[i].card[Now]]),Now++;
        for (int j=Now;j<=P[i].num;j++) if (!P[i].is_used[j]) printf(" %c",Num_to_char[P[i].card[j]]);
        printf("\n");
    }
    exit(0);
}
void kill(int A,int B){ //A kill B
    P[B].state=1;Num[P[B].role]--;P[B].now=P[B].num+1;P[B].other_role_look=0;
    if (!Num[1]) gameover(3);
    if (!Num[3]) gameover(1);
    if (P[A].role==1&&P[B].role==2){
        P[A].equipment=0;
        for (int i=P[A].now;i<=P[A].num;i++) P[A].is_used[i]=1;
        P[A].now=P[A].num+1;
    }
    if (P[B].role==3) getcard(A,3);
    Nxt[Lst[B]]=Nxt[B];Lst[Nxt[B]]=Lst[B];P[B].role=0;
}
int find_card(int need_find_card_type,int id){
    for (int i=P[id].now;i<=P[id].num;i++) if (!P[id].is_used[i]&&P[id].card[i]==need_find_card_type) return i;
    return 0;
}
int find_pig(int role,int L,int R){
    for (int i=L;i<=R;i++){
        if (P[i].state==1) continue;
        if (P[i].other_role_look==role) return i;
    }
    return 0;
}
void pd_blood_will_dead(int id){
    while (P[id].blood<=0){
        int Card_id=find_card(1,id);
        if (!Card_id) return ;
        P[id].blood++;discard(id,Card_id);
    }
}
void Blood_loss(int BeAttacker,int Attacker,int Sp){
    P[BeAttacker].blood--;
    pd_blood_will_dead(BeAttacker);
    if (P[BeAttacker].blood<=0) kill(Attacker,BeAttacker);
    if (Sp){
        if (P[BeAttacker].role==1&&P[Attacker].other_role_look==0) P[Attacker].other_role_look=2;
        return ;
    }
    if (P[BeAttacker].other_role_look==1) P[Attacker].other_role_look=3;
    if (P[BeAttacker].other_role_look==3) P[Attacker].other_role_look=1;
}
namespace Invulnerable{
    int find_can_use_Invulnerable(int ForWho,int L,int R){
        for (int i=L;i<=R;i++) {
            if (P[i].state==1) continue;
            if (((ForWho==1&&(P[i].role==1||P[i].role==2))||
                 (ForWho==3&&P[i].role==3))
                 &&find_card(7,i)) return i; 
        }
        return 0;
    }
    bool work_Invulnerable(int User,int A,int B){
        int Who=find_can_use_Invulnerable(A,User,N);
        if (!Who) Who=find_can_use_Invulnerable(A,1,User-1);
        if (!Who) return 0;
        else {
            discard(Who,find_card(7,Who));P[Who].other_role_look=A;
            return !work_Invulnerable(Who,B,A);
        }
    }
    bool use_Invulnerable(int User,int BeUser){
        if (P[BeUser].other_role_look==1) return work_Invulnerable(User,1,3);
        else if (P[BeUser].other_role_look==3) return work_Invulnerable(User,3,1);
        return 0;
    }
};
namespace use_card{
    void patch(int id,int C_id){P[id].blood++;discard(id,C_id);}
    void attack(int id,int C_id,int Change){
        discard(id,C_id);Use_card=1;
        int Card_id=find_card(3,Nxt[id]);
        if (!Card_id) Blood_loss(Nxt[id],id,0);
        else discard(Nxt[id],Card_id);
        P[id].other_role_look=Change;
    }
    void duel(int id,int target,int C_id){
        discard(id,C_id);Use_card=1;
        if (P[target].other_role_look==1) P[id].other_role_look=3;
        if (P[target].other_role_look==3) P[id].other_role_look=1;
        if (Invulnerable::use_Invulnerable(id,target)) return ;
        if (P[target].role==2&&P[id].role==1){
            Blood_loss(target,id,0);return ;
        }
        int Card_id_User=find_card(2,id),Card_id_BeUser=find_card(2,target);
        while (1){
            if (Card_id_BeUser) discard(target,Card_id_BeUser),Card_id_BeUser=find_card(2,target);
            else {Blood_loss(target,id,0);return ;}
            if (Card_id_User) discard(id,Card_id_User),Card_id_User=find_card(2,id);
            else {Blood_loss(id,target,0);return ;}
        }
    }
    void AOE(int id,int type,int C_id){
        discard(id,C_id);Use_card=1;
        for (int i=id+1;i<=N;i++){
            if (P[i].state==1) continue;
            if (Invulnerable::use_Invulnerable(id,i)) continue;
            int Card_id=find_card(type,i);
            if (Card_id) discard(i,Card_id);
            else Blood_loss(i,id,1);
        }
        for (int i=1;i<id;i++){
            if (P[i].state==1) continue;
            if (Invulnerable::use_Invulnerable(id,i)) continue;
            int Card_id=find_card(type,i);
            if (Card_id) discard(i,Card_id);
            else Blood_loss(i,id,1);
        }
    }
    void equip(int id,int C_id){P[id].equipment=1;discard(id,C_id);}
};
namespace pd{
    void patch(int id,int C_id){
        if (P[id].upper_limit_blood>P[id].blood) use_card::patch(id,C_id);
    }
    void attack(int id,int C_id){
        if (Attk&&!P[id].equipment) return ;
        int target=Nxt[id];
        if (P[id].role==1&&(P[target].other_role_look==2||P[target].other_role_look==3)) Attk=1,use_card::attack(id,C_id,1);
        if (P[id].role==2&&P[target].other_role_look==3) Attk=1,use_card::attack(id,C_id,1);
        if (P[id].role==3&&P[target].other_role_look==1) Attk=1,use_card::attack(id,C_id,3);
    }
    void duel(int id,int C_id){
        if (P[id].role==1){
            int Who,Whom,RW;
            Who=find_pig(2,id+1,N);
            if (!Who) Who=find_pig(2,1,id-1);
            Whom=find_pig(3,id+1,N);
            if (!Whom) Whom=find_pig(3,1,id-1);
            RW=Who;
            if (!RW) RW=Whom;
            if (RW>id&&Whom>id&&Whom<RW&&Whom) RW=Whom;
            if (RW<id&&Whom>id&&Whom) RW=Whom;
            if (RW<id&&Whom<id&&Whom<RW&&Whom) RW=Whom;
            if (!RW) return ;
            use_card::duel(id,RW,C_id);
        }
        if (P[id].role==2){
            int Who;
            Who=find_pig(3,id+1,N);
            if (!Who) Who=find_pig(3,1,id-1);
            if (!Who) return ;
            use_card::duel(id,Who,C_id);
        }
        if (P[id].role==3) use_card::duel(id,1,C_id);
    }
    void AOE(int id,int type,int C_id){
        use_card::AOE(id,type,C_id);
    }
    void equip(int id,int C_id){
        use_card::equip(id,C_id);Use_card=1;
    }
}
int main()
{
    freopen("kopk.in","r",stdin);
    freopen("kopk.out","w",stdout);
    scanf("%d%d",&N,&M);
    char_to_Num['P']=1;char_to_Num['K']=2;
    char_to_Num['D']=3;char_to_Num['F']=4;
    char_to_Num['N']=5;char_to_Num['W']=6;
    char_to_Num['J']=7;char_to_Num['Z']=8;
    for (int i=1;i<=N;i++){
        char ch[3];Nxt[i]=i+1;Lst[i]=i-1;
        scanf("%s",ch);
        switch (ch[0]){
            case 'M':P[i].role=1;break;
            case 'Z':P[i].role=2;break;
            case 'F':P[i].role=3;break;
        }
        Num[P[i].role]++;
        for (int j=1;j<=4;j++){
            scanf("%s",ch);
            P[i].card[++P[i].num]=char_to_Num[ch[0]];
        }
        P[i].now=1;P[i].blood=P[i].upper_limit_blood=4;
    }
    Nxt[N]=1;Lst[1]=N;P[1].other_role_look=1;
    for (int i=1;i<=M;i++){
        char ch[3];
        scanf("%s",ch);
        Card[i]=char_to_Num[ch[0]];
    }
    Now_Card=1;
    while (1){
        for (int i=1;i<=N;i++){
            if (P[i].state==1) continue;
            getcard(i,2);Attk=0;
            int Now=P[i].now;
            for (int j=P[i].now;j<=P[i].num;j++){
                if (P[i].is_used[j]) continue;
                switch (P[i].card[j]){
                    case 1:pd::patch(i,j);break;
                    case 2:pd::attack(i,j);break;
                    case 4:pd::duel(i,j);break;
                    case 5:case 6:pd::AOE(i,P[i].card[j]-3,j);break;
                    case 8:pd::equip(i,j);break;                    
                }
                if (Use_card) j=P[i].now-1,Use_card=0;
            }
            while (P[i].is_used[P[i].now]) P[i].now++;
        }
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章