综合测验
Summary
继承允许我们模拟两个对象之间的is-a关系。从中继承的对象称为父类,基类。执行继承的对象称为子类,派生类或子类。
当派生类继承自基类时,派生类将获取基类的所有成员。
构造派生类时,首先构造类的基类部分,然后构造派生部分。更详细为:
#预留派生类的内存(对于基本部分和派生部分都足够)。
#调用适当的派生类构造函数。
#首先使用适当的基类构造函数构造基类对象。如果未指定基类构造函数,则将使用默认构造函数。
#派生类的初始化列表初始化派生类的成员。
#派生类构造函数的主体执行。
#控制权返回给调用者。
#破坏以相反的顺序发生,从大多数派生到最基础的阶级。
C ++有3个访问说明符:public,private和protected。受保护的访问说明符允许成员所属的类,友元函数和派生类访问受保护的成员,而不是公共成员。
类可以公开,私有或受保护地从另一个类继承。类几乎总是公开继承。
这是一个包含所有访问说明符和继承类型组合的表:
基类中的访问说明符 | 公开继承时的访问说明符 | 私有继承时的访问说明符 | 受保护地继承时的访问说明符 |
---|---|---|---|
public | 公开 | 私有的 | 受保护的 |
private | 无法访问 | 无法访问 | 无法访问 |
protected | 受保护 | 私有的 | 受保护 |
派生类可以添加新函数,更改派生类中基类工作中存在的函数的方式,更改继承成员的访问级别或隐藏功能。
多重继承使派生类可以从多个父级继承成员。您应该尽可能避免多重继承。
Quiz Time
1)对于以下每个程序,确定它们输出的内容,或者它们是否不能编译,指出原因。这个练习是通过检查来完成的,所以不要编译这些(答案是微不足道的)。
1A)
#include <iostream>
class Base
{
public:
Base()
{
std::cout << "Base()\n";
}
~Base()
{
std::cout << "~Base()\n";
}
};
class Derived: public Base
{
public:
Derived()
{
std::cout << "Derived()\n";
}
~Derived()
{
std::cout << "~Derived()\n";
}
};
int main()
{
Derived d;
}
解决方案
构造按照从大多数父类到大多数子类的顺序进行。销毁以相反的顺序发生。
Base()
Derived()
~Derived()
~Base()
1b)
#include <iostream>
class Base
{
public:
Base()
{
std::cout << "Base()\n";
}
~Base()
{
std::cout << "~Base()\n";
}
};
class Derived: public Base
{
public:
Derived()
{
std::cout << "Derived()\n";
}
~Derived()
{
std::cout << "~Derived()\n";
}
};
int main()
{
Derived d;
Base b;
}
提示:局部变量以与定义相反的顺序销毁。
解决方案
首先我们构造d,打印:
Base()
Derived()
然后我们构造b,打印:
Base()
然后我们破坏b,打印:
〜Base()
然后我们破坏d,打印:
~Derived()
〜Base()
1C)
#include <iostream>
class Base
{
private:
int m_x;
public:
Base(int x): m_x(x)
{
std::cout << "Base()\n";
}
~Base()
{
std::cout << "~Base()\n";
}
void print() { std::cout << "Base: " << m_x << '\n'; }
};
class Derived: public Base
{
public:
Derived(int y): Base(y)
{
std::cout << "Derived()\n";
}
~Derived()
{
std::cout << "~Derived()\n";
}
void print() { std::cout << "Derived: " << m_x << '\n'; }
};
int main()
{
Derived d(5);
d.print();
}
解决方案
不编译,Derived :: print()无法访问私有成员m_x
1D)
#include <iostream>
class Base
{
protected:
int m_x;
public:
Base(int x): m_x(x)
{
std::cout << "Base()\n";
}
~Base()
{
std::cout << "~Base()\n";
}
void print() { std::cout << "Base: " << m_x << '\n'; }
};
class Derived: public Base
{
public:
Derived(int y): Base(y)
{
std::cout << "Derived()\n";
}
~Derived()
{
std::cout << "~Derived()\n";
}
void print() { std::cout << "Derived: " << m_x << '\n'; }
};
int main()
{
Derived d(5);
d.print();
}
解决方案
Base()
Derived()
Derived:5
~Derived()
~Base()
1E)
#include <iostream>
class Base
{
protected:
int m_x;
public:
Base(int x): m_x(x)
{
std::cout << "Base()\n";
}
~Base()
{
std::cout << "~Base()\n";
}
void print() { std::cout << "Base: " << m_x << '\n'; }
};
class Derived: public Base
{
public:
Derived(int y): Base(y)
{
std::cout << "Derived()\n";
}
~Derived()
{
std::cout << "~Derived()\n";
}
void print() { std::cout << "Derived: " << m_x << '\n'; }
};
class D2 : public Derived
{
public:
D2(int z): Derived(z)
{
std::cout << "D2()\n";
}
~D2()
{
std::cout << "~D2()\n";
}
// 注意:这里没有print()函数
};
int main()
{
D2 d(5);
d.print();
}
隐藏解决方案
Base()
Derived()
D2()
Derived:5
~D2()
〜Derived()
~Base()
2a)编写一个源自常见Fruit类的Apple类和Banana类。Fruit应该有两个成员:名称和颜色。
应运行以下程序:
int main()
{
Apple a("red");
Banana b;
std::cout << "My " << a.getName() << " is " << a.getColor() << ".\n";
std::cout << "My " << b.getName() << " is " << b.getColor() << ".\n";
return 0;
}
并产生结果:
My apple is red.
My banana is yellow.
解决方案
#include <iostream>
#include <string>
class Fruit
{
private:
std::string m_name;
std::string m_color;
public:
Fruit(std::string name, std::string color)
: m_name(name), m_color(color)
{
}
std::string getName() { return m_name; }
std::string getColor() { return m_color; }
};
class Apple: public Fruit
{
public:
Apple(std::string color="red")
: Fruit("apple", color)
{
}
};
class Banana : public Fruit
{
public:
Banana()
: Fruit("banana", "yellow")
{
}
};
int main()
{
Apple a("red");
Banana b;
std::cout << "My " << a.getName() << " is " << a.getColor() << ".\n";
std::cout << "My " << b.getName() << " is " << b.getColor() << ".\n";
return 0;
}
2b)在以前的程序中添加一个新类,该程序名为GrannySmith,继承自Apple。
应运行以下程序:
int main()
{
Apple a("red");
Banana b;
GrannySmith c;
std::cout << "My " << a.getName() << " is " << a.getColor() << ".\n";
std::cout << "My " << b.getName() << " is " << b.getColor() << ".\n";
std::cout << "My " << c.getName() << " is " << c.getColor() << ".\n";
return 0;
}
并产生结果:
My apple is red.
My banana is yellow.
My granny smith apple is green.
解决方案
#include <iostream>
#include <string>
class Fruit
{
private:
std::string m_name;
std::string m_color;
public:
Fruit(std::string name, std::string color)
: m_name(name), m_color(color)
{
}
std::string getName() { return m_name; }
std::string getColor() { return m_color; }
};
class Apple: public Fruit
{
// 我们用于Apple的前一个构造函数有一个固定的名称(“apple”)。
// 我们需要一个新的GrannySmith构造函数来设置水果的名称
protected: // 受保护,因此只有派生类可以访问
Apple(std::string name, std::string color)
: Fruit(name, color)
{
}
public:
Apple(std::string color="red")
: Fruit("apple", color)
{
}
};
class Banana : public Fruit
{
public:
Banana()
: Fruit("banana", "yellow")
{
}
};
class GrannySmith : public Apple
{
public:
GrannySmith()
: Apple("granny smith apple", "green")
{
}
};
int main()
{
Apple a("red");
Banana b;
GrannySmith c;
std::cout << "My " << a.getName() << " is " << a.getColor() << ".\n";
std::cout << "My " << b.getName() << " is " << b.getColor() << ".\n";
std::cout << "My " << c.getName() << " is " << c.getColor() << ".\n";
return 0;
}
3)挑战时间!以下测验问题更加困难和冗长。我们打算写一个简单的游戏来对抗怪物。游戏的目标是在你死之前收集尽可能多的金币或者达到20级。
我们的程序将包含3个类:一个Creature类,一个Player类和一个Monster类。玩家和怪物都继承自生物。
3a)首先创建Creature类。生物有5个属性:一个名字(std :: string),一个符号(一个char),一个生命值(int),它们每次攻击所造成的伤害量(int),以及它们携带的金币( INT)。将它们作为类成员实现。编写一整套getter(每个成员的get函数)。添加其他三个函数:void reduceHealth(int)将生物的生命值降低整数。当Creature的生命值为0或更低时,bool isDead()返回true。void addGold(int)为生物添加金币。
应运行以下程序:
#include <iostream>
#include <string>
int main()
{
Creature o("orc", 'o', 4, 2, 10);
o.addGold(5);
o.reduceHealth(1);
std::cout << "The " << o.getName() << " has " << o.getHealth() << " health and is carrying " << o.getGold() << " gold.\n.";
return 0;
}
并产生结果:
The has 3 health and is carrying 15 gold.
解决方案
#include <iostream>
#include <string>
class Creature
{
protected:
std::string m_name;
char m_symbol;
int m_health;
int m_damage;
int m_gold;
public:
Creature(std::string name, char symbol, int health, int damage, int gold) :
m_name(name), m_symbol(symbol), m_health(health), m_damage(damage), m_gold(gold)
{
}
const std::string& getName() { return m_name; }
char getSymbol() { return m_symbol; }
int getHealth() { return m_health; }
int getDamage() { return m_damage; }
int getGold() { return m_gold; }
void reduceHealth(int health) { m_health -= health; }
bool isDead() { return m_health <= 0; }
void addGold(int gold) { m_gold += gold; }
};
int main()
{
Creature o("orc", 'o', 4, 2, 10);
o.addGold(5);
o.reduceHealth(1);
std::cout << "The " << o.getName() << " has " << o.getHealth() << " health and is carrying " << o.getGold() << " gold.\n.";
return 0;
}
3b)现在我们要创建Player类。Player类继承自Creature。玩家有一个额外的成员,玩家的等级,从1开始。玩家有一个自定义名称(由用户输入),使用符号’@’,有10个生命值,1个伤害开始,并且没有金币。编写一个名为levelUp()的函数,将玩家的等级和伤害提高1.还为级别成员编写一个getter。最后,编写一个名为hasWon()的函数,如果玩家达到20级则返回true。
编写一个新的main()函数,询问用户的名称并生成输出,如下所示:
Enter your name: Alex
Welcome, Alex.
You have 10 health and are carrying 0 gold.
解决方案
#include <iostream>
#include <string>
class Creature
{
protected:
std::string m_name;
char m_symbol;
int m_health;
int m_damage;
int m_gold;
public:
Creature(std::string name, char symbol, int health, int damage, int gold) :
m_name(name), m_symbol(symbol), m_health(health), m_damage(damage), m_gold(gold)
{
}
const std::string& getName() { return m_name; }
char getSymbol() { return m_symbol; }
int getHealth() { return m_health; }
int getDamage() { return m_damage; }
int getGold() { return m_gold; }
void reduceHealth(int health) { m_health -= health; }
bool isDead() { return m_health <= 0; }
void addGold(int gold) { m_gold += gold; }
};
class Player : public Creature
{
int m_level = 1;
public:
Player(std::string name)
: Creature(name, '@', 10, 1, 0)
{
}
void levelUp()
{
++m_level;
++m_damage;
}
int getLevel() { return m_level; }
bool hasWon() { return m_level >= 20; }
};
int main()
{
std::cout << "Enter your name: ";
std::string playerName;
std::cin >> playerName;
Player p(playerName);
std::cout << "Welcome, " << p.getName() << ".\n";
std::cout << "You have " << p.getHealth() << " health and are carrying " << p.getGold() << " gold.\n.";
return 0;
}
3c)接下来是怪物类。怪物也继承了生物。怪物没有非继承的成员变量。
首先,编写一个继承自Creature的空Monster类,然后在名为Type的Monster类中添加一个枚举,其中包含我们将在此游戏中拥有的3个怪物的枚举器:DRAGON,ORC和SLIME(您还需要一个MAX_TYPES枚举器,因为它会派上用场。)
解决方案
class Monster : public Creature
{
public:
enum Type
{
DRAGON,
ORC,
SLIME,
MAX_TYPES
};
};
3d)每个怪物类型将具有不同的名称,符号,开始健康,黄金和伤害。这是每个怪物类型的统计表:
Type | Name | Symbol | Health | Damage | Gold |
---|---|---|---|---|---|
DRAGON | dragon | D | 20 | 4 | 100 |
ORC | orc | o | 4 | 2 | 25 |
SLIME | slime | s | 1 | 1 | 10 |
下一步是编写一个Monster构造函数,这样我们就可以创建怪物了。Monster构造函数应该使用Type枚举作为参数,然后创建一个具有该类怪物的相应统计数据的Monster。
有许多不同的方法可以实现这一点(一些更好,一些更糟)。但是在这种情况下,因为我们所有的怪物属性都是预定义的(不是随机的),我们将使用查找表。查找表是包含所有预定义属性的数组。我们可以根据需要使用查找表来查找给定怪物的属性。
那么我们如何实现这个查找表呢?这并不难。我们只需要两件事。首先,我们需要一个包含每个怪物Type的元素的数组。每个数组元素都将包含一个结构,其中包含该类型的Monster的所有预定义属性值。
第1步:在名为MonsterData的Monster中创建一个结构类型。此结构应具有每个属性的成员(名称,符号,运行状况,损坏和黄金)。
步骤2:将该结构的数组声明为名为monsterData的类的静态成员(将其声明为普通数组成员,然后在其之前添加单词static)。
第3步:在类之外添加以下代码。这是我们的查找表的定义:
Monster::MonsterData Monster::monsterData[Monster::MAX_TYPES]
{
{ "dragon", 'D', 20, 4, 100 },
{ "orc", 'o', 4, 2, 25 },
{ "slime", 's', 1, 1, 10 }
};
现在我们可以索引这个数组来查找我们需要的任何值!例如,要获得Dragon的金币,我们可以访问monsterData [DRAGON] .gold。
使用此查找表来实现构造函数:
Monster(Type type): Creature(monsterData[type].name, ...)
以下程序应编译:
#include <iostream>
#include <string>
int main()
{
Monster m(Monster::ORC);
std::cout << "A " << m.getName() << " (" << m.getSymbol() << ") was created.\n";
}
并打印:
创建了一个orc(o)。
解决方案
#include <iostream>
#include <string>
class Creature
{
protected:
std::string m_name;
char m_symbol;
int m_health;
int m_damage;
int m_gold;
public:
Creature(std::string name, char symbol, int health, int damage, int gold) :
m_name(name), m_symbol(symbol), m_health(health), m_damage(damage), m_gold(gold)
{
}
const std::string& getName() { return m_name; }
char getSymbol() { return m_symbol; }
int getHealth() { return m_health; }
int getDamage() { return m_damage; }
int getGold() { return m_gold; }
void reduceHealth(int health) { m_health -= health; }
bool isDead() { return m_health <= 0; }
void addGold(int gold) { m_gold += gold; }
};
class Player : public Creature
{
int m_level = 1;
public:
Player(std::string name)
: Creature(name, '@', 10, 1, 0)
{
}
void levelUp()
{
++m_level;
++m_damage;
}
int getLevel() { return m_level; }
};
class Monster : public Creature
{
public:
enum Type
{
DRAGON,
ORC,
SLIME,
MAX_TYPES
};
struct MonsterData
{
const char* name;
char symbol;
int health;
int damage;
int gold;
};
static MonsterData monsterData[MAX_TYPES];
Monster(Type type)
: Creature(monsterData[type].name, monsterData[type].symbol, monsterData[type].health, monsterData[type].damage, monsterData[type].gold)
{
}
};
Monster::MonsterData Monster::monsterData[Monster::MAX_TYPES]
{
{ "dragon", 'D', 20, 4, 100 },
{ "orc", 'o', 4, 2, 25 },
{ "slime", 's', 1, 1, 10 }
};
int main()
{
Monster m(Monster::ORC);
std::cout << "A " << m.getName() << " (" << m.getSymbol() << ") was created.\n";
return 0;
}
3e)最后,向名为getRandomMonster()的Monster添加一个静态函数。此函数应选择0和MAX_TYPES-1之间的随机数,并返回一个具有该类型的怪物(按值)(您需要将int static_cast到一个Type以将其传递给Monster构造函数)。
您可以使用以下代码选择一个随机数:
#include <cstdlib> //rand() 和srand()
#include <ctime> // time()
// 生成最小和最大(包括)之间的随机数
// 假设已经调用了srand()
int getRandomNumber(int min, int max)
{
static const double fraction = 1.0 / (static_cast<double>(RAND_MAX) + 1.0); //static用于效率,所以我们只计算一次这个值
// 在我们的范围内均匀分布随机数
return static_cast<int>(rand() * fraction * (max - min + 1) + min);
}
应运行以下主要功能:
#include <iostream>
#include <string>
#include <cstdlib> // rand() 和srand()
#include <ctime> // time()
int main()
{
srand(static_cast<unsigned int>(time(0))); // 将初始值设置为系统时钟
rand(); // get rid of first result
for (int i = 0; i < 10; ++i)
{
Monster m = Monster::getRandomMonster();
std::cout << "A " << m.getName() << " (" << m.getSymbol() << ") was created.\n";
}
return 0;
}
该计划的结果应该是随机的。
解决方案
#include <iostream>
#include <string>
#include <cstdlib> // rand() 和srand()
#include <ctime> // time()
// 生成最小和最大(包括)之间的随机数
// 假设已经调用了srand()
int getRandomNumber(int min, int max)
{
static const double fraction = 1.0 / (static_cast<double>(RAND_MAX) + 1.0); //static用于效率,所以我们只计算一次这个值
// 在我们的范围内均匀分布随机数
return static_cast<int>(rand() * fraction * (max - min + 1) + min);
}
class Creature
{
protected:
std::string m_name;
char m_symbol;
int m_health;
int m_damage;
int m_gold;
public:
Creature(std::string name, char symbol, int health, int damage, int gold) :
m_name(name), m_symbol(symbol), m_health(health), m_damage(damage), m_gold(gold)
{
}
char getSymbol() { return m_symbol; }
const std::string& getName() { return m_name; }
bool isDead() { return m_health <= 0; }
int getGold() { return m_gold; }
void addGold(int gold) { m_gold += gold; }
void reduceHealth(int health) { m_health -= health; }
int getHealth() { return m_health; }
int getDamage() { return m_damage; }
};
class Player : public Creature
{
int m_level = 1;
public:
Player(std::string name)
: Creature(name, '@', 10, 1, 0)
{
}
void levelUp()
{
++m_level;
++m_damage;
}
int getLevel() { return m_level; }
bool hasWon() { return m_level >= 20; }
};
class Monster : public Creature
{
public:
enum Type
{
DRAGON,
ORC,
SLIME,
MAX_TYPES
};
struct MonsterData
{
const char* name;
char symbol;
int health;
int damage;
int gold;
};
static MonsterData monsterData[MAX_TYPES];
Monster(Type type)
: Creature(monsterData[type].name, monsterData[type].symbol, monsterData[type].health, monsterData[type].damage, monsterData[type].gold)
{
}
static Monster getRandomMonster()
{
int num = getRandomNumber(0, MAX_TYPES - 1);
return Monster(static_cast<Type>(num));
}
};
Monster::MonsterData Monster::monsterData[Monster::MAX_TYPES]
{
{ "dragon", 'D', 20, 4, 100 },
{ "orc", 'o', 4, 2, 25 },
{ "slime", 's', 1, 1, 10 }
};
int main()
{
srand(static_cast<unsigned int>(time(0))); // 将初始值设置为系统时钟
rand(); // get rid of first result
for (int i = 0; i < 10; ++i)
{
Monster m = Monster::getRandomMonster();
std::cout << "A " << m.getName() << " (" << m.getSymbol() << ") was created.\n";
}
return 0;
}
3f)我们终于开始编写我们的游戏逻辑了!
以下是游戏规则:
玩家一次遇到一个随机生成的怪物。
对于每个怪物,玩家有两种选择:(R)un或(F)ight。
如果玩家决定参加比赛,他们有50%的机会逃跑。
如果玩家逃脱,他们移动到下一次遭遇将不会产生不良影响。
如果玩家没有逃脱,则怪物获得自由攻击,并且玩家选择他们的下一个动作。
如果玩家选择战斗,则玩家首先攻击。玩家的伤害会降低怪物的健康。
如果怪物死亡,玩家将获取怪物携带的任何金币。玩家也升级,将等级和伤害提高1点。
如果怪物没有死亡,怪物就会攻击玩家。怪物的伤害会降低玩家的健康。
当玩家死亡(失去)或达到20级(胜利)时游戏结束
如果玩家死亡,游戏应告诉玩家他们的等级以及他们有多少金币。
如果玩家获胜,游戏应告诉玩家他们赢了,以及他们有多少金币
这是一个示例游戏会话:
Enter your name: MW
Welcome, MW
You have encountered a orc (o).
®un or (F)ight: R
You successfully fled.
You have encountered a orc (o).
®un or (F)ight: R
You successfully fled.
You have encountered a slime (s).
®un or (F)ight: F
You hit the slime for 1 damage.
You killed the slime.
You are now level 2.
You found 5 gold.
You have encountered a slime (s).
®un or (F)ight: F
You hit the slime for 2 damage.
You killed the slime.
You are now level 3.
You found 5 gold.
You have encountered a slime (s).
®un or (F)ight: F
You hit the slime for 3 damage.
You killed the slime.
You are now level 4.
You found 5 gold.
You have encountered a dragon (D).
®un or (F)ight: R
You failed to flee.
The dragon hit you for 4 damage.
®un or (F)ight: R
You successfully fled.
You have encountered a slime (s).
®un or (F)ight: F
You hit the slime for 4 damage.
You killed the slime.
You are now level 5.
You found 5 gold.
You have encountered a slime (s).
®un or (F)ight: F
You hit the slime for 5 damage.
You killed the slime.
You are now level 6.
You found 5 gold.
You have encountered a dragon (D).
®un or (F)ight: R
You failed to flee.
The dragon hit you for 4 damage.
®un or (F)ight: R
You failed to flee.
The dragon hit you for 4 damage.
You died at level 6 and with 25 gold.
Too bad you can’t take it with you!
请按任意键继续. . .
提示:创建4个功能:
main()函数应该处理游戏设置(创建播放器)和主游戏循环。
fightMonster()处理玩家与单个怪物之间的战斗,包括询问玩家他们想做什么,处理跑步或打击案件。
attackMonster()处理攻击怪物的玩家,包括升级。
attackPlayer()处理攻击玩家的怪物。
解决方案
#include <iostream>
#include <string>
#include <cstdlib> // rand()和srand()
#include <ctime> // time()
// 生成最小和最大(包括)之间的随机数
// 假设已经调用了srand()
int getRandomNumber(int min, int max)
{
static const double fraction = 1.0 / (static_cast<double>(RAND_MAX) + 1.0); //static用于效率,所以我们只计算一次这个值
// 在我们的范围内均匀分布随机数
return static_cast<int>(rand() * fraction * (max - min + 1) + min);
}
class Creature
{
protected:
std::string m_name;
char m_symbol;
int m_health;
int m_damage;
int m_gold;
public:
Creature(std::string name, char symbol, int health, int damage, int gold) :
m_name(name), m_symbol(symbol), m_health(health), m_damage(damage), m_gold(gold)
{
}
char getSymbol() { return m_symbol; }
const std::string& getName() { return m_name; }
bool isDead() { return m_health <= 0; }
int getGold() { return m_gold; }
void addGold(int gold) { m_gold += gold; }
void reduceHealth(int health) { m_health -= health; }
int getHealth() { return m_health; }
int getDamage() { return m_damage; }
};
class Player : public Creature
{
int m_level = 1;
public:
Player(std::string name)
: Creature(name, '@', 10, 1, 0)
{
}
void levelUp()
{
++m_level;
++m_damage;
}
int getLevel() { return m_level; }
bool hasWon() { return m_level >= 20; }
};
class Monster : public Creature
{
public:
enum Type
{
DRAGON,
ORC,
SLIME,
MAX_TYPES
};
struct MonsterData
{
const char* name;
char symbol;
int health;
int damage;
int gold;
};
static MonsterData monsterData[MAX_TYPES];
Type m_type;
Monster(Type type)
: Creature(monsterData[type].name, monsterData[type].symbol, monsterData[type].health, monsterData[type].damage, monsterData[type].gold), m_type(type)
{
}
static Monster getRandomMonster()
{
int num = getRandomNumber(0, MAX_TYPES - 1);
return Monster(static_cast<Type>(num));
}
};
Monster::MonsterData Monster::monsterData[Monster::MAX_TYPES]
{
{ "dragon", 'D', 20, 4, 100 },
{ "orc", 'o', 6, 2, 25 },
{ "slime", 's', 1, 1, 5 }
};
// 此函数处理玩家攻击怪物
void attackMonster(Player &p, Monster &m)
{
// 如果玩家死了,我们就无法攻击怪物
if (p.isDead())
return;
std::cout << "You hit the " << m.getName() << " for " << p.getDamage() << " damage.\n";
// 由玩家的伤害减少怪物的健康
m.reduceHealth(p.getDamage());
// 如果怪物现在已经死了,请将玩家升级
if (m.isDead())
{
std::cout << "You killed the " << m.getName() << ".\n";
p.levelUp();
std::cout << "You are now level " << p.getLevel() << ".\n";
std::cout << "You found " << m.getGold() << " gold.\n";
p.addGold(m.getGold());
}
}
// 此函数处理攻击玩家的怪物
void attackPlayer(Monster &m, Player &p)
{
// 如果怪物死了,它就无法攻击玩家
if (m.isDead())
return;
// 怪物的伤害会降低玩家的健康
p.reduceHealth(m.getDamage());
std::cout << "The " << m.getName() << " hit you for " << m.getDamage() << " damage.\n";
}
// 此函数处理玩家和随机生成的怪物之间的整个战斗
void fightMonster(Player &p)
{
// First randomly generate a monster
Monster m = Monster::getRandomMonster();
std::cout << "You have encountered a " << m.getName() << " (" << m.getSymbol() << ").\n";
// 只要怪物没有死,玩家没有死,那么战斗继续
while (!m.isDead() && !p.isDead())
{
std::cout << "(R)un or (F)ight: ";
char input;
std::cin >> input;
if (input == 'R' || input == 'r')
{
// 成功逃离的几率为50%
if (getRandomNumber(1, 2) == 1)
{
std::cout << "You successfully fled.\n";
return; // success ends the encounter
}
else
{
// 没有逃跑会让怪物免受攻击并且你会受到伤害
std::cout << "You failed to flee.\n";
attackPlayer(m, p);
continue;
}
}
if (input == 'F' || input == 'f')
{
// 玩家首先攻击,怪物再攻击
attackMonster(p, m);
attackPlayer(m, p);
}
}
}
int main()
{
srand(static_cast<unsigned int>(time(0))); // 将初始值设置为系统时钟
rand(); // 摆脱第一个结果
std::cout << "Enter your name: ";
std::string playerName;
std::cin >> playerName;
Player p(playerName);
std::cout << "Welcome, " << p.getName() << '\n';
// 如果玩家没有死并且尚未获胜,则游戏继续进行
while (!p.isDead() && !p.hasWon())
fightMonster(p);
// 此时,玩家已经死亡或已经获胜
if (p.isDead())
{
std::cout << "You died at level " << p.getLevel() << " and with " << p.getGold() << " gold.\n";
std::cout << "Too bad you can't take it with you!\n";
}
else
{
std::cout << "You won the game with " << p.getGold() << " gold!\n";
}
return 0;
}