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