魔兽世界之三:开战(北京大学MOOC 程序设计与算法(三) C++面向对象程序设计)

题目来源:

北京大学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个蓝武士和一个红武士),就会发生战斗。战斗的规则是:

  1. 在奇数编号城市,红武士先发起攻击

  2. 在偶数编号城市,蓝武士先发起攻击

  3. 战斗开始前,双方先对自己的武器排好使用顺序,然后再一件一件地按顺序使用。编号小的武器,排在前面。若有多支arrow,用过的排在前面。排好序后,攻击者按此排序依次对敌人一件一件地使用武器。如果一种武器有多件,那就都要用上。每使用一件武器,被攻击者生命值要减去武器攻击力。如果任何一方生命值减为0或小于0即为死去。有一方死去,则战斗结束。

  4. 双方轮流使用武器,甲用过一件,就轮到乙用。某一方把自己所有的武器都用过一轮后,就从头开始再用一轮。如果某一方没有武器了,那就挨打直到死去或敌人武器用完。武器排序只在战斗前进行,战斗中不会重新排序。

  5. 如果双方武器都用完且都还活着,则战斗以平局结束。如果双方都死了,也算平局。

  6. 有可能由于武士自身攻击力太低,而导致武器攻击力为0。攻击力为0的武器也要使用。如果战斗中双方的生命值和武器的状态都不再发生变化,则战斗结束,算平局。

  7. 战斗的胜方获得对方手里的武器。武士手里武器总数不超过10件。缴获武器时,按照武器种类编号从小到大缴获。如果有多件arrow,优先缴获没用过的。

  8. 如果战斗开始前双方都没有武器,则战斗视为平局。如果先攻击方没有武器,则由后攻击方攻击。

不同的武士有不同的特点。

编号为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;
}

  • 7
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值