C++ 魔兽世界之二:装备

总时间限制: 1000ms 内存限制: 65536kB
描述
魔兽世界的西面是红魔军的司令部,东面是蓝魔军的司令部。两个司令部之间是依次排列的若干城市。

红司令部,City 1,City 2,……,City n,蓝司令部

两军的司令部都会制造武士。武士一共有 dragon 、ninja、iceman、lion、wolf 五种。每种武士都有编号、生命值这两种属性。
有的武士可以拥有武器。武器有三种,sword, bomb,和arrow,编号分别为0,1,2。
双方的武士编号都是从1开始计算。红方制造出来的第 n 个武士,编号就是n。同样,蓝方制造出来的第 n 个武士,编号也是n。

不同的武士有不同的特点。
dragon 可以拥有一件武器。编号为n的dragon降生时即获得编号为 n%3 的武器。dragon还有“士气”这个属性,是个浮点数,其值为它降生后其司令部剩余生命元的数量除以造dragon所需的生命元数量。
ninja可以拥有两件武器。编号为n的ninja降生时即获得编号为 n%3 和 (n+1)%3的武器。
iceman有一件武器。编号为n的iceman降生时即获得编号为 n%3 的武器。
lion 有“忠诚度”这个属性,其值等于它降生后其司令部剩余生命元的数目。
wolf没特点。
请注意,在以后的题目里,武士的士气,生命值,忠诚度在其生存期间都可能发生变化,都有作用,武士手中的武器随着使用攻击力也会发生变化。

武士在刚降生的时候有一个生命值。

在每个整点,双方的司令部中各有一个武士降生。

红方司令部按照 iceman、lion、wolf、ninja、dragon 的顺序循环制造武士。

蓝方司令部按照 lion、dragon、ninja、iceman、wolf 的顺序循环制造武士。

制造武士需要生命元。

制造一个初始生命值为 m 的武士,司令部中的生命元就要减少 m 个。

如果司令部中的生命元不足以制造某个按顺序应该制造的武士,那么司令部就试图制造下一个。如果所有武士都不能制造了,则司令部停止制造武士。
给定一个时间,和双方司令部的初始生命元数目,要求你将从0点0分开始到双方司令部停止制造武士为止的所有事件按顺序输出。
一共有两种事件,其对应的输出样例如下:

  1. 武士降生
    输出样例: 004 blue lion 5 born with strength 5,2 lion in red headquarter
    表示在 4点整,编号为5的蓝魔lion武士降生,它降生时生命值为5,降生后蓝魔司令部里共有2个lion武士。(为简单起见,不考虑单词的复数形式)注意,每制造出一个新的武士,都要输出此时司令部里共有多少个该种武士。
    如果造出的是dragon,那么还要输出一行,例:
    It has a arrow,and it’s morale is 23.34
    表示该dragon降生时得到了arrow,其士气是23.34(为简单起见,本题中arrow前面的冠词用a,不用an,士气精确到小数点后面2位,四舍五入)
    如果造出的是ninja,那么还要输出一行,例:
    It has a bomb and a arrow
    表示该ninja降生时得到了bomb和arrow。
    如果造出的是iceman,那么还要输出一行,例:
    It has a sword
    表示该iceman降生时得到了sword。
    如果造出的是lion,那么还要输出一行,例:
    It’s loyalty is 24
    表示该lion降生时的忠诚度是24。
  2. 司令部停止制造武士
    输出样例: 010 red headquarter stops making warriors
    表示在 10点整,红方司令部停止制造武士

输出事件时:

首先按时间顺序输出;

同一时间发生的事件,先输出红司令部的,再输出蓝司令部的。

输入
第一行是一个整数,代表测试数据组数。

每组测试数据共两行。

第一行,一个整数M。其含义为: 每个司令部一开始都有M个生命元( 1 <= M <= 10000)

