【計算機本科補全計劃】CCF計算機職業(yè)資格認證 2016-09-03(爐石傳說)詳解

正文之前

這是2016年九月份的CCF考試的第三題梯皿,按照高分標準來算,應(yīng)該是在30min內(nèi)解決县恕??然而忠烛。我昨晚花了10mins看完了題目属提,今天上午有限元課的時候想數(shù)據(jù)結(jié)構(gòu),想流程花了我1h 然后,計算機控制系統(tǒng)課上花了1h多來寫這個程序冤议,當然斟薇。其實寫出來只花了半小時多,但是Debug 而且還是巨簡單的非語法BugK∷帷?氨酢!花了我半個多小時蕊温!下面??我來填坑8は洹!

正文

試題編號: 201609-3
試題名稱: 爐石傳說
時間限制: 1.0s
內(nèi)存限制: 256.0MB
  • 問題描述
    《爐石傳說:魔獸英雄傳》(Hearthstone: Heroes of Warcraft义矛,簡稱爐石傳說)是暴雪娛樂開發(fā)的一款集換式卡牌游戲(如下圖所示)发笔。游戲在一個戰(zhàn)斗棋盤上進行,由兩名玩家輪流進行操作凉翻,本題所使用的爐石傳說游戲的簡化規(guī)則如下:


    • 玩家會控制一些角色了讨,每個角色有自己的生命值和攻擊力。當生命值小于等于 0 時制轰,該角色死亡量蕊。角色分為英雄和隨從。
    • 玩家各控制一個英雄艇挨,游戲開始時残炮,英雄的生命值為 30,攻擊力為 0缩滨。當英雄死亡時势就,游戲結(jié)束,英雄未死亡的一方獲勝脉漏。
      *玩家可在游戲過程中召喚隨從苞冯。棋盤上每方都有 7 個可用于放置隨從的空位,從左到右一字排開侧巨,被稱為戰(zhàn)場舅锄。當隨從死亡時,它將被從戰(zhàn)場上移除司忱。
    • 游戲開始后皇忿,兩位玩家輪流進行操作,每個玩家的連續(xù)一組操作稱為一個回合坦仍。
    • 每個回合中鳍烁,當前玩家可進行零個或者多個以下操作:
        1) 召喚隨從:玩家召喚一個隨從進入戰(zhàn)場,隨從具有指定的生命值和攻擊力繁扎。
        2) 隨從攻擊:玩家控制自己的某個隨從攻擊對手的英雄或者某個隨從幔荒。
        3) 結(jié)束回合:玩家聲明自己的當前回合結(jié)束糊闽,游戲?qū)⑦M入對手的回合。該操作一定是一個回合的最后一個操作爹梁。
    • 當隨從攻擊時右犹,攻擊方和被攻擊方會同時對彼此造成等同于自己攻擊力的傷害。受到傷害的角色的生命值將會減少姚垃,數(shù)值等同于受到的傷害念链。例如,隨從 X 的生命值為 HX莉炉、攻擊力為 AX钓账,隨從 Y 的生命值為 HY、攻擊力為 AY絮宁,如果隨從 X 攻擊隨從 Y梆暮,則攻擊發(fā)生后隨從 X 的生命值變?yōu)?HX - AY,隨從 Y 的生命值變?yōu)?HY - AX绍昂。攻擊發(fā)生后啦粹,角色的生命值可以為負數(shù)。
        本題將給出一個游戲的過程窘游,要求編寫程序模擬該游戲過程并輸出最后的局面唠椭。
  • 輸入格式

輸入第一行是一個整數(shù) n,表示操作的個數(shù)忍饰。接下來 n 行贪嫂,每行描述一個操作,格式如下:

 <action> <arg1> <arg2> ...

其中<action>表示操作類型艾蓝,是一個字符串力崇,共有 3 種:summon表示召喚隨從,attack表示隨從攻擊赢织,end表示結(jié)束回合亮靴。這 3 種操作的具體格式如下:

1、 summon <position> <attack> <health>:

當前玩家在位置<position>召喚一個生命值為<health>于置、攻擊力為<attack>的隨從茧吊。其中<position>是一個 1 到 7 的整數(shù),表示召喚的隨從出現(xiàn)在戰(zhàn)場上的位置八毯,原來該位置及右邊的隨從都將順次向右移動一位搓侄。

2、 attack <attacker> <defender>:

當前玩家的角色<attacker>攻擊對方的角色 <defender>宪彩。<attacker>是 1 到 7 的整數(shù)休讳,表示發(fā)起攻擊的本方隨從編號,<defender>是 0 到 7 的整數(shù)尿孔,表示被攻擊的對方角色,0 表示攻擊對方英雄,1 到 7 表示攻擊對方隨從的編號活合。

3雏婶、 end:當前玩家結(jié)束本回合。

注意:隨從的編號會隨著游戲的進程發(fā)生變化白指,當召喚一個隨從時留晚,玩家指定召喚該隨從放入戰(zhàn)場的位置,此時告嘲,原來該位置及右邊的所有隨從編號都會增加 1错维。而當一個隨從死亡時,它右邊的所有隨從編號都會減少 1橄唬。任意時刻赋焕,戰(zhàn)場上的隨從總是從1開始連續(xù)編號。

  • 輸出格式(輸出共 5 行)
    • 第 1 行包含一個整數(shù)仰楚,表示這 n 次操作后(以下稱為 T 時刻)游戲的勝負結(jié)果隆判,1 表示先手玩家獲勝,-1 表示后手玩家獲勝僧界,0 表示游戲尚未結(jié)束侨嘀,還沒有人獲勝。
    • 第 2 行包含一個整數(shù)捂襟,表示 T 時刻先手玩家的英雄的生命值咬腕。
    • 第 3 行包含若干個整數(shù),第一個整數(shù) p 表示 T 時刻先手玩家在戰(zhàn)場上存活的隨從個數(shù)葬荷,之后 p 個整數(shù)涨共,分別表示這些隨從在 T 時刻的生命值(按照從左往右的順序)。
    • 第 4 行和第 5 行與第 2 行和第 3 行類似闯狱,只是將玩家從先手玩家換為后手玩家煞赢。
  • 樣例輸入

8
summon 1 3 6
summon 2 4 2
end
summon 1 4 5
summon 1 2 1
attack 1 2
end
attack 1 1

  • 樣例輸出

0
30
1 2
30
1 2

  • 樣例說明

按照樣例輸入從第 2 行開始逐行的解釋如下:
  1. 先手玩家在位置 1 召喚一個生命值為 6、攻擊力為 3 的隨從 A哄孤,是本方戰(zhàn)場上唯一的隨從照筑。
  2. 先手玩家在位置 2 召喚一個生命值為 2、攻擊力為 4 的隨從 B瘦陈,出現(xiàn)在隨從 A 的右邊凝危。
  3. 先手玩家回合結(jié)束。
  4. 后手玩家在位置 1 召喚一個生命值為 5晨逝、攻擊力為 4 的隨從 C蛾默,是本方戰(zhàn)場上唯一的隨從。
  5. 后手玩家在位置 1 召喚一個生命值為 1捉貌、攻擊力為 2 的隨從 D支鸡,出現(xiàn)在隨從 C 的左邊冬念。
  6. 隨從 D 攻擊隨從 B,雙方均死亡牧挣。
  7. 后手玩家回合結(jié)束急前。
  8. 隨從 A 攻擊隨從 C,雙方的生命值都降低至 2瀑构。

  • 評測用例規(guī)模與約定
    • 操作的個數(shù)0 ≤ n ≤ 1000裆针。
    • 隨從的初始生命值為 1 到 100 的整數(shù),攻擊力為 0 到 100 的整數(shù)寺晌。
    • 保證所有操作均合法世吨,包括但不限于:
        1. 召喚隨從的位置一定是合法的,即如果當前本方戰(zhàn)場上有 m 個隨從呻征,則召喚隨從的位置一定在 1 到 m + 1 之間耘婚,其中 1 表示戰(zhàn)場最左邊的位置,m + 1 表示戰(zhàn)場最右邊的位置怕犁。
        1. 當本方戰(zhàn)場有 7 個隨從時边篮,不會再召喚新的隨從。
        1. 發(fā)起攻擊和被攻擊的角色一定存在奏甫,發(fā)起攻擊的角色攻擊力大于 0戈轿。
        1. 一方英雄如果死亡,就不再會有后續(xù)操作阵子。
          數(shù)據(jù)約定:
        • 前 20% 的評測用例召喚隨從的位置都是戰(zhàn)場的最右邊思杯。
        • 前 40% 的評測用例沒有 attack 操作。
        • 前 60% 的評測用例不會出現(xiàn)隨從死亡的情況挠进。
