题目来源:
北京大学MOOC 郭炜 程序设计与算法(三)C++面向对象程序设计
描述:
魔兽世界的西面是红魔军的司令部,东面是蓝魔军的司令部。两个司令部之间是依次排列的若干城市,城市从西向东依次编号为1,2,3 .... N ( N <= 20)。红魔军的司令部算作编号为0的城市,蓝魔军的司令部算作编号为N+1的城市。司令部有生命元,用于制造武士。
两军的司令部都会制造武士。武士一共有dragon 、ninja、iceman、lion、wolf 五种。每种武士都有编号、生命值、攻击力这三种属性。
双方的武士编号都是从1开始计算。红方制造出来的第n 个武士,编号就是n。同样,蓝方制造出来的第n 个武士,编号也是n。
武士在刚降生的时候有一个初始的生命值,生命值在战斗中会发生变化,如果生命值减少到0(生命值变为负数时应当做变为0处理),则武士死亡(消失)。
武士可以拥有武器。武器有三种,sword, bomb,和arrow,编号分别为0,1,2。
sword的攻击力是使用者当前攻击力的20%(去尾取整)。
bomb的攻击力是使用者当前攻击力的40%(去尾取整),但是也会导致使用者受到攻击,对使用者的攻击力是对敌人取整后的攻击力的1/2(去尾取整)。Bomb一旦使用就没了。
arrow的攻击力是使用者当前攻击力的30%(去尾取整)。一个arrow用两次就没了。
武士降生后就朝对方司令部走,在经过的城市如果遇到敌人(同一时刻每个城市最多只可能有1个蓝武士和一个红武士),就会发生战斗。战斗的规则是:
-
在奇数编号城市,红武士先发起攻击
-
在偶数编号城市,蓝武士先发起攻击
-
战斗开始前,双方先对自己的武器排好使用顺序,然后再一件一件地按顺序使用。编号小的武器,排在前面。若有多支arrow,用过的排在前面。排好序后,攻击者按此排序依次对敌人一件一件地使用武器。如果一种武器有多件,那就都要用上。每使用一件武器,被攻击者生命值要减去武器攻击力。如果任何一方生命值减为0或小于0即为死去。有一方死去,则战斗结束。
-
双方轮流使用武器,甲用过一件,就轮到乙用。某一方把自己所有的武器都用过一轮后,就从头开始再用一轮。如果某一方没有武器了,那就挨打直到死去或敌人武器用完。武器排序只在战斗前进行,战斗中不会重新排序。
-
如果双方武器都用完且都还活着,则战斗以平局结束。如果双方都死了,也算平局。
-
有可能由于武士自身攻击力太低,而导致武器攻击力为0。攻击力为0的武器也要使用。如果战斗中双方的生命值和武器的状态都不再发生变化,则战斗结束,算平局。
-
战斗的胜方获得对方手里的武器。武士手里武器总数不超过10件。缴获武器时,按照武器种类编号从小到大缴获。如果有多件arrow,优先缴获没用过的。
-
如果战斗开始前双方都没有武器,则战斗视为平局。如果先攻击方没有武器,则由后攻击方攻击。
不同的武士有不同的特点。
编号为n的dragon降生时即获得编号为n%3 的武器。dragon在战斗结束后,如果还没有战死,就会欢呼。
编号为n的ninjia降生时即获得编号为n%3 和(n+1)%3的武器。ninja 使用bomb不会让自己受伤。
编号为n的iceman降生时即获得编号为n%3 的武器。iceman每前进一步,生命值减少10%(减少的量要去尾取整)。
编号为n的lion降生时即获得编号为n%3 的武器。lion 有“忠诚度”这个属性,其初始值等于它降生之后其司令部剩余生命元的数目。每前进一步忠诚度就降低K。忠诚度降至0或0以下,则该lion逃离战场,永远消失。但是已经到达敌人司令部的lion不会逃跑。lion在己方司令部可能逃跑。
wolf降生时没有武器,但是在战斗开始前会抢到敌人编号最小的那种武器。如果敌人有多件这样的武器,则全部抢来。Wolf手里武器也不能超过10件。如果敌人arrow太多没法都抢来,那就先抢没用过的。如果敌人也是wolf,则不抢武器。
以下是不同时间会发生的不同事件:
在每个整点,即每个小时的第0分, 双方的司令部中各有一个武士降生。
红方司令部按照iceman、lion、wolf、ninja、dragon 的顺序制造武士。
蓝方司令部按照lion、dragon、ninja、iceman、wolf 的顺序制造武士。
制造武士需要生命元。
制造一个初始生命值为m 的武士,司令部中的生命元就要减少m 个。
如果司令部中的生命元不足以制造某本该造的武士,那就从此停止制造武士。
在每个小时的第5分,该逃跑的lion就在这一时刻逃跑了。
在每个小时的第10分:所有的武士朝敌人司令部方向前进一步。即从己方司令部走到相邻城市,或从一个城市走到下一个城市。或从和敌军司令部相邻的城市到达敌军司令部。
在每个小时的第35分:在有wolf及其敌人的城市,wolf要抢夺对方的武器。
在每个小时的第40分:在有两个武士的城市,会发生战斗。
在每个小时的第50分,司令部报告它拥有的生命元数量。
在每个小时的第55分,每个武士报告其拥有的武器情况。
武士到达对方司令部后就算完成任务了,从此就呆在那里无所事事。
任何一方的司令部里若是出现了敌人,则认为该司令部已被敌人占领。
任何一方的司令部被敌人占领,则战争结束。战争结束之后就不会发生任何事情了。
给定一个时间,要求你将从0点0分开始到此时间为止的所有事件按顺序输出。事件及其对应的输出样例如下:
1) 武士降生
输出样例:000:00 blue dragon 1 born
表示在0点0分,编号为1的蓝魔dragon武士降生
如果造出的是lion,那么还要多输出一行,例:
000:00 blue lion 1 born
Its loyalty is 24
表示该lion降生时的忠诚度是24
2) lion逃跑
输出样例:000:05 blue lion 1 ran away
表示在0点5分,编号为1的蓝魔lion武士逃走
3) 武士前进到某一城市
输出样例:
000:10 red iceman 1 marched to city 1 with 20 elements and force 30
表示在0点10分,红魔1号武士iceman前进到1号城市,此时他生命值为20,攻击力为30
对于iceman,输出的生命值应该是变化后的数值
4) wolf抢敌人的武器
000:35 blue wolf 2 took 3 bomb from red dragon 2 in city 4
表示在0点35分,4号城市中,红魔1号武士wolf 抢走蓝魔2号武士dragon 3个bomb。为简单起见,武器不写复数形式
5) 报告战斗情况
战斗只有3种可能的输出结果:
000:40 red iceman 1 killed blue lion 12 in city 2 remaining 20 elements
表示在0点40分,1号城市中,红魔1号武士iceman 杀死蓝魔12号武士lion后,剩下生命值20
000:40 both red iceman 1 and blue lion 12 died in city 2
注意,把红武士写前面
000:40 both red iceman 1 and blue lion 12 were alive in city 2
注意,把红武士写前面
6) 武士欢呼
输出样例:003:40 blue dragon 2 yelled in city 4
7) 武士抵达敌军司令部
输出样例:001:10 red iceman 1 reached blue headquarter with 20 elements and force 30
(此时他生命值为20,攻击力为30)对于iceman,输出的生命值和攻击力应该是变化后的数值
8) 司令部被占领
输出样例:003:10 blue headquarter was taken
9)司令部报告生命元数量
000:50 100 elements in red headquarter
000:50 120 elements in blue headquarter
表示在0点50分,红方司令部有100个生命元,蓝方有120个
10)武士报告情况
000:55 blue wolf 2 has 2 sword 3 bomb 0 arrow and 7 elements
为简单起见,武器都不写复数形式。elements一律写复数,哪怕只有1个
交代武器情况时,次序依次是:sword,bomb, arrow。
输出事件时:
首先按时间顺序输出;
同一时间发生的事件,按发生地点从西向东依次输出. 武士前进的事件, 算是发生在目的地。
在一次战斗中有可能发生上面的 5 至 6 号事件。这些事件都算同时发生,其时间就是战斗开始时间。一次战斗中的这些事件,序号小的应该先输出。
两个武士同时抵达同一城市,则先输出红武士的前进事件,后输出蓝武士的。
对于同一城市,同一时间发生的事情,先输出红方的,后输出蓝方的。
显然,8号事件发生之前的一瞬间一定发生了7号事件。输出时,这两件事算同一时间发生,但是应先输出7号事件
虽然任何一方的司令部被占领之后,就不会有任何事情发生了。但和司令部被占领同时发生的事件,全都要输出。
输入:
第一行是t,代表测试数据组数
每组样例共三行。
第一行,4个整数 M,N,K, T。其含义为:
每个司令部一开始都有M个生命元( 1 <= M <= 100000)
两个司令部之间一共有N个城市( 1 <= N <= 20 )
lion每前进一步,忠诚度就降低K。(0<=K<=100)
要求输出从0时0分开始,到时间T为止(包括T) 的所有事件。T以分钟为单位,0 <= T <= 6000
第二行:五个整数,依次是 dragon 、ninja、iceman、lion、wolf 的初始生命值。它们都大于0小于等于200
第三行:五个整数,依次是 dragon 、ninja、iceman、lion、wolf 的攻击力。它们都大于0小于等于200
输出:
对每组数据,先输出一行:
Case n:
如对第一组数据就输出 Case 1:
然后按恰当的顺序和格式输出到时间T为止发生的所有事件。每个事件都以事件发生的时间开头,时间格式是“时: 分”,“时”有三位,“分”有两位。
请注意浮点数精度误差问题。OJ上的编译器编译出来的可执行程序,在这方面和你电脑上执行的程序很可能会不一致。5 * 0.3 的结果,有的机器上可能是 15.00000001,去尾取整得到15,有的机器上可能是14.9999999,去尾取整后就变成14。因此,本题不要写 5 * 0.3,要写 5 * 3 / 10。
样例输入:
1 20 1 10 400 20 20 30 10 20 5 5 5 5 5
样例输出:
Case 1: 000:00 blue lion 1 born Its loyalty is 10 000:10 blue lion 1 marched to city 1 with 10 elements and force 5 000:50 20 elements in red headquarter 000:50 10 elements in blue headquarter 000:55 blue lion 1 has 0 sword 1 bomb 0 arrow and 10 elements 001:05 blue lion 1 ran away 001:50 20 elements in red headquarter 001:50 10 elements in blue headquarter 002:50 20 elements in red headquarter 002:50 10 elements in blue headquarter 003:50 20 elements in red headquarter 003:50 10 elements in blue headquarter 004:50 20 elements in red headquarter 004:50 10 elements in blue headquarter 005:50 20 elements in red headquarter 005:50 10 elements in blue headquarter
题目解析:
该题在“魔兽世界二:装备”基础上新增和改变了许多功能,其中的难点主要在“wolf抢夺武器”和“两个武士发生战斗”这两个事件,下面来说说我在这道题目中踩过的坑,如下
/*
1. 在前两个题目备战和装备中,组数要求输出“Case:1”,而这道题目中要求输出“Case 1:”;
2. 虽然任何一方的司令部被占领之后,就不会有任何事情发生了,但和司令部被占领同时发生的事件,全都要输出。
因此在武士前进的函数中,要特别注意当武士占领司令部后函数的返回时机。我最先因为没处理好这一点,导致
司令部被占领后,司令部中若有武士要前进到相邻的城市得不到输出;
3. ninja使用bomb不会让自己受伤 。当时我写着写着就忘记了 ;
4. int life; 注意“life *= 9/10;”与“ life = num * 9/10;” 的差异,即计算顺序不同导致的结果差异。当时我在对iceman的
前进掉血属性中没有注意到这一点;
5. wolf不抢wolf的武器,wolf抢夺武器时会抢到敌人编号最小的那种武器,即wolf只会抢夺一种类型的武器。 当时我先让对方丢失
一件武器,结果wolf判断该武器不符合抢夺的要求没有抢夺,但却忘了把这件丢失的武器还给被抢夺者。
*/
参考代码:
提交状态为Accepted的参考代码如下
# include<iostream>
# include<iomanip>
# include<string>
# include<cmath>
# include<map>
using namespace std;
# define BOMB_DAMAGE 4 / 10 // bomb的攻击力是使用者攻击力的百分比
# define SWORD_DAMAGE 2 / 10 // sord的攻击力是使用者攻击力的百分比
# define ARROW_DAMAGE 3 / 10 // arrow的攻击力是使用者攻击力的百分比
# define WEPON_MAX_NUM 10 // 拥有的最多武器数
# define WEPON_KIND_NUM 3 // 武器种类
# define WARRIOR_KIND_NUM 5 // 武士的种类
# define ICEMAN_LIFE_REDUCE 1 / 10 // iceman每前进一步生命值减少百分比
int CITY_NUM; // 两个司令部之间城市的数量
int TIME_NUM; // 每组进行总的时间,以分钟为单位
int LIFE_ELEMENT; // 一开始拥有的生命元数量
int LOYALTY_LESS; // lion每前进一步,忠诚度的降低值
map<string, int> WARRIOR_LIFE; // 各种武士初始生命值
map<string, int> WARRIOR_DAMAGE; // 每种武士的攻击力
map<string, int> WEPON_USE_TIME = { {"sword",-1},{"bomb",1} ,{"arrow",2} }; // 每种武器的使用次数,-1代表可以无限使用
string WEPON_LIST[3] = { "sword","bomb","arrow" }; // 武器种类
string BLUE_MAKE_SORT[5] = { "lion","dragon","ninja","iceman","wolf" }; // 红方司令部制造武士顺序
string RED_MAKE_SORT[5] = { "iceman", "lion", "wolf", "ninja", "dragon" }; // 蓝方司令部制造武士顺序
string WARRIOR_CIN_SORT[WARRIOR_KIND_NUM] = { "dragon","ninja","iceman","lion","wolf" }; // 武士生命值输入顺序
class CWarrior;
// 武器类
class CWepon {
public:
int id; // 武器编号
int use_time; // 使用次数
int damage_value; // 攻击力
string name; // 武器种类
// 构造函数
CWepon(int _id) :id(_id) ,damage_value(0){
name = WEPON_LIST[_id];
use_time = WEPON_USE_TIME[name];
}
// 重载运算符实现武器之间的大小比较(编号大为大,编号相同使用次数大为大)
bool operator > (const CWepon& compare_object) {
if (id > compare_object.id || (id == compare_object.id && use_time > compare_object.use_time))return true;
else return false;
}
// 武器使用属性
virtual void use_self(CWarrior* warrior_use, CWarrior* warrior_victim) {}
// 虚析构函数
virtual ~CWepon() {}
};
// 武器派生类sword
class CSword :public CWepon {
public:
CSword(int _id, int warrior_damage_value) :CWepon(_id) {
damage_value = warrior_damage_value * SWORD_DAMAGE;
}
void use_self(CWarrior* warrior_use, CWarrior* warrior_victim);
};
// 武器派生类bomb
class CBomb :public CWepon {
public:
CBomb(int _id, int warrior_damage_value) :CWepon(_id) {
damage_value = warrior_damage_value * BOMB_DAMAGE;
}
void use_self(CWarrior* warrior_use, CWarrior* warrior_victim);
};
// 武器派生类arrow
class CArrow :public CWepon {
public:
CArrow(int _id, int warrior_damage_value) :CWepon(_id) {
damage_value = warrior_damage_value * ARROW_DAMAGE;
}
void use_self(CWarrior* warrior_use, CWarrior* warrior_victim);
};
// 武士类
class CWarrior {
public:
int id; // 编号
int life_value; // 初始生命值
int wepon_total; // 拥有的武器总数量
int damage_value; // 攻击力
string name; // 种类
string color; // 所属司令部类别
CWepon* wepon[WEPON_MAX_NUM]; // 拥有的武器
map<string, int>wepon_kind_num; // 拥有各种武器的数量
// 构造函数
CWarrior(int _id, int _life_value, string _name, string _color) :
id(_id), life_value(_life_value), name(_name), color(_color), wepon_total(0),damage_value(0) {
for (int i = 0; i < WEPON_MAX_NUM; ++i)wepon[i] = NULL;
for (int i = 0; i < WEPON_KIND_NUM; ++i) {
wepon_kind_num[WEPON_LIST[i]] = 0;
}
}
// 析构函数
virtual ~CWarrior() {
for (int i = 0; i < WEPON_MAX_NUM; ++i) {
if (wepon[i] != NULL)delete wepon[i];
}
}
// 获取初始武器
void get_initial_wepon(int wepon_id) {
CWepon* ptr_wepon = NULL;
if (wepon_id == 0) {
ptr_wepon = new CSword(wepon_id, WARRIOR_DAMAGE[name]);
}
else if (wepon_id == 1) {
ptr_wepon = new CBomb(wepon_id, WARRIOR_DAMAGE[name]);
}
else if (wepon_id == 2) {
ptr_wepon = new CArrow(wepon_id, WARRIOR_DAMAGE[name]);
}
wepon[wepon_total++] = ptr_wepon;
++wepon_kind_num[WEPON_LIST[wepon_id]];
}
// 前进属性
virtual void move_step() {}
// 失去一件武器(武器编号小优先,编号相同使用次数大优先),为了满足wolf的抢夺因此设置一个默认参数
CWepon* lose_wepon(int same_id = -1) {
CWepon* back_wepon = NULL;
int min_id = WEPON_KIND_NUM;
// list_id记录返回的是武器列表中的第几件武器
int list_id = -1; // 记录返回的是武器列表中的第几件武器
for (int i = 0; i < WEPON_MAX_NUM; ++i) {
if (wepon[i] != NULL && wepon[i]->id < min_id) { // 有NULL的判定,是因为返回后,将原有武器指针置为了NULL
// 挑选编号小的
min_id = wepon[i]->id;
back_wepon = wepon[i];
list_id = i;
}
else if (wepon[i] != NULL && wepon[i]->id == min_id && wepon[i]->use_time == 2) {
// 编号相同,挑选使用次数大的
back_wepon = wepon[i];
list_id = i;
}
}
// 针对wolf的抢夺:其只抢一种类型的武器
if (same_id != -1 && back_wepon != NULL && back_wepon->id != same_id) return NULL;
// 将原有位置置为NULL
if (list_id != -1) {
--wepon_total;
--wepon_kind_num[back_wepon->name];
wepon[list_id] = NULL;
}
return back_wepon;
}
// 更新所拥有的武器的攻击力
void update_wepon_damage() {
for (int i = 0; i < WEPON_MAX_NUM; ++i) {
if (wepon[i] != NULL) {
if (wepon[i]->name == "sword")wepon[i]->damage_value = damage_value * SWORD_DAMAGE;
else if (wepon[i]->name == "bomb")wepon[i]->damage_value = damage_value * BOMB_DAMAGE;
else if (wepon[i]->name == "arrow")wepon[i]->damage_value = damage_value * ARROW_DAMAGE;
}
}
}
// 报告自身拥有的武器情况
void print_wepon_info(int time_now) {
cout << setw(3) << time_now / 60 << ":" << setw(2) << time_now % 60 << " " << color << " " << name << " " << id
<< " has " << wepon_kind_num["sword"] << " sword " << wepon_kind_num["bomb"] << " bomb "
<< wepon_kind_num["arrow"] << " arrow and " << life_value << " elements" << endl;
}
// 更新武器数量
void update_wepon_num() {
wepon_total = 0;
wepon_kind_num["sword"] = 0;
wepon_kind_num["bomb"] = 0;
wepon_kind_num["arrow"] = 0;
for (int i = 0; i < WEPON_MAX_NUM; ++i) {
if (wepon[i] != NULL) {
++wepon_kind_num[wepon[i]->name];
++wepon_total;
}
}
return;
}
// 对所拥有的武器进行冒泡排序(排序同时更新各种武器数量)
void sort_wepon() {
for (int i = WEPON_MAX_NUM - 2; i >= 0; --i) {
for (int j = 0; j <= i; ++j) {
if ((wepon[j] == NULL && wepon[j + 1] != NULL) || (wepon[j] != NULL && wepon[j + 1] != NULL && *wepon[j] > *wepon[j + 1])) {
CWepon* tmp = wepon[j + 1];
wepon[j + 1] = wepon[j];
wepon[j] = tmp;
}
}
}
update_wepon_num();
}
// 对敌人使用武器
void warrior_use_wepon(int& ptr_num, CWarrior* ptr_warrior_victim) {
int first_num = ptr_num;
while (wepon[ptr_num] == NULL) {
++(ptr_num);
if (ptr_num == WEPON_MAX_NUM)ptr_num = 0;
if (ptr_num == first_num) {
// 即没有武器可以使用
return;
}
}
// 使用武器
wepon[ptr_num]->use_self(this, ptr_warrior_victim);
// 判断武器状态
if (wepon[ptr_num]->use_time == 0) {
--(wepon_kind_num[wepon[ptr_num]->name]);
--wepon_total;
delete wepon[ptr_num];
wepon[ptr_num] = NULL;
}
// 下一次将调用下一个编号的武器
++(ptr_num);
if (ptr_num == WEPON_MAX_NUM)ptr_num = 0;
return;
}
// 获胜属性(胜方获得败方的武器,dragon欢呼)
void fight_win(int city_num, int time_now, CWarrior* loser);
// 平局属性(dragon欢呼)
void fight_peace(int city_num, int time_now);
};
// 武士派生类dragon
class CDragon :public CWarrior {
public:
double morale; // 士气
// 构造函数
CDragon(int _id, int _life_value, string _name, string _color,double _morale) :
CWarrior(_id, _life_value, _name, _color), morale(_morale) {
damage_value = WARRIOR_DAMAGE[name];
// 装备初始武器
get_initial_wepon(_id % 3);
}
// 平局或胜利进行欢呼
void dragon_yell(int city_num, int time_now) {
cout << setw(3) << time_now / 60 << ":" << setw(2) << time_now % 60 << " " << color << " " << name
<< " " << id << " yelled in city " << city_num << endl;
}
};
// 武士派生类ninja
class CNinja :public CWarrior {
public:
// 构造函数
CNinja(int _id, int _life_value, string _name, string _color) :
CWarrior(_id, _life_value, _name, _color) {
damage_value = WARRIOR_DAMAGE[name];
// 装备初始武器
get_initial_wepon(_id % 3);
get_initial_wepon((_id + 1) % 3);
}
};
// 武士派生类iceman
class CIceman :public CWarrior {
public:
// 构造函数
CIceman(int _id, int _life_value, string _name, string _color) :
CWarrior(_id, _life_value, _name, _color) {
damage_value = WARRIOR_DAMAGE[name];
get_initial_wepon(_id % 3);
}
// 前进属性
virtual void move_step() {
life_value -= life_value * ICEMAN_LIFE_REDUCE;
}
};
// 武士派生类lion
class CLion :public CWarrior {
public:
int loyalty;
// 构造函数
CLion(int _id, int _life_value, string _name, string _color, int _loyalty) :
CWarrior(_id, _life_value, _name, _color), loyalty(_loyalty) {
damage_value = WARRIOR_DAMAGE[name];
get_initial_wepon(_id % 3);
cout << "Its loyalty is " << loyalty << endl;
}
// 是否逃跑
bool run_away(int time_now) {
if (loyalty <= 0) {
cout << setw(3) << time_now / 60 << ":" << setw(2) << time_now % 60 << " " << color << " " << name << " " << id << " ran away" << endl;
return true;
}
return false;
}
// 前进属性
virtual void move_step() {
loyalty -= LOYALTY_LESS;
}
};
// 武士派生类wolf
class CWolf :public CWarrior {
public:
// 构造函数
CWolf(int _id, int _life_value, string _name, string _color) :
CWarrior(_id, _life_value, _name, _color) {
damage_value = WARRIOR_DAMAGE[name];
}
// 抢夺武器
void grab_wepon(int city_num,int time_now,CWarrior* opponent) {
// 如果对方也是wolf则不抢夺
if (opponent->name == "wolf")return;
// 先抢一件记录name
CWepon* wepon_get = opponent->lose_wepon();
string wepon_name;
if (wepon_get != NULL) {
wepon[wepon_total++] = wepon_get;
++wepon_kind_num[wepon_get->name];
wepon_name = wepon_get->name;
}
else return; // 对手一件武器也没有
// 继续抢夺,grab_num记录抢夺的总数量
int grab_num = 1;
while (wepon_total != WEPON_MAX_NUM) {
wepon_get = opponent->lose_wepon(wepon_get->id);
if (wepon_get != NULL) {
wepon[wepon_total++] = wepon_get;
++wepon_kind_num[wepon_get->name];
++grab_num;
}
else break; // 对手已经没有武器可抢夺或者抢夺的武器不是最小编号
}
// 更新拥有的武器攻击力
update_wepon_damage();
// 输出抢夺结果
cout << setw(3) << time_now / 60 << ":" << setw(2) << time_now % 60 << " " << color << " " << name << " "
<< id << " took " << grab_num << " " << wepon_name << " from " << opponent->color
<< " " << opponent->name << " " << opponent->id << " in city " << city_num << endl;
return;
}
};
// 城市类
class CCity {
public:
CWarrior* ptr_warrior_red; // 位于该城市的红方武士指针
CWarrior* ptr_warrior_red_tmp; // 辅助红武士移动的指针
CWarrior* ptr_warrior_blue; // 位于该城市的蓝方武士指针
// 构造函数:初始化三个指针都为空
CCity() :ptr_warrior_red(NULL), ptr_warrior_blue(NULL), ptr_warrior_red_tmp(NULL) {}
// 析构函数
~CCity() {
if (ptr_warrior_red != NULL)delete ptr_warrior_red;
if (ptr_warrior_blue != NULL)delete ptr_warrior_blue;
}
};
// 司令部类
class CHeadquarter {
public:
string color; // 所属派别
int make_num; // 下一个要制造的武士编号
int total_num; // 拥有的武士总数
int life_element; // 生命元总数
map<string, int>warrior_num; // 各种武士的数量
string make_sort[WARRIOR_KIND_NUM]; // 制造武士的顺序
// 构造函数
CHeadquarter(string _color, int _life_element) :color(_color), life_element(_life_element), make_num(0), total_num(0) {
for (int i = 0; i < WARRIOR_KIND_NUM; ++i) {
if (_color == "red")make_sort[i] = RED_MAKE_SORT[i];
else if (_color == "blue")make_sort[i] = BLUE_MAKE_SORT[i];
warrior_num[WARRIOR_CIN_SORT[i]] = 0;
}
}
// 报告自身拥有的生命元数量
void print_element_info(int time_now) {
cout << setw(3) << time_now / 60 << ":" << setw(2) << time_now % 60 << " " << life_element
<< " elements in " << color << " headquarter" << endl;
}
// 制造武士并投放城市
bool make_warrior(int time_now,CCity* ptr_city_list) {
using FUNC_PTR = CWarrior * (CHeadquarter::*)(int);
map<string, FUNC_PTR> make_warrior_map = {
{"dragon",&CHeadquarter::make_warrior_dragon},
{"ninja",&CHeadquarter::make_warrior_ninja},
{"iceman",&CHeadquarter::make_warrior_iceman},
{"lion",&CHeadquarter::make_warrior_lion},
{"wolf",&CHeadquarter::make_warrior_wolf}
};
// 尝试制造的武士种类和所需要的生命值
string name = make_sort[make_num];
int life_need = WARRIOR_LIFE[name];
if (life_element >= life_need) {
// 更新制造后司令部的状态
life_element -= life_need;
++total_num;
++warrior_num[name];
if (++make_num == WARRIOR_KIND_NUM)make_num = 0;
// 输出制造信息
cout << setw(3) << time_now / 60 << ":" << setw(2) << time_now % 60 << " " << color
<< " " << name << " "<< total_num << " born" << endl;
// 制造武士并投放城市
CWarrior* ptr_warrior = (this->*make_warrior_map[name])(life_need);
if (color == "red") {
ptr_city_list[0].ptr_warrior_red = ptr_warrior;
}
else ptr_city_list[CITY_NUM + 1].ptr_warrior_blue = ptr_warrior;
// 制造成功
return true;
}
// 制造失败
return false;
}
// 制造武士wolf
CWarrior* make_warrior_wolf(int life_need) {
CWarrior* ptr_wolf = new CWolf(total_num, life_need, "wolf", color);
return ptr_wolf;
}
// 制造武士lion
CWarrior* make_warrior_lion(int life_need) {
int loyalty = life_element;
CWarrior* ptr_lion = new CLion(total_num, life_need, "lion", color, loyalty);
return ptr_lion;
}
// 制造武士iceman
CWarrior* make_warrior_iceman(int life_need) {
CWarrior* ptr_iceman = new CIceman(total_num, life_need, "iceman", color);
return ptr_iceman;
}
// 制造武士ninja
CWarrior* make_warrior_ninja(int life_need) {
CWarrior* ptr_ninja = new CNinja(total_num, life_need, "ninja", color);
return ptr_ninja;
}
// 制造武士dragon
CWarrior* make_warrior_dragon(int life_need) {
double morale = (double)life_element / life_need;
CWarrior* ptr_dragon = new CDragon(total_num, life_need, "dragon", color, morale);
return ptr_dragon;
}
};
// sword造成的伤害属性
void CSword::use_self(CWarrior* warrior_use, CWarrior* warrior_victim) {
warrior_victim->life_value -= damage_value;
}
// bomb造成伤害属性
void CBomb::use_self(CWarrior* warrior_use, CWarrior* warrior_victim) {
warrior_victim->life_value -= damage_value;
if (warrior_use->name != "ninja") {
// ninja使用bomb不会对自身造成伤害
warrior_use->life_value -= damage_value * 1 / 2;
}
--use_time;
return;
}
// arrow造成的伤害
void CArrow::use_self(CWarrior* warrior_use, CWarrior* warrior_victim) {
warrior_victim->life_value = warrior_victim->life_value - damage_value;
--use_time;
return;
}
// 战士在战斗中取得胜利
void CWarrior::fight_win(int city_num, int time_now, CWarrior* loser) {
// 胜方获得败方的武器(先对自身武器进行排序)
sort_wepon();
CWepon* wepon_get = NULL;
while (wepon_total != WEPON_MAX_NUM) {
wepon_get = loser->lose_wepon();
if (wepon_get != NULL) {
wepon[wepon_total++] = wepon_get;
++wepon_kind_num[wepon_get->name];
}
else break; // 对方已无武器可抢
}
// 更新拥有的武器攻击力
update_wepon_damage();
// 如果是dragon则进行欢呼
if (name == "dragon") {
CDragon* ptr_dragon = dynamic_cast<CDragon*>(this);
ptr_dragon->dragon_yell(city_num, time_now);
}
return;
}
// 战士在战斗中以平局告终
void CWarrior::fight_peace(int city_num, int time_now) {
if (name == "dragon") {
CDragon* ptr_dragon = dynamic_cast<CDragon*>(this);
ptr_dragon->dragon_yell(city_num, time_now);
}
// 对自身武器进行排序
sort_wepon();
return;
}
// 接收输入,初始化信息
void cin_data() {
// 接收生命元、城市、忠诚度变化、时间范围值
cin >> LIFE_ELEMENT >> CITY_NUM >> LOYALTY_LESS >> TIME_NUM;
// 接收每种武士的生命值
int life_value;
for (int i = 0; i < WARRIOR_KIND_NUM; ++i) {
cin >> life_value;
WARRIOR_LIFE[WARRIOR_CIN_SORT[i]] = life_value;
}
// 接收每种武士的攻击力
int warrior_damage;
for (int i = 0; i < WARRIOR_KIND_NUM; ++i) {
cin >> warrior_damage;
WARRIOR_DAMAGE[WARRIOR_CIN_SORT[i]] = warrior_damage;
}
return;
}
// 城市中符合逃跑要求的lion逃跑
void lion_ran(int city_num, int time_now, CCity* ptr_city_list) {
// 同一个城市中,先判断红方再判断蓝方
CWarrior* warrior_red = ptr_city_list[city_num].ptr_warrior_red;
CWarrior* warrior_blue = ptr_city_list[city_num].ptr_warrior_blue;
if (warrior_red != NULL && warrior_red->name == "lion") {
CLion* lion_red = dynamic_cast<CLion*>(warrior_red);
if (lion_red->run_away(time_now)) {
delete lion_red;
ptr_city_list[city_num].ptr_warrior_red = NULL;
}
}
if (warrior_blue != NULL && warrior_blue->name == "lion") {
CLion* lion_blue = dynamic_cast<CLion*>(warrior_blue);
if (lion_blue->run_away(time_now)) {
delete lion_blue;
ptr_city_list[city_num].ptr_warrior_blue = NULL;
}
}
return;
}
// 输出进军信息
int print_march_info(int i, int time_now, CWarrior* ptr_warrior) {
// 触发武士前进特性
ptr_warrior->move_step();
// 判断司令部情况
if (ptr_warrior->color == "blue" && i == 0) {
// 占领红方司令部
cout << setw(3) << time_now / 60 << ":" << setw(2) << time_now % 60 << " " << ptr_warrior->color << " " << ptr_warrior->name
<< " " << ptr_warrior->id << " reached red headquarter with " << ptr_warrior->life_value
<< " elements and force " << ptr_warrior->damage_value << endl;
return -1;
}
else if (ptr_warrior->color == "red" && i == CITY_NUM + 1) {
// 占领蓝方司令部
cout << setw(3) << time_now / 60 << ":" << setw(2) << time_now % 60 << " " << ptr_warrior->color << " " << ptr_warrior->name
<< " " << ptr_warrior->id << " reached blue headquarter with " << ptr_warrior->life_value
<< " elements and force " << ptr_warrior->damage_value << endl;
return 1;
}
// 双方司令部还未被占领
cout << setw(3) << time_now / 60 << ":" << setw(2) << time_now % 60 << " " << ptr_warrior->color << " " << ptr_warrior->name
<< " " << ptr_warrior->id << " marched to city " << i << " with " << ptr_warrior->life_value
<< " elements and force " << ptr_warrior->damage_value << endl;
return 0;
}
// 双方士兵前进,返回值:-1红方被占,0双方未被占,1蓝方被占
int march_city(int i, int time_now, CCity* ptr_city_list) {
int result = 0;
// 因为武士前进的事件发生在目的地,因此这里应该先判断蓝方
if (ptr_city_list[i + 1].ptr_warrior_blue != NULL) {
// 蓝方武士向西前进
ptr_city_list[i].ptr_warrior_blue = ptr_city_list[i + 1].ptr_warrior_blue;
ptr_city_list[i + 1].ptr_warrior_blue = NULL;
// 输出前进信息,判断司令部死否被占领
CWarrior* ptr_warrior = ptr_city_list[i].ptr_warrior_blue;
int tmp_result = print_march_info(i, time_now, ptr_warrior);
if (tmp_result == -1) {
// 输出红方被占领
result = -1;
cout << setw(3) << time_now / 60 << ":" << setw(2) << time_now % 60 << " red headquarter was taken" << endl;
// 这里千万不能直接return result,这样会使得假如红司令部有武士要前进到city1则得不到输出
}
}
if (ptr_city_list[i].ptr_warrior_red_tmp != NULL) {
// 有红方武士向东前进
ptr_city_list[i + 1].ptr_warrior_red = ptr_city_list[i].ptr_warrior_red_tmp;
ptr_city_list[i].ptr_warrior_red_tmp = NULL;
// 输出前进信息,判断司令部死否被占领,其到达的城市编号是i+1
CWarrior* ptr_warrior = ptr_city_list[i + 1].ptr_warrior_red;
int tmp_result = print_march_info(i + 1, time_now, ptr_warrior);
if (tmp_result == 1) {
// 输出蓝方被占领
result = 1;
cout << setw(3) << time_now / 60 << ":" << setw(2) << time_now % 60 << " blue headquarter was taken" << endl;
}
}
return result;
}
// 在有wolf及其敌人的城市wolf抢夺对方的武器
void wolf_grab_wepon(int city_num, int time_now, CCity* ptr_city_list) {
CWarrior* warrior_red = ptr_city_list[city_num].ptr_warrior_red;
CWarrior* warrior_blue = ptr_city_list[city_num].ptr_warrior_blue;
if (warrior_red != NULL && warrior_red->name == "wolf" && warrior_blue!=NULL) {
CWolf* wolf_red = dynamic_cast<CWolf*>(warrior_red);
wolf_red->grab_wepon(city_num, time_now, warrior_blue);
}
if (warrior_blue != NULL && warrior_blue->name == "wolf" && warrior_red != NULL) {
CWolf* wolf_blue = dynamic_cast<CWolf*>(warrior_blue);
wolf_blue->grab_wepon(city_num, time_now, warrior_red);
}
return;
}
// 战斗是否继续,true继续,false结束战斗
bool fight_on(CWarrior* ptr_warrior_red, CWarrior* ptr_warrior_blue) {
// 红或蓝方阵亡或双方均阵亡
if (ptr_warrior_red->life_value <= 0 || ptr_warrior_blue->life_value <= 0) {
return false;
}
// 红蓝方均无武器
if (ptr_warrior_red->wepon_total == 0 && ptr_warrior_blue->wepon_total == 0) {
return false;
}
// 红方只有攻击力为0的sword且蓝方无武器
if (ptr_warrior_red->wepon_total != 0 && ptr_warrior_red->wepon_total == ptr_warrior_red->wepon_kind_num["sword"]) {
if (ptr_warrior_red->damage_value < 5 && ptr_warrior_blue->wepon_total == 0) {
return false;
}
}
// 蓝方只有攻击力为0的sword且红方无武器
if (ptr_warrior_blue->wepon_total != 0 && ptr_warrior_blue->wepon_total == ptr_warrior_blue->wepon_kind_num["sword"]) {
if (ptr_warrior_blue->damage_value < 5 && ptr_warrior_red->wepon_total == 0) {
return false;
}
}
// 红蓝双方都只有攻击力为0的sword
if (ptr_warrior_red->wepon_total != 0 && ptr_warrior_red->wepon_total == ptr_warrior_red->wepon_kind_num["sword"] && ptr_warrior_red->damage_value < 5) {
if (ptr_warrior_blue->wepon_total != 0 && ptr_warrior_blue->wepon_total == ptr_warrior_blue->wepon_kind_num["sword"] && ptr_warrior_blue->damage_value < 5) {
return false;
}
}
// 否则战斗继续
return true;
}
// 胜方获得武器,报告战斗情况,清扫战场
void fight_end(int city_num, int time_now, CWarrior* ptr_warrior_red, CWarrior* ptr_warrior_blue, CCity* ptr_city_list) {
if (ptr_warrior_red->life_value > 0 && ptr_warrior_blue->life_value <= 0) {
// 红方获胜
cout << setw(3) << time_now / 60 << ":" << setw(2) << time_now % 60 << " red " << ptr_warrior_red->name << " "
<< ptr_warrior_red->id << " killed blue " << ptr_warrior_blue->name << " " << ptr_warrior_blue->id
<< " in city " << city_num << " remaining " << ptr_warrior_red->life_value << " elements" << endl;
ptr_warrior_red->fight_win(city_num, time_now, ptr_warrior_blue);
ptr_city_list[city_num].ptr_warrior_blue = NULL;
return;
}
// 蓝方获胜
if (ptr_warrior_blue->life_value > 0 && ptr_warrior_red->life_value <= 0) {
cout << setw(3) << time_now / 60 << ":" << setw(2) << time_now % 60 << " blue " << ptr_warrior_blue->name << " "
<< ptr_warrior_blue->id << " killed red " << ptr_warrior_red->name << " " << ptr_warrior_red->id
<< " in city " << city_num << " remaining " << ptr_warrior_blue->life_value << " elements" << endl;
// 获取武器,释放战败方指针
ptr_warrior_blue->fight_win(city_num, time_now, ptr_warrior_red);
// 若dragon存活则欢呼
ptr_city_list[city_num].ptr_warrior_red = NULL;
return;
}
// 红蓝方均存活
if (ptr_warrior_red->life_value > 0 && ptr_warrior_blue->life_value > 0) {
cout << setw(3) << time_now / 60 << ":" << setw(2) << time_now % 60 << " both red " << ptr_warrior_red->name << " "
<< ptr_warrior_red->id << " and blue " << ptr_warrior_blue->name << " " << ptr_warrior_blue->id
<< " were alive in city " << city_num << endl;
ptr_warrior_red->fight_peace(city_num, time_now);
ptr_warrior_blue->fight_peace(city_num, time_now);
return;
}
// 红蓝方均阵亡
if (ptr_warrior_red->life_value <= 0 && ptr_warrior_blue->life_value <= 0) {
cout << setw(3) << time_now / 60 << ":" << setw(2) << time_now % 60 << " both red " << ptr_warrior_red->name << " "
<< ptr_warrior_red->id << " and blue " << ptr_warrior_blue->name << " " << ptr_warrior_blue->id
<< " died in city " << city_num << endl;
delete ptr_city_list[city_num].ptr_warrior_red;
delete ptr_city_list[city_num].ptr_warrior_blue;
ptr_city_list[city_num].ptr_warrior_red = NULL;
ptr_city_list[city_num].ptr_warrior_blue = NULL;
return;
}
}
// 在有两个武士的城市发生战斗
void warrior_fight(int city_num, int time_now, CCity* ptr_city_list) {
CWarrior* ptr_warrior_red = ptr_city_list[city_num].ptr_warrior_red;
CWarrior* ptr_warrior_blue = ptr_city_list[city_num].ptr_warrior_blue;
if (ptr_warrior_red != NULL && ptr_warrior_blue != NULL) {
// 双方先对武器进行排序
ptr_warrior_red->sort_wepon();
ptr_warrior_blue->sort_wepon();
int red_use_num = 0, blue_use_num = 0;
// 进行战斗
while (fight_on(ptr_warrior_red,ptr_warrior_blue)) {
if (city_num % 2 == 1) {
// 奇数编号城市红武士先发起进攻
ptr_warrior_red->warrior_use_wepon(red_use_num, ptr_warrior_blue);
if (ptr_warrior_red->life_value <= 0 || ptr_warrior_blue->life_value <= 0)break;
ptr_warrior_blue->warrior_use_wepon(blue_use_num, ptr_warrior_red);
}
else {
// 偶数编号城市蓝武士先发起进攻
ptr_warrior_blue->warrior_use_wepon(blue_use_num, ptr_warrior_red);
if (ptr_warrior_red->life_value <= 0 || ptr_warrior_blue->life_value <= 0)break;
ptr_warrior_red->warrior_use_wepon(red_use_num, ptr_warrior_blue);
}
}
// 处理战后并报告战斗情况
fight_end(city_num, time_now, ptr_warrior_red, ptr_warrior_blue, ptr_city_list);
}
return;
}
// 开战
void make_war(int case_num) {
// 输入并初始化信息
cin_data();
// 输出测试样例组号
cout << setfill('0') << "Case " << case_num << ":" << endl;
// 创建红蓝司令部和城市,将两军司令部也重新算做城市
CHeadquarter red_quarter("red", LIFE_ELEMENT), blue_quarter("blue", LIFE_ELEMENT);
CCity* ptr_city_list = new CCity[CITY_NUM + 2];
bool red_can = true, blue_can = true;
// 执行事件
int time_now = 0;
while (time_now <= TIME_NUM) {
if (time_now % 60 == 0) {
// 武士降生
if (red_can)red_can = red_quarter.make_warrior(time_now, ptr_city_list);
if (blue_can)blue_can = blue_quarter.make_warrior(time_now, ptr_city_list);
time_now += 5;
if (time_now > TIME_NUM)break;
}
if (time_now % 60 == 5) {
// 城市中包含己军司令部中忠诚度不大于0的liontaop
for (int i = 0; i < CITY_NUM + 2; ++i) {
lion_ran(i, time_now, ptr_city_list);
}
time_now += 5;
if (time_now > TIME_NUM)break;
}
if (time_now % 60 == 10) {
// 武士前进到某一城市
bool one_win = false;
for (int i = 0; i < CITY_NUM + 1; ++i) {
// 先将红五十指针移动到辅助位置
ptr_city_list[i].ptr_warrior_red_tmp = ptr_city_list[i].ptr_warrior_red;
ptr_city_list[i].ptr_warrior_red = NULL;
}
for (int i = 0; i < CITY_NUM + 1; ++i) {
// march_city返回-1表示红方被占领,0表示双方未被占领,1表示蓝方被占领
int march_result = march_city(i, time_now, ptr_city_list);
if (march_result != 0)one_win = true;
}
// 因为和司令部被占领同时发生的事件,因此有司令部被占领也不要立即退出循环
if (one_win)return;
time_now += 25;
if (time_now > TIME_NUM)break;
}
if (time_now % 60 == 35) {
// 在有wolf及其敌人的地方,wolf要抢夺对方的武器
for (int i = 1; i < CITY_NUM + 1; ++i) {
wolf_grab_wepon(i, time_now, ptr_city_list);
}
time_now += 5;
if (time_now > TIME_NUM)break;
}
if (time_now % 60 == 40) {
// 在有两个武士的城市,发生战斗
for (int i = 1; i < CITY_NUM + 1; ++i) {
warrior_fight(i, time_now, ptr_city_list);
}
time_now += 10;
if (time_now > TIME_NUM)break;
}
if (time_now % 60 == 50) {
// 司令部报告拥有的生命元数量
red_quarter.print_element_info(time_now);
blue_quarter.print_element_info(time_now);
time_now += 5;
if (time_now > TIME_NUM)break;
}
if (time_now % 60 == 55) {
// 所有武士报告自身情况
for (int i = 1; i < CITY_NUM + 1; ++i) {
if (ptr_city_list[i].ptr_warrior_red != NULL)ptr_city_list[i].ptr_warrior_red->print_wepon_info(time_now);
if (ptr_city_list[i].ptr_warrior_blue != NULL)ptr_city_list[i].ptr_warrior_blue->print_wepon_info(time_now);
}
time_now += 5;
if (time_now > TIME_NUM)break;
}
}
delete[] ptr_city_list;
return;
}
int main() {
// 接收测试样例数
int case_total, case_num = 0;
cin >> case_total;
while (case_num != case_total) {
++case_num;
make_war(case_num);
}
return 0;
}