正文之前
這是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ù)寺晌。
- 保證所有操作均合法世吨,包括但不限于:
- 召喚隨從的位置一定是合法的,即如果當前本方戰(zhàn)場上有 m 個隨從呻征,則召喚隨從的位置一定在 1 到 m + 1 之間耘婚,其中 1 表示戰(zhàn)場最左邊的位置,m + 1 表示戰(zhàn)場最右邊的位置怕犁。
- 當本方戰(zhàn)場有 7 個隨從時边篮,不會再召喚新的隨從。
- 發(fā)起攻擊和被攻擊的角色一定存在奏甫,發(fā)起攻擊的角色攻擊力大于 0戈轿。
-
- 一方英雄如果死亡,就不再會有后續(xù)操作阵子。
數(shù)據(jù)約定:
- 前 20% 的評測用例召喚隨從的位置都是戰(zhàn)場的最右邊思杯。
- 前 40% 的評測用例沒有 attack 操作。
- 前 60% 的評測用例不會出現(xiàn)隨從死亡的情況挠进。
- 一方英雄如果死亡,就不再會有后續(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;
}
運行結(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ā)一題好了妻味!