#include<iostream>
#include<string>
#include<vector>
using namespace std;

class Role
{
public:
    int place;
    int HP;
    int MP;
    // bool player;
};



void Summon(vector<Role> &chess,int position,int MP,int HP)
{
    for(auto &x:chess)
    {
        if (x.place>=position && x.place<=7)
            x.place+=1;
    }
    Role ThisSubmmom;
    ThisSubmmom.place=position;
    ThisSubmmom.HP=HP;
    ThisSubmmom.MP=MP;
    chess.push_back(ThisSubmmom);
}

void Attack(vector<Role> &chess1,vector<Role> &chess2,int attacker,int defender)
{
    int m=0;
    auto p1=chess1.begin(), p2=chess2.begin();
    for(auto x=chess1.begin();x!= chess1.end();++x)
    {
        if((*x).place==attacker)
        {
            m=(*x).MP;
            (*x).HP-=(*x).MP;
            p1=x;
        }
    }
    for(auto x=chess2.begin();x!=chess2.end();++x)
    {
        if((*x).place==defender)
        {
            (*x).HP-=m;
            p2=x;
        }
    }
    if((*p1).HP<=0)
    {
        for(auto &x:chess1)
        {
            if (x.place>(*p1).place)
                x.place-=1;
        }
        chess1.erase(p1);
    }
    if((*p2).HP<=0)
    {
        for(auto &x:chess2)
            
        {
            if (x.place>(*p2).place)
                x.place-=1;
        }
        chess2.erase(p2);
    }
}


int main()
{
    int round;
    Role hero;
    hero.place=0;
    hero.HP=30;
    hero.MP=0;
    vector<Role> Chess1;
    vector<Role> Chess2;
    Chess1.push_back(hero);
    Chess2.push_back(hero);
    cin>>round;
    string action;
    bool Xianshou=true;
    while(round--)
    {
        cin>>action;
        int ac=0;
        if(action=="summon")
            ac=1;
        else if(action=="attack")
            ac=2;
        else
            ac=3;
        switch(ac)
        {
            case 1:
            {
                int a,b,c;
                cin>>a>>b>>c;
                if (Xianshou)
                    Summon(Chess1,a,b,c);
                else
                    Summon(Chess2,a,b,c);
                break;
            }
            case 2:
            {
                int a,b;
                cin>>a>>b;
                if(Xianshou)
                    Attack(Chess1,Chess2,a,b);
                else
                    Attack(Chess2,Chess1,a,b);
                break;
            }
            case 3:
                Xianshou=!Xianshou;
                break;
            default:
                cout<<"you idot~"<<endl;
        }
    }
    int result=0;
    if((*Chess1.begin()).HP==0)
        result=-1;
    else if((*Chess2.begin()).HP==0)
        result=1;
    else
        result=0;
    cout<<result<<endl;
    cout<<(*Chess1.begin()).HP<<endl;
    cout<<Chess1.size()-1<<" ";
    for(auto x=Chess1.begin()+1;x!=Chess1.end();++x)
        cout<<(*x).HP<<" ";
    cout<<endl;
     cout<<(*Chess1.begin()).HP<<endl;
    cout<<Chess2.size()-1<<" ";
    for(auto x=Chess2.begin()+1;x!=Chess2.end();++x)
        cout<<(*x).HP<<" ";
    return 0;
}

運行結(jié)果:

Last login: Tue Nov 28 11:43:23 on ttys001
HustWolf:~ zhangzhaobo$ /Users/zhangzhaobo/program/C++/CCF_2016_09_3 ; exit;
8
summon 1 3 6
summon 2 4 2
end
summon 1 4 5
summon 1 2 1
attack 1 2
end
attack 1 1
0
30
1 3 
30
1 2 logout
Saving session...
...copying shared history...
...saving history...truncating history files...
...completed.

[進程已完成]

下面說說我在編程的過程中遇到的一些Bug:

1色乾、 錯誤的把當前生命值算作攻擊力了豺裆。

按照題目的規(guī)則匪傍,每次攻擊對方,自己也會掉血琳袄,如果每次掉的都是跟自己生命值一樣的血的話君旦,那么就是拿命在攻擊澎办,所以難怪我初期會攻一次死一次,最后搞得直接崩潰了程序金砍,在第二次程序的時候攻不出去局蚀,因為沒有隨從可以攻擊了!~

圖中是改進的恕稠,下面代碼中我進行標識:

void Attack(vector<Role> &chess1,vector<Role> &chess2,int attacker,int defender)
//每次攻擊琅绅,都要有一個攻擊方,一個被攻擊方鹅巍,以及一個攻擊隨從和一個防御隨從千扶,所以傳進來四個參數(shù)料祠,因為要對參數(shù)進行改變,所以采用引用~
{
    int m=0; // 此處用于記錄攻擊者的攻擊力县貌,用來對防御方進行掉血
    auto p1=chess1.begin(), p2=chess2.begin();  //記錄攻擊隨從和防御隨從的位置术陶,在一次操作后對其進行檢驗凑懂,看是否還存活
    for(auto x=chess1.begin();x!= chess1.end();++x)
    {
// find the position of the attacker in the chess1
        if((*x).place==attacker)
        {
            m=(*x).MP;  //record the power of attacker
            (*x).HP-=(*x).MP;  
//殺敵一千煤痕,自損一千   我一開始直接就習慣性的把MP寫成了HP 慘淡,玩命~
            p1=x;   //record the position of attacker
        }
    }
    for(auto x=chess2.begin();x!=chess2.end();++x)
    {
// find the position of defender in the chess2 
        if((*x).place==defender)
        {
            (*x).HP-=m;  //被殺一千
            p2=x; //record the position of the defender
        }
    }
    if((*p1).HP<=0)
    {
// look at the attacker and his life
        for(auto &x:chess1)
        {
            if (x.place>(*p1).place)
                x.place-=1;
        }
        chess1.erase(p1);  // if he dies,erase him.
    }
    if((*p2).HP<=0)
    {
        for(auto &x:chess2)
            
        {
            if (x.place>(*p2).place)
                x.place-=1;
        }
        chess2.erase(p2);
    }
}

2接谨、 因為圖方便摆碉,直接copy了一段代碼。

 if((*p1).HP<=0)
    {
        for(auto &x:chess1)
        {
            if (x.place>(*p1).place)
                x.place-=1;
        }
        chess1.erase(p1);
    }
    if((*p2).HP<=0)
    {
        for(auto &x:chess2)
            
        {
            if (x.place>(*p2).place)//一開始這里是寫的p1脓豪,所以我就奇怪每次都會報錯巷帝??扫夜?因為p2根本不在x的序列中@闫谩!所以會有重合的position笤闯,然后就GG
                x.place-=1;
        }
        chess2.erase(p2);
    }

3堕阔、 忘了switch 的case貌似只能帶int?反正我按照圖中這么改了之后就對了

一開始的代碼是這樣的颗味!~然后就報錯了超陆,賊心塞!浦马!

cin>>action;
switch(ac)  
{
    case "summon":  // 好像是case后面只跟int
    {
        int a,b,c;
        cin>>a>>b>>c;
        if (Xianshou)
            Summon(Chess1,a,b,c);
        else
            Summon(Chess2,a,b,c);
        break;
    }
    case "attack":
    {
        int a,b;
        cin>>a>>b;
        if(Xianshou)
            Attack(Chess1,Chess2,a,b);
        else
            Attack(Chess2,Chess1,a,b);
        break;
    }
    case "end":
        Xianshou=!Xianshou;
        break;
    default:
        cout<<"you idot~"<<endl;
}

其實可以建個map的时呀,but算了吧!懶得搞了~晶默,別到時候又出岔子谨娜。算了,寫一個試試磺陡?趴梢?果然,裝逼還是全套的好 美滋滋仅政。done了

        cin>>action;
        map<string,int> act;
        act.insert(pair<string,int>("summon",1));
        act.insert(pair<string,int>("attack",2));
        act.insert(pair<string,int>("end",3));
        switch(act[action])

4垢油、 忘了英雄不算隨從數(shù)了:

   int result=0;
   if((*Chess1.begin()).HP==0)
       result=-1;
   else if((*Chess2.begin()).HP==0)
       result=1;
   else
       result=0;
   cout<<result<<endl;
   cout<<(*Chess1.begin()).HP<<endl;
   cout<<Chess1.size()-1<<" ";
   for(auto x=Chess1.begin()+1;x!=Chess1.end();++x)
       cout<<(*x).HP<<" ";
   cout<<endl;
   cout<<(*Chess1.begin()).HP<<endl;
   cout<<Chess2.size()-1<<" ";  //本來沒有這個-1 所以vector的size會把0位的英雄也算上
   for(auto x=Chess2.begin()+1;x!=Chess2.end();++x)
       cout<<(*x).HP<<" ";  // 此處輸出隨從的生命值,早早就知道了要把英雄去掉了圆丹,所以begin之后+1 美滋滋~ 英雄的0位不可撼動滩愁!

   return 0;

正文之后

我現(xiàn)在對自己很不自信,不知道下一題會做到什么時候辫封,雖然熟練度會上升硝枉,但是第四題這種還是不好說的廉丽!所以我估計做完要到明天了吧?所以先發(fā)一題好了妻味!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末正压,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子责球,更是在濱河造成了極大的恐慌焦履,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,110評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件雏逾,死亡現(xiàn)場離奇詭異嘉裤,居然都是意外死亡,警方通過查閱死者的電腦和手機栖博,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評論 3 395
  • 文/潘曉璐 我一進店門屑宠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人仇让,你說我怎么就攤上這事典奉。” “怎么了丧叽?”我有些...
    開封第一講書人閱讀 165,474評論 0 356
  • 文/不壞的土叔 我叫張陵卫玖,是天一觀的道長。 經(jīng)常有香客問我蠢正,道長骇笔,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,881評論 1 295
  • 正文 為了忘掉前任嚣崭,我火速辦了婚禮笨触,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘雹舀。我一直安慰自己芦劣,他們只是感情好,可當我...
    茶點故事閱讀 67,902評論 6 392
  • 文/花漫 我一把揭開白布说榆。 她就那樣靜靜地躺著虚吟,像睡著了一般。 火紅的嫁衣襯著肌膚如雪签财。 梳的紋絲不亂的頭發(fā)上串慰,一...
    開封第一講書人閱讀 51,698評論 1 305
  • 那天,我揣著相機與錄音唱蒸,去河邊找鬼邦鲫。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的庆捺。 我是一名探鬼主播古今,決...
    沈念sama閱讀 40,418評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼滔以!你這毒婦竟也來了捉腥?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,332評論 0 276
  • 序言:老撾萬榮一對情侶失蹤你画,失蹤者是張志新(化名)和其女友劉穎抵碟,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體撬即,經(jīng)...
    沈念sama閱讀 45,796評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡立磁,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,968評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了剥槐。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,110評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡宪摧,死狀恐怖粒竖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情几于,我是刑警寧澤蕊苗,帶...
    沈念sama閱讀 35,792評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站沿彭,受9級特大地震影響朽砰,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜喉刘,卻給世界環(huán)境...
    茶點故事閱讀 41,455評論 3 331
  • 文/蒙蒙 一瞧柔、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧睦裳,春花似錦造锅、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蛛蒙,卻和暖如春糙箍,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背牵祟。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評論 1 272
  • 我被黑心中介騙來泰國打工深夯, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人课舍。 一個月前我還...
    沈念sama閱讀 48,348評論 3 373
  • 正文 我出身青樓塌西,卻偏偏與公主長得像他挎,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子捡需,可洞房花燭夜當晚...
    茶點故事閱讀 45,047評論 2 355