一、实验目的
- 掌握类的实现
- 掌握对象的生成和初始化
- 掌握构造函数、拷贝构造函数和析构函数的定义和实现
- 掌握类成员函数调用的方法
- 阅读并理解程序代码
- 编程工具的使用
二、实验内容
在奥特曼的世界,打怪兽就是全部。现在人人都有机会成为奥特曼,加入到与怪兽无止境的战斗中。可惜,并非人人生来就是英雄,革命尚未成功,同志仍需努力啊。每一个奥特曼都要从零开始,辛勤劳动,打怪升级,最终才能成为举世瞩目的大英雄。
每个奥特曼的等级(rank)都从第一级开始,随着它打怪兽经验(exp)的增加,等级将不断攀升。随着等级的升高,奥特曼的生命值(hp)上限和攻击力(damage)也将大大增强。在与怪兽的战斗中,奥特曼收获的不仅仅是经验。有时,运气好的话,还能从怪兽身上弄到点小钱(money)。不要小看这些钱,关键时刻,它能给奥特曼买药补血呀。奥特曼没有金刚不坏之身,在与怪兽的战斗中,奥特曼会受到伤害。一旦奥特曼的生命值降到0,它英雄的一生就结束了。
好了,了解了奥特曼的基本情况,现在可以开始战斗了。首先,我们需要一位全新的奥特曼(Outman),我们给它赋予一定的初始实力(initial)。让它投入战斗吧!
在与怪兽的战斗中要讲究策略。所谓知己知彼,百战不殆,一旦碰到怪兽,我们首先要查看自己和对方的实力(display),包括双方的等级、生命值、攻击力、经验和所拥有的钱财。所谓打得赢就打,打不赢就跑。如果对手太强大,逃跑吧(escape)!偶尔逃跑无伤颜面,但会耗费一点生命值。如果总是逃跑,生命被虚耗,那英雄就当不成了。所以该出手时就出手,勇敢地战斗(attack)吧!每一回合的战斗中,怪兽会受到攻击(attacked),怪兽也会反击(fightback),让奥特曼受到攻击(attacked)。每一回合结束,只要奥特曼还活着(isalive),而且怪兽也还活着,战斗就要继续。如果奥特曼的生命值太低,也许抵挡不了下一轮的进攻,那么别财迷了,掏钱出来给它补血(restore)吧。当然,如果形势确实不妙,奥特曼也可以中途逃跑。但如果获得了最终的胜利(win),不仅能赢得战斗经验,夺取怪兽身上的钱财,足够多的经验也许能让奥特曼升级(upgrade)。
现在有一个奥特曼打怪兽的角色扮演游戏。请你根据以上描述,完成以下实验内容:
定义两个类:奥特曼类(Ultraman)和怪兽类(Monster),为他们各自添加构造函数、拷贝构造函数和析构函数,实现对象的初始化和析构行为。
奥特曼说明如下:
- 为每个属性设置get方法
- 初始化(利用构造函数完成初始化),参数是等级,等级与其他属性的关系:生命是等级10倍,攻击是等级3倍,金钱是等级的10倍,经验开始为0。
- 逃跑(escape),当生命不超过10点时,奥特曼将逃跑,逃跑将损失所有金钱,战斗结果为奥特曼失败(lose)
- 攻击(attack),(这个方法要参数么??),当攻击怪兽时,怪兽受到的伤害等于奥特曼攻击力。(本方法实际上就是怪兽被攻击,所以不一定需要实现)
- 被攻击(attacked),(这个方法要参数么??),当怪兽反击时,奥特曼受到的伤害等于怪兽攻击力的一半,即生命损失=怪兽攻击力值/2,取整处理
- 回复生命(restore),如果体力不支(生命低于50%但大于10点),每10个金钱可恢复1点生命值。只要有足够的钱,可以一直恢复,直到达到生命值上限(等级的10倍)。
- 胜利(win),(这个方法要参数么??),当怪兽生命小于等于0,战斗结果为奥特曼胜利(win),奥特曼将获得怪兽身上所有金钱和经验值。
- 升级(upgrade),战斗结束后,达到升级条件可以升级,条件是经验值不小于等级10倍。升级将扣除相应的经验值,生命满血,更新生命上限和攻击力。
- 显示状态(display),单行输出,格式如下:
rank=等级 hp=生命 damage=攻击 exp=经验 money=金钱
怪兽说明如下:
- 为每个属性设置get方法。
- 初始化(利用构造函数完成初始化),参数是等级,等级与其他属性的关系:生命是等级20倍,攻击是等级2倍,金钱是等级的10倍,经验值是等级的10倍。
- 被攻击(attacked),(这个方法要参数么??),当奥特曼攻击时,怪兽受到的伤害等于奥特曼攻击力,即生命损失=奥特曼攻击力值
- 反击(fightback)当怪兽被反击后,如果怪兽不死,将进行反击,反击力等于怪兽攻击力(本方法实际上就是奥特曼被攻击,所以不一定需要实现)
- 显示状态(display),单行输出,格式如下:
rank=等级 hp=生命 damage=攻击 exp=经验 money=金钱
实现以下扩展。
怪兽分为四种类型(定义四个类):
普通型怪兽(NMonster):攻击力是等级2倍,生命是10倍,金钱经验是10倍
攻击型怪兽(AMonster):攻击力是等级4倍,生命是5倍,金钱经验是10倍
防御型怪兽(DMonster):攻击力是等级1倍,生命是20倍,金钱经验是10倍
肉鸡型怪兽(SMonster):攻击力是等级1倍,生命是10倍,金钱经验是20倍
- 定义一个守护神类(Angel),该类定义怪兽或奥特曼的守护神,为怪兽或奥特曼提供帮助。守护神等级为所守护对象的等级(例如守护神a1守护等级为3的攻击型怪兽am1,则a1的等级也为3),攻击是等级的一半,无生命。怪兽的守护神金钱和经验都为等级的5倍。奥特曼的守护神金钱和经验为0,等级随守护对象升级而升级。
- 为四个怪兽类和奥特曼类添加守护神对象成员,使它们都成为复合类。
- 当奥特曼战胜怪兽后,将获得怪兽及其守护神的经验金钱。
- 修改奥特曼类和怪兽类相关成员函数,实现守护神类与它们的关系,具体如下:
奥特曼,守护神为它攻击攻击型怪兽时,加1点攻击力,而在它攻击防御型怪兽时,加2点攻击力,在获得肉鸡型怪兽的金钱和经验时,翻倍(仅获得怪兽的经验和金钱翻倍,守护神的不翻倍)。
普通型怪兽和肉鸡型怪兽,无守护神。
攻击型怪兽,守护神为它在攻击奥特曼时,也打一次,使奥特曼除了受到怪兽攻击,还将将受到守护神攻击力的伤害。
防御型怪兽,守护神为它受到奥特曼攻击时,将生命损失减半。
Outman(奥特曼类对象)这个热血骚年总是叫嚷“一个打十个”,叫的老天爷都不耐烦了。这次Outman傻眼了,是一个打4个。现在让我们来为Outman欢呼吧,围观吧(记得带上板凳瓜子和鸡蛋,不好看的话就扔扔)。
请在main函数中实现如下架构。
while (t--) //每个实例就是奥特曼与个怪兽的战斗
{
//输入奥特曼等级值,利用等级值,声明一个奥特曼对象并初始化。
//输出奥特曼状态,调用display方法,每行输出一个
//输入个怪兽的等级,依次为普通型怪兽、肉鸡型怪兽、防御型怪兽、攻击型怪兽,保存在数组mgrad[4]中
//创建种类型怪兽对象并利用等级值mgrad初始化。
//输出每个怪兽的状态,调用display方法,每行输出一个
//设置战斗标志flag为true,与每个怪兽的战斗结果winflag1=0,winflag2=0,winflag3=0,winflag4=0。
//启动战斗循环,具体如下:
while(flag) //4个怪兽群殴奥特曼
{
//奥特曼攻击每个怪兽1次
if (如果怪兽i没死) //如果怪兽i没死,怪兽i攻击奥特曼,注意:只要没死的怪兽,都攻击奥特曼次。
{
//怪兽i反击1次
if (奥特曼不逃跑) //如果奥特曼不逃跑,用奥特曼生命来判断
//奥特曼回血,在方法中判断是否需要加血
else
{ //奥特曼逃跑,设置逃跑标志eflag为true,并输出"lose"并回车
//输出奥特曼状态,调用display方法
//设置flag为false,停止战斗
}
}
else if(怪兽是这一轮死的)//如果怪兽这一轮死了
{
//奥特曼胜利,并输出"win"并回车
//奥特曼升级
//输出奥特曼状态,调用display方法
//设置打赢标记winflagi为true
}
if(所有怪兽都死了){//所有怪兽都死了,用个打赢标记判断
//结束战斗,设置flag为false,并输出“win all”
}
}//end of while flag
}
三、输入输出
Input
第1行输入t表示有t个测试实例
对于每个测试实例,首行先输入奥特曼等级
接着4行依次输入普通型、肉鸡型、防御型、攻击型怪兽的等级
Output
输出奥特曼和每个怪兽的战斗结果,具体要求参考程序框架
Sample Input
2
5
3
3
3
3
5
10
10
10
10
Sample Output
rank=5 hp=50 damage=15 exp=0 money=50
rank=3 hp=30 damage=6 exp=30 money=30
rank=3 hp=30 damage=3 exp=60 money=60
rank=3 hp=60 damage=3 exp=30 money=30
rank=3 hp=15 damage=12 exp=30 money=30
win
rank=5 hp=45 damage=15 exp=45 money=95
win
rank=6 hp=60 damage=18 exp=25 money=125
win
rank=8 hp=80 damage=24 exp=15 money=245
win
rank=8 hp=76 damage=24 exp=60 money=290
win all
rank=5 hp=50 damage=15 exp=0 money=50
rank=10 hp=100 damage=20 exp=100 money=100
rank=10 hp=100 damage=10 exp=200 money=200
rank=10 hp=200 damage=10 exp=100 money=100
rank=10 hp=50 damage=40 exp=100 money=100
lose
rank=5 hp=8 damage=15 exp=0 money=0
四、碎碎念念
文字描述比较多,但是也算是比较详细了,要注意的就是奥特曼和怪兽的守护神,奥特曼提升的伤害和怪兽的伤害减免都是在原有伤害的基础上叠加的。
还有就是奥特曼的升级应该写成循环,因为有可能某一次获得的经验足够升级多次。
还有就是主函数框架题目是给出来了,但是仅仅是个框架而已,还是需要自己去写啊。
凭借样例输出,加上多次碰壁,可以感觉出主函数,应该是这样的:
首先我们的奥特曼发挥主角光环,率先出手,攻击这一堆怪兽,之后没死的怪兽(注意是没死的,因为这是一个循环)攻击奥特曼,奥特曼此时不能躲闪(因为是C++面向对象程序设计基础),只能乖乖的依次接受怪兽(没死的)的攻击,然后在攻击中,如果被打残血了,很残的那种,那么奥特曼不能逞英雄,秉持着峡谷第一定律:活着才有输出,必须选择暂时性撤退(逃跑,战斗失败),如果没有被打的那么残,那么可以用资本治疗一下,然后继续打,直到一方挂。
五、AC代码
#include"iostream"
using namespace std;
class Angel
{
protected:
int rank,damage,exp,money;
public:
Angel(int rank,int exp,int money):rank(rank),damage(rank/2),money(money),exp(exp){}
int getexp(){return exp;}
int getmoney(){return money;}
int getdamage(){return damage;}
void upgrade(int rank,int money,int exp){this->rank=rank;damage=rank/2;this->money=money;this->exp=exp;}
};
class Ultraman
{
protected:
int rank,exp,hp,damage,money;
Angel angel;
public:
int getrank(){return rank;}
int getexp(){return exp;}
int gethp(){return hp;}
int getdamage(){return damage;}
int getmoney(){return money;}
Ultraman(int rank):rank(rank),hp(10*rank),damage(3*rank),money(10*rank),exp(0),angel(rank,0,0){}
void escape(){money=0;}
void attack(){}
void attacked(int hurt){hp-=hurt/2;}
void restore()
{
if(hp>10&&hp<5*rank)
while(money>=10&&hp<10*rank)
{
money-=10;
hp+=1;
}
}
void win(int monster_money,int monster_exp)
{
money+=monster_money;
exp+=monster_exp;
}
void upgrade()
{
while(exp>=10*rank)
{
exp-=10*rank;
rank++;
angel.upgrade(rank,0,0);
hp=10*rank;
damage=3*rank;
}
}
void display(){cout<<"rank="<<rank<<" hp="<<hp<<" damage="<<damage<<" exp="<<exp<<" mongey="<<money<<endl;}
};
class Monster
{
protected:
int rank,hp,damage,exp,money;
public:
int getrank(){return rank;}
int getexp(){return exp;}
int gethp(){return hp;}
int getdamage(){return damage;}
int getmoney(){return money;}
Monster(int rank):rank(rank),hp(20*rank),damage(2*rank),money(10*rank),exp(10*rank){}
void attacked(int hurt){hp-=hurt;}
void fightback(){}
void display(){cout<<"rank="<<rank<<" hp="<<hp<<" damage="<<damage<<" exp="<<exp<<" mongey="<<money<<endl;}
};
class NMonster:public Monster
{
public:
NMonster(int rank):Monster(rank){hp=10*rank;}
};
class AMonster:public Monster
{
protected:
Angel angel;
public:
AMonster(int rank):Monster(rank),angel(rank,5*rank,5*rank){hp=5*rank;damage=4*rank;}
int angel_exp(){return angel.getexp();}
int angel_money(){return angel.getmoney();}
int angel_damage(){return angel.getdamage();}
};
class DMonster:public Monster
{
protected:
Angel angel;
public:
DMonster(int rank):Monster(rank),angel(rank,5*rank,5*rank){damage=rank;}
int angel_exp(){return angel.getexp();}
int angel_money(){return angel.getmoney();}
};
class SMonster:public Monster
{
public:
SMonster(int rank):Monster(rank){hp=10*rank;damage=rank;money=20*rank;exp=20*rank;}
};
int main()
{
int t,rank,i,mgrad[4];
cin>>t;
while(t--)
{
cin>>rank;
Ultraman Outman(rank);
Outman.display();
for(i=0;i<4;i++)
cin>>mgrad[i];
NMonster normal(mgrad[0]);
normal.display();
SMonster snack(mgrad[1]);
snack.display();
DMonster defense(mgrad[2]);
defense.display();
AMonster attacker(mgrad[3]);
attacker.display();
bool flag=true,winflag1=0,winflag2=0,winflag3=0,winflag4=0,eflag;
while(flag)
{
normal.attacked(Outman.getdamage());
snack.attacked(Outman.getdamage());
defense.attacked((Outman.getdamage()+2)/2);
attacker.attacked(Outman.getdamage()+1);
if(normal.gethp()>0)
{
Outman.attacked(normal.getdamage());
if(Outman.gethp()>10)
Outman.restore();
else
{
eflag=true;
cout<<"lose"<<endl;
Outman.escape();
Outman.display();
flag=false;
break;
}
}
else if(winflag1==0)
{
cout<<"win"<<endl;
Outman.win(normal.getmoney(),normal.getexp());
Outman.upgrade();
Outman.display();
winflag1=true;
}
if(snack.gethp()>0)
{
Outman.attacked(snack.getdamage());
if(Outman.gethp()>10)
Outman.restore();
else
{
eflag=true;
cout<<"lose"<<endl;
Outman.escape();
Outman.display();
flag=false;
break;
}
}
else if(winflag2==0)
{
cout<<"win"<<endl;
Outman.win(snack.getmoney()*2,snack.getexp()*2);
Outman.upgrade();
Outman.display();
winflag2=true;
}
if(defense.gethp()>0)
{
Outman.attacked(defense.getdamage());
if(Outman.gethp()>10)
Outman.restore();
else
{
eflag=true;
cout<<"lose"<<endl;
Outman.escape();
Outman.display();
flag=false;
break;
}
}
else if(winflag3==0)
{
cout<<"win"<<endl;
Outman.win(defense.getmoney()+defense.angel_money(),defense.getexp()+defense.angel_exp());
Outman.upgrade();
Outman.display();
winflag3=true;
}
if(attacker.gethp()>0)
{
Outman.attacked(attacker.getdamage()+attacker.angel_damage());
if(Outman.gethp()>10)
Outman.restore();
else
{
eflag=true;
cout<<"lose"<<endl;
Outman.escape();
Outman.display();
flag=false;
break;
}
}
else if(winflag4==0)
{
cout<<"win"<<endl;
Outman.win(attacker.getmoney()+attacker.angel_money(),attacker.getexp()+attacker.angel_exp());
Outman.upgrade();
Outman.display();
winflag4=true;
}
if(winflag1&&winflag2&&winflag3&&winflag4)
{
flag=false;
cout<<"win all"<<endl;
}
}
}
}