第二行:五个整数,依次是 dragon 、ninja、iceman、lion、wolf 的初始生命值。它们都大于0小于等于10000
输出
对每组测试数据,要求输出从0时0分开始,到双方司令部都停止制造武士为止的所有事件。
对每组测试数据,首先输出“Case:n" n是测试数据的编号,从1开始
接下来按恰当的顺序和格式输出所有事件。每个事件都以事件发生的时间开头,时间以小时为单位,有三位。
样例输入

1
20
3 4 5 6 7

样例输出

Case:1
000 red iceman 1 born with strength 5,1 iceman in red headquarter
It has a bomb
000 blue lion 1 born with strength 6,1 lion in blue headquarter
It's loyalty is 14
001 red lion 2 born with strength 6,1 lion in red headquarter
It's loyalty is 9
001 blue dragon 2 born with strength 3,1 dragon in blue headquarter
It has a arrow,and it's morale is 3.67
002 red wolf 3 born with strength 7,1 wolf in red headquarter
002 blue ninja 3 born with strength 4,1 ninja in blue headquarter
It has a sword and a bomb
003 red headquarter stops making warriors
003 blue iceman 4 born with strength 5,1 iceman in blue headquarter
It has a bomb
004 blue headquarter stops making warriors

相比较备战,这次的武士多出了个性,故每种武士不单单是一个名字,需要从武士类派生定制个性;
需要在派生出的武士类中添加该派生类的武器即可。

武士 分为5种
武器 分为 swor、bomb 、arrow 三种

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
using namespace std;
#define WARRIOR_NUM 5      //武士数
#define WEAPON_NUM 3      //武器数 
#define MAX_WARRIORS 1000      //武士最大数量

enum { DRAGON,NINJA,ICEMAN,LION,WOLF};  //枚举,即dragon=0,ninja=1,2,3,4 

武器类的定义
武器有序号——0-2
武器有攻击力——本题未定义
静态变量——与武器类相关的全局变量,分别为武器的攻击力列表,武器名字的列表
均可由武器的序号得到

class CWeapon
{
	public:
		int nKindNo;   //序号 
		int nForce;      //攻击力
		static int InitialForce[WEAPON_NUM];      //武器初始攻击力列表 
		static const char *Names[WEAPON_NUM];     //武器名字的列表 
};

武士类的定义
武士的属性:所属司令部颜色,所拥有生命值,所拥有武器,种类名,序号
武士的制造顺序与基地的颜色有关
武士的制造结束与基地的生命值有关
故需要指向基地的指针,得到基地的有关参数

class CHeadquarter;         //声明司令类
class CWarrior{        
	protected:                       //保护,派生可以访问当前对象的protect内容 
		CHeadquarter *pHeadquarter;  //指向该武士基地的指针,用于得到基地的颜色,基地的生命值  
		int nNo;                     //武士的编号,用于武士计数 
	public:
		static const char*Names[WARRIOR_NUM];     //静态数组——武士名字
		static int InitialLifeValue[WARRIOR_NUM]; //静态数组——每种武士的初始生命值
		CWarrior(CHeadquarter * p, int nNo_);     //武士构造函数——输入基地指针,武士编号
		virtual void PrintResult(int nTime,int nKindNo);  //虚函数——输出函数——此为通用输出函数 
		virtual void PrintResult(int nTime) =0;      //虚函数——输出函数———此为派生类的个性输出函数
		virtual ~CWarrior(){}        //虚函数——析构函数 
}; 

司令类的定义
司令类的有颜色和生命值两个属性;

为输出服务的成员:
为判断能否继续生产武士,添加stop成员;
要输出每种武士的个数,故需要anWarriorNum列表,记录每种武士的个数;
需要确定当前制造武士的种类,可由武士总数/循环个数得出;
需要列表保存以生产的每一个武士,方便进行后续处理;

