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

正文之前

這是2016年九月份的CCF考試的第三題,按照高分標(biāo)準(zhǔn)來(lái)算,應(yīng)該是在30min內(nèi)解決??然而。我昨晚花了10mins看完了題目,今天上午有限元課的時(shí)候想數(shù)據(jù)結(jié)構(gòu),想流程花了我1h 然后,計(jì)算機(jī)控制系統(tǒng)課上花了1h多來(lái)寫這個(gè)程序,當(dāng)然。其實(shí)寫出來(lái)只花了半小時(shí)多,但是Debug 而且還是巨簡(jiǎn)單的非語(yǔ)法Bug?。。』宋野雮€(gè)多小時(shí)!下面??我來(lái)填坑??!

正文

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


    • 玩家會(huì)控制一些角色,每個(gè)角色有自己的生命值和攻擊力。當(dāng)生命值小于等于 0 時(shí),該角色死亡。角色分為英雄和隨從。
    • 玩家各控制一個(gè)英雄,游戲開始時(shí),英雄的生命值為 30,攻擊力為 0。當(dāng)英雄死亡時(shí),游戲結(jié)束,英雄未死亡的一方獲勝。
      *玩家可在游戲過程中召喚隨從。棋盤上每方都有 7 個(gè)可用于放置隨從的空位,從左到右一字排開,被稱為戰(zhàn)場(chǎng)。當(dāng)隨從死亡時(shí),它將被從戰(zhàn)場(chǎng)上移除。
    • 游戲開始后,兩位玩家輪流進(jìn)行操作,每個(gè)玩家的連續(xù)一組操作稱為一個(gè)回合。
    • 每個(gè)回合中,當(dāng)前玩家可進(jìn)行零個(gè)或者多個(gè)以下操作:
        1) 召喚隨從:玩家召喚一個(gè)隨從進(jìn)入戰(zhàn)場(chǎng),隨從具有指定的生命值和攻擊力。
        2) 隨從攻擊:玩家控制自己的某個(gè)隨從攻擊對(duì)手的英雄或者某個(gè)隨從。
        3) 結(jié)束回合:玩家聲明自己的當(dāng)前回合結(jié)束,游戲?qū)⑦M(jìn)入對(duì)手的回合。該操作一定是一個(gè)回合的最后一個(gè)操作。
    • 當(dāng)隨從攻擊時(shí),攻擊方和被攻擊方會(huì)同時(shí)對(duì)彼此造成等同于自己攻擊力的傷害。受到傷害的角色的生命值將會(huì)減少,數(shù)值等同于受到的傷害。例如,隨從 X 的生命值為 HX、攻擊力為 AX,隨從 Y 的生命值為 HY、攻擊力為 AY,如果隨從 X 攻擊隨從 Y,則攻擊發(fā)生后隨從 X 的生命值變?yōu)?HX - AY,隨從 Y 的生命值變?yōu)?HY - AX。攻擊發(fā)生后,角色的生命值可以為負(fù)數(shù)。
        本題將給出一個(gè)游戲的過程,要求編寫程序模擬該游戲過程并輸出最后的局面。
  • 輸入格式

輸入第一行是一個(gè)整數(shù) n,表示操作的個(gè)數(shù)。接下來(lái) n 行,每行描述一個(gè)操作,格式如下:

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

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

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

當(dāng)前玩家在位置<position>召喚一個(gè)生命值為<health>、攻擊力為<attack>的隨從。其中<position>是一個(gè) 1 到 7 的整數(shù),表示召喚的隨從出現(xiàn)在戰(zhàn)場(chǎng)上的位置,原來(lái)該位置及右邊的隨從都將順次向右移動(dòng)一位。

2、 attack <attacker> <defender>:

當(dāng)前玩家的角色<attacker>攻擊對(duì)方的角色 <defender>。<attacker>是 1 到 7 的整數(shù),表示發(fā)起攻擊的本方隨從編號(hào),<defender>是 0 到 7 的整數(shù),表示被攻擊的對(duì)方角色,0 表示攻擊對(duì)方英雄,1 到 7 表示攻擊對(duì)方隨從的編號(hào)。

3、 end:當(dāng)前玩家結(jié)束本回合。

注意:隨從的編號(hào)會(huì)隨著游戲的進(jìn)程發(fā)生變化,當(dāng)召喚一個(gè)隨從時(shí),玩家指定召喚該隨從放入戰(zhàn)場(chǎng)的位置,此時(shí),原來(lái)該位置及右邊的所有隨從編號(hào)都會(huì)增加 1。而當(dāng)一個(gè)隨從死亡時(shí),它右邊的所有隨從編號(hào)都會(huì)減少 1。任意時(shí)刻,戰(zhàn)場(chǎng)上的隨從總是從1開始連續(xù)編號(hào)。

  • 輸出格式(輸出共 5 行)
    • 第 1 行包含一個(gè)整數(shù),表示這 n 次操作后(以下稱為 T 時(shí)刻)游戲的勝負(fù)結(jié)果,1 表示先手玩家獲勝,-1 表示后手玩家獲勝,0 表示游戲尚未結(jié)束,還沒有人獲勝。
    • 第 2 行包含一個(gè)整數(shù),表示 T 時(shí)刻先手玩家的英雄的生命值。
    • 第 3 行包含若干個(gè)整數(shù),第一個(gè)整數(shù) p 表示 T 時(shí)刻先手玩家在戰(zhàn)場(chǎng)上存活的隨從個(gè)數(shù),之后 p 個(gè)整數(shù),分別表示這些隨從在 T 時(shí)刻的生命值(按照從左往右的順序)。
    • 第 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 召喚一個(gè)生命值為 6、攻擊力為 3 的隨從 A,是本方戰(zhàn)場(chǎng)上唯一的隨從。
  2. 先手玩家在位置 2 召喚一個(gè)生命值為 2、攻擊力為 4 的隨從 B,出現(xiàn)在隨從 A 的右邊。
  3. 先手玩家回合結(jié)束。
  4. 后手玩家在位置 1 召喚一個(gè)生命值為 5、攻擊力為 4 的隨從 C,是本方戰(zhàn)場(chǎng)上唯一的隨從。
  5. 后手玩家在位置 1 召喚一個(gè)生命值為 1、攻擊力為 2 的隨從 D,出現(xiàn)在隨從 C 的左邊。
  6. 隨從 D 攻擊隨從 B,雙方均死亡。
  7. 后手玩家回合結(jié)束。
  8. 隨從 A 攻擊隨從 C,雙方的生命值都降低至 2。

  • 評(píng)測(cè)用例規(guī)模與約定
    • 操作的個(gè)數(shù)0 ≤ n ≤ 1000。
    • 隨從的初始生命值為 1 到 100 的整數(shù),攻擊力為 0 到 100 的整數(shù)。
    • 保證所有操作均合法,包括但不限于:
        1. 召喚隨從的位置一定是合法的,即如果當(dāng)前本方戰(zhàn)場(chǎng)上有 m 個(gè)隨從,則召喚隨從的位置一定在 1 到 m + 1 之間,其中 1 表示戰(zhàn)場(chǎng)最左邊的位置,m + 1 表示戰(zhàn)場(chǎng)最右邊的位置。
        1. 當(dāng)本方戰(zhàn)場(chǎng)有 7 個(gè)隨從時(shí),不會(huì)再召喚新的隨從。
        1. 發(fā)起攻擊和被攻擊的角色一定存在,發(fā)起攻擊的角色攻擊力大于 0。
        1. 一方英雄如果死亡,就不再會(huì)有后續(xù)操作。
          數(shù)據(jù)約定:
        • 前 20% 的評(píng)測(cè)用例召喚隨從的位置都是戰(zhàn)場(chǎng)的最右邊。
        • 前 40% 的評(píng)測(cè)用例沒有 attack 操作。
        • 前 60% 的評(píng)測(cè)用例不會(huì)出現(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;
}

運(yùn)行結(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.

[進(jìn)程已完成]

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

1、 錯(cuò)誤的把當(dāng)前生命值算作攻擊力了。

按照題目的規(guī)則,每次攻擊對(duì)方,自己也會(huì)掉血,如果每次掉的都是跟自己生命值一樣的血的話,那么就是拿命在攻擊,所以難怪我初期會(huì)攻一次死一次,最后搞得直接崩潰了程序,在第二次程序的時(shí)候攻不出去,因?yàn)闆]有隨從可以攻擊了!~

圖中是改進(jìn)的,下面代碼中我進(jìn)行標(biāo)識(shí):

void Attack(vector<Role> &chess1,vector<Role> &chess2,int attacker,int defender)
//每次攻擊,都要有一個(gè)攻擊方,一個(gè)被攻擊方,以及一個(gè)攻擊隨從和一個(gè)防御隨從,所以傳進(jìn)來(lái)四個(gè)參數(shù),因?yàn)橐獙?duì)參數(shù)進(jìn)行改變,所以采用引用~
{
    int m=0; // 此處用于記錄攻擊者的攻擊力,用來(lái)對(duì)防御方進(jìn)行掉血
    auto p1=chess1.begin(), p2=chess2.begin();  //記錄攻擊隨從和防御隨從的位置,在一次操作后對(duì)其進(jìn)行檢驗(yàn),看是否還存活
    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;  
//殺敵一千,自損一千   我一開始直接就習(xí)慣性的把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、 因?yàn)閳D方便,直接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,所以我就奇怪每次都會(huì)報(bào)錯(cuò)???因?yàn)閜2根本不在x的序列中?。∷詴?huì)有重合的position,然后就GG
                x.place-=1;
        }
        chess2.erase(p2);
    }

3、 忘了switch 的case貌似只能帶int?反正我按照?qǐng)D中這么改了之后就對(duì)了

一開始的代碼是這樣的!~然后就報(bào)錯(cuò)了,賊心塞!!

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;
}

其實(shí)可以建個(gè)map的,but算了吧!懶得搞了~,別到時(shí)候又出岔子。算了,寫一個(gè)試試??果然,裝逼還是全套的好 美滋滋。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<<" ";  //本來(lái)沒有這個(gè)-1 所以vector的size會(huì)把0位的英雄也算上
   for(auto x=Chess2.begin()+1;x!=Chess2.end();++x)
       cout<<(*x).HP<<" ";  // 此處輸出隨從的生命值,早早就知道了要把英雄去掉了,所以begin之后+1 美滋滋~ 英雄的0位不可撼動(dòng)!

   return 0;

正文之后

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,963評(píng)論 6 542
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,348評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 178,083評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,706評(píng)論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,442評(píng)論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,802評(píng)論 1 328
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,795評(píng)論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,983評(píng)論 0 290
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,542評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,287評(píng)論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,486評(píng)論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,030評(píng)論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,710評(píng)論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,116評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,412評(píng)論 1 294
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,224評(píng)論 3 398
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,462評(píng)論 2 378