class CHeadquarter   //定义司令部 
{
	private:
		int nTotalLifeValue;        //基地总生命值 
		bool bStopped;             //是否停止制造 
		int nColor;                //基地颜色 
		int nCurMakingSeqIdx;     //当前正在制造的武士序列号
		int anWarriorNum[WARRIOR_NUM];        //每种武士的数量 
		int nTotalWarriorNum;                 //总武士数量 
		CWarrior * pWarriors[MAX_WARRIORS];    
	public:
		friend class CWarrior;          //友元武士,武士类可访问司令类private 
		static int MakingSeq[2][WARRIOR_NUM];      //制作顺序表,
		void Init(int nColor_, int lv);       //声明初始函数——颜色,生命值
		~CHeadquarter();					     //声明析构函数
		int Produce(int nTime);  //声明生产函数,需要输入当前时间
		void GetColor(char * szColor);  //声明函数,得到当前基地的颜色 
		int GetTotalLifeValue() { return nTotalLifeValue;}    //声明函数,得到当前基地的生命值 
};

派生类的定义

class CDragon:public CWarrior{   //武士派生
//dragon 拥有武器和士气 
//武器:编号为n%3,n为dragon的编号 
//士气:降生后司令部剩余生命元的数量除以造dragon所需的生命元数量,double类型
	 private:
	 	CWeapon wp;        //武器 
	 	double fmorale;    //忠诚度
	public:
		void Countmorale()
		{   			//指向司令部的指针——得到司令部的生命值 
			fmorale = pHeadquarter -> GetTotalLifeValue()/(double)CWarrior::InitialLifeValue[0];  
			//序号0为dragon 
		 } 
		 
		 CDragon( CHeadquarter *p, int nNo_): CWarrior(p,nNo_){     
		 //初始构造函数,基类有的与基类相同 
		 	wp.nKindNo = nNo % WEAPON_NUM;                    //武器种类构造 
		 	wp.nForce = CWeapon::InitialForce[wp.nKindNo];    //攻击力数值构造 
		 	Countmorale();                                   //士气构造 
		 }
		 void PrintResult(int nTime)        //虚函数
		 {
		 	CWarrior::PrintResult(nTime,DRAGON);        //调用基类的printresult 
		 	printf("It has a %s,and it's morale is %.2f\n",CWeapon::Names[wp.nKindNo],fmorale);  
		 	//Dragon类特有的输出 
		 }
}; 
class CNinja:public CWarrior
{
	private:
		CWeapon wps[2];        //派生出2把武器 
	public:
		CNinja(CHeadquarter *p, int nNo_): CWarrior(p,nNo_)     //得到基类的构造 
		{  //添加武器的构造方法 
			wps[0].nKindNo=nNo%WEAPON_NUM;                       //确定武器序号 
			wps[0].nForce = CWeapon::InitialForce[wps[0].nKindNo];  //确定武器攻击力 
			
			wps[1].nKindNo=(nNo+1)%WEAPON_NUM;
			wps[1].nForce = CWeapon::InitialForce[wps[1].nKindNo];    //武器类里的该种武器的攻击力     
		}
		void PrintResult(int nTime)      //输出函数 
		{
			CWarrior::PrintResult(nTime,NINJA);      
			//此处NINJA为开头的序号 ,先调用武士类的print函数 
			printf("It has a %s and a %s\n",CWeapon::Names[wps[0].nKindNo],CWeapon::Names[wps[1].nKindNo]);
			//再输出两把武器的名字 
			}	
 };
class CIceman:public CWarrior{
	private:
		CWeapon wp;
	public:
		CIceman(CHeadquarter * p, int nNo_):CWarrior(p,nNo_)  //构造函数
		{
			wp.nKindNo=nNo % WEAPON_NUM;
			wp.nForce=CWeapon::InitialForce[wp.nKindNo];
		 } 
		 void PrintResult(int nTime)
		 {
		 	CWarrior::PrintResult(nTime,ICEMAN);
		 	printf("It has a %s\n",CWeapon::Names[wp.nKindNo]);    //输出该武士的武器 
		 }
};
class CLion:public CWarrior
{
	private:
		int nLoyalty;         //忠诚度
	public:
		void CountLoyalty()   //定义函数,得到nloyalty 
		{
			nLoyalty=pHeadquarter->GetTotalLifeValue();
		 } 
		 CLion(CHeadquarter *p, int nNo_):CWarrior(p,nNo_){    //构造函数——调用父类 
		 	CountLoyalty();      //赋值nloyalty 
		 } 
		void PrintResult(int nTime)
		{
			CWarrior::PrintResult(nTime,LION);
			CountLoyalty();
			printf("It's loyalty is %d\n",nLoyalty);
		}
};
class CWolf:public CWarrior{
	public:
		CWolf(CHeadquarter *p, int nNo_): CWarrior(p,nNo_){}      //构造函数,与父类完全相同     
		void PrintResult(int nTime)     
		{
			CWarrior::PrintResult(nTime,WOLF);   //print函数,与父类相同 
		}
}; 

补充武士类的内部函数
1.构造函数

CWarrior::CWarrior(CHeadquarter *p,int nNo_)       //武士类构造函数 
{
	nNo=nNo_;
	pHeadquarter =p;
}

2.输出函数
制造该武士的时间
输出该武士的司令部颜色
武士的序号,
武士的种类,
武士种类的个数——该属性保存司令部中
武士的生命值;

void CWarrior::PrintResult(int nTime, int nKindNo)     //双参数的武士类print函数 
{											//要输出的时间数,武士的种类 
	char szColor[20];       
	pHeadquarter->GetColor(szColor);       //得到当前司令部颜色,防暑szColor中 
	printf("%03d %s %s %d born with strength %d,%d %s in %s headquarter\n",
			nTime,szColor,Names[nKindNo],nNo,InitialLifeValue[nKindNo],pHeadquarter->anWarriorNum[nKindNo],Names[nKindNo],szColor);
}

补充司令部的内部函数
1.司令部初始化函数

void CHeadquarter::Init(int nColor_, int lv)     //司令部初始化函数 
{
	nColor= nColor_;
	nTotalLifeValue = lv;
	
	bStopped = false;    
	nCurMakingSeqIdx=0;   
	nTotalWarriorNum=0;                 
	for(int i=0;i<WARRIOR_NUM;i++)
		anWarriorNum[i]=0; 
}

2.司令部析构函数
因pWarrior为动态数组,结束后需要全部释放

CHeadquarter::~CHeadquarter(){       //司令部析构函数 
	int i;
	for (i=0;i<nTotalWarriorNum;i++)
		delete pWarriors[i];            //删除武士类列表的信息 
}

3.制造函数
用于判断能否制造武士,和输出制造出的武士
先判断停止条件——每一个武士都无法制造
(1)当前武士无法制造,则看下一个武士能否制造,直到看完全部武士
(2)跳出上述循环,依旧无法制造,则返回停止
(3)上述条件不满足,说明可以制造,则开始制造
制造武士
(1)确定武士种类——通过curMakingSeqIdx得到当前制造武士的种类
(2)由种类确定武士生命值,由武士总数确定当前武士序号,由每种武士个数确定武士的种内序号
(3)基地生命值-=武士生命值
(4)为制造下一个武士做准备
(5)将当前武士保存至勇士列表,利用多态性质调用每种武士的输出函数;

int CHeadquarter::Produce(int nTime)     //制造函数
{
	int nSearchingTimes=0;
	 if(bStopped)       //停止标记 
	 	return 0;
	while(CWarrior::InitialLifeValue[MakingSeq[nColor][nCurMakingSeqIdx]]>nTotalLifeValue
	&& nSearchingTimes<WARRIOR_NUM)   //当前正在造的武士(由基地颜色和制造序号确定)生命值大于基地生命值 
	{   //且未遍历完每一个武士 
		nCurMakingSeqIdx=(nCurMakingSeqIdx+1)%WARRIOR_NUM;
		nSearchingTimes ++;              //查找次数也+1——到5个后停止查找并弹出结束 
	}  
	//跳出上述循环时 
	int nKindNo=MakingSeq[nColor][nCurMakingSeqIdx];      //得到当前要造的武士的序号
	
	if(CWarrior::InitialLifeValue[nKindNo]>nTotalLifeValue) //说明遍历完了每一个武士,都不能造,故停止制造 
	{
		bStopped=true;        //停止标记 
		if(nColor==0)        //按基地颜色输出 
			printf("%03d red headquarter stops making warriors\n",nTime);
		else 
			printf("%03d blue headquarter stops making warriors\n",nTime);
		return 0;
	 } 
	 //说明可以制造武士 
	 nTotalLifeValue -= CWarrior::InitialLifeValue[nKindNo];    //基地总生命值-所制造武士生命值 
	 nCurMakingSeqIdx = (nCurMakingSeqIdx+1)%WARRIOR_NUM;   //制造武士序列+1 
	 int nTmp=  anWarriorNum[nKindNo];   //得到当前种类武士的已有数量
	 anWarriorNum[nKindNo]++;     //+1
	 switch(nKindNo){
	 	case DRAGON:       //DRAGON=1
	 		pWarriors[nTotalWarriorNum] = new CDragon(this,nTotalWarriorNum+1);  //生成动态对象,放入武士列表 
	 		break;
	 	case NINJA:
	 		pWarriors[nTotalWarriorNum]= new CNinja(this, nTotalWarriorNum+1);   //this为当前基地对象,武士编号
	 		break;
	 	case ICEMAN:
	 		pWarriors[nTotalWarriorNum]= new CIceman(this, nTotalWarriorNum+1);
	 		break;
	 	case LION:
	 		pWarriors[nTotalWarriorNum]= new CLion(this,nTotalWarriorNum+1);
	 		break;
	 	case WOLF:
	 		pWarriors[nTotalWarriorNum]= new CWolf(this,nTotalWarriorNum+1);
	 		break;
	 } 
	 pWarriors[nTotalWarriorNum]->PrintResult(nTime);   //用多态——调用了当前武士对象的printresult函数 
	 nTotalWarriorNum ++;   //总武士数+1 
	 return 1;
 } 

司令部类的颜色函数
将int转化为颜色str

 void CHeadquarter::GetColor(char * szColor)     //定义getcolor函数 
 {
 	if(nColor==0)                        //0红,1蓝 
 		strcpy(szColor,"red");
 	else
 		strcpy(szColor,"blue");
 }

静态变量的初始化

const char * CWeapon::Names[WEAPON_NUM] = {"sword","bomb","arrow"};      //武器列表
int CWeapon::InitialForce[WEAPON_NUM];       //武器的攻击力列表——这次未用到

const char *CWarrior::Names[WARRIOR_NUM] = {"dragon","ninja","iceman","lion","wolf"}; //武士列表 

int CWarrior::InitialLifeValue[WARRIOR_NUM];     //武士总生命值列表

int CHeadquarter::MakingSeq[2][WARRIOR_NUM] = {{2,3,4,1,0},{3,0,1,2,4}};   //红蓝方制造武士的顺序

主函数

int main(){
	int t;        //case个数
	int m;        //基地生命值
	CHeadquarter RedHead,BlueHead;
	scanf("%d",&t);
	
	int nCaseNo=1;  //当前case数
	while(t--){
		printf("Case:%d\n",nCaseNo++);
		scanf("%d",&m);                   //读入生命值总数 
		int i;
		for (i=0;i<WARRIOR_NUM;i++)
			scanf("%d", &CWarrior::InitialLifeValue[i]);    //读入每个武士的生命值
	//	for(i=0;i<WEAPON_NUM;i++)
	//		scanf("%d",&CWeapon::InitialForce[i]);       //读入每把武器的攻击力 
		RedHead.Init(0,m);     //颜色,生命值 
		BlueHead.Init(1,m);
		int nTime=0;
		while(true){
			int tmp1=RedHead.Produce(nTime);     //调用produce即出现输出
			int tmp2=BlueHead.Produce(nTime);
			if(tmp1==0 && tmp2==0)           //生产结束
				break;                 //停止循环
			nTime ++;
		}
	}

	return 0;
} 
发布了77 篇原创文章 · 获赞 3 · 访问量 3055

猜你喜欢

转载自blog.csdn.net/BLUEsang/article/details/105138092
今日推荐