You are designing a text-based Role-Playing Game (RPG), in which each character can have one of three jobs: Fighter, Thief, or Wizard. You need a way to keep track of the data for each character, and because a lot of the data and functionality is shared between characters, you have decided to use objects and inheritance to accomplish this.
Part 1:
First, you’ll need a base Adventurer class, which represents a jobless character template for all of the job classes to build off of.
The Adventurer class should have the following methods:
● Constructor: The Adventurer class constructor should have the following signature:
__init__(self, name, level, strength, speed, power)
where name (the name of the Adventurer) should be a string, and level, strength, speed, and power should be integers that represent the Adventurer’s ability levels. The constructor should create instance variables to store the value of each of these arguments (self.name, self.level, self.strength, self.speed, and self.power, respectively), along with two more instance variables:
● self.HP, an integer representing the Adventurer’s remaining Hit Points, which should be initialized to the Adventurer’s level multiplied by 6.
● self.hidden, a boolean representing whether the Adventurer is currently hiding, which should be initialized to False.
● __repr__(self)
You must overload the repr() method (similar to the str() method, except that it also changes what is output when you pass the object directly to the interpreter) for the Adventurer class so that it returns a string of the format:
"<Name - HP: <Current HP"
Be sure to match the spacing and format of the above string exactly or you will fail test cases and lose points (note that the angled brackets are not part of the string itself, but indicate where you should substitute in the actual name and hit points of your adventurer). Note that changing __repr__ automatically changes the behavior of str() as well. See the sample output below for an example.
● attack(self,target)
The attack method takes as a parameter another Adventurer object target and does the following:
● If the target is hidden, then this method should print the string:
"<Name can't see <Target’s name"
● Otherwise, this method should the compute the damage the Adventurer does (their strength + 4), and subtract that value from the target’s HP. The method should update target’s hit points accordingly, and print out a message of the following format:
"<Name attacks <Target’s name for <Damage amount damage"
Example: (italic text is printed, bold text is returned)
thog = Adventurer("Thog",3,5,1,2)
repr(thog)
'Thog - HP: 18'
goku = Adventurer("Goku",20,10,7,9001)
goku
Goku - HP: 120
thog.attack(goku)
Thog attacks Goku for 9 damage
str(goku)
'Goku - HP: 111'
goku.HP
111
goku.hidden = True
thog.attack(goku)
Thog can't see Goku
goku.attack(thog)
Goku attacks Thog for 14 damage
print(thog)
Thog - HP: 4
goku.attack(thog)
Goku attacks Thog for 14 damage
thog.HP
-10
Part 2:
Construct three additional classes named Fighter, Thief, and Wizard to represent each of the three possible specializations for an Adventurer. Each of these classes should inherit from the Adventurer class and extend it by overloading the constructor and attack methods.
Fighter:
● The Fighter constructor must take the same parameters as its superclass constructor and pass them into the superclass constructor, and must then alter self.HP to be initialized to level * 12 rather than level * 6.
● The overridden attack method for Fighter is identical to that of Adventurer except that a
Fighter does (2*strength + 6) damage to enemies that aren’t hidden rather than (strength + 4).
Thief:
● The Thief constructor must take the same parameters as its superclass constructor and pass them into the superclass constructor, and must then alter self.HP to be initialized to level * 8 rather than level * 6, and set self.hidden to True.
● The overridden attack method for Thief should call the superclass method of the same name in the case that the Thief is not hidden (that is, when self.hidden is False). If the Thief is hidden, then instead the following should occur:
○ If both the Thief and the target are hidden, and the Thief’s speed is less than the target’s speed, then the Thief is unable to find their target and the method should print a message of the format:
"<Name can't see <Target’s name"
○ Otherwise, the Thief is able to perform a sneak attack. This does damage equal to (speed + level) * 5. It also causes the Thief and their target (if applicable) to no longer be hidden, and should print a message of the format:
"<Name sneak attacks <Target’s name for <Damage amount damage"
Wizard:
● The Wizard constructor must take the same parameters as its superclass constructor and pass them into the superclass constructor, and must then initialize a new instance variable,
self.fireballs_left, initially equal to the Wizard’s power.
● The overridden attack method for Wizard should call the superclass method of the same name in the case that the Wizard has no fireballs left (that is, self.fireballs_left is 0).
If the Wizard does have fireballs left, the Wizard should instead cast a fireball:
○ A fireball causes the target to no longer be hidden (if applicable), and does (level * 3) damage to the target. Remember to subtract one from the Wizard’s number of fireballs left. Casting a fireball should also print a message of the format:
"<Name casts fireball on <Target’s name for <Damage amt damage"
Part 3:
Finally, create a function (not part of any class) called duel(adv1, adv2) which takes two Adventurer objects adv1 and adv2 as parameters and returns True if adv1 would win in a one-onone fight, or False otherwise. Specifically, the function should do the following:
● If at any point adv1 reaches 0 or fewer HP while adv2 still has more than 0 HP, duel should print out adv1 and adv2, followed by a message of the form:
"<adv2’s name wins!"
and then return False.
● If at any point adv2 reaches 0 or fewer HP while adv1 still has more than 0 HP, duel should print out adv1 and adv2, followed by a message of the form:
"<adv1’s name wins!"
and then return True.
● If adv1 and adv2 somehow reach 0 HP or below simultaneously (because they start the duel like that, or because they’re the same object) duel should print out adv1 and adv2, followed by the message:
"Everyone loses!"
and then return False.
● Otherwise, the duel should proceed: adv1 and adv2 should be printed out to see the current HP counts, then adv1 should attack adv2, and then adv2 should attack adv1. This should repeat until one of the above conditions is met.
● Remember, you must check whether one or both Adventurers is at 0 or fewer HP after EVERY attack, not just every pair of attacks: if adv2 reaches 0 or fewer HP after adv1 attacks, then adv2 should not get a chance to retaliate.
Constraints:
● Your file should only contain class definitions and the duel function. No code should be included outside of the classes/function (though, as usual, comments are fine).
● You must name all classes, methods, and instance variables EXACTLY as specified.
● You should not import any modules.
Examples: (italic text is printed, bold text is returned)
Example 1:
albus = Wizard("Dumbledore",15,4,6,2)
smeagol = Thief("Gollum",12,1,4,1)
bruce = Thief("Batman",10,4,5,1)
duel(albus,smeagol)
Dumbledore - HP: 90
Gollum - HP: 96
Dumbledore casts fireball on Gollum for 45 damage
Gollum attacks Dumbledore for 5 damage
Dumbledore - HP: 85
Gollum - HP: 51
Dumbledore casts fireball on Gollum for 45 damage
Gollum attacks Dumbledore for 5 damage
Dumbledore - HP: 80
Gollum - HP: 6
Dumbledore attacks Gollum for 8 damage
Dumbledore - HP: 80
Gollum - HP: -2
Dumbledore wins!
True
duel(bruce,albus)
Batman - HP: 80
Dumbledore - HP: 80
Batman sneak attacks Dumbledore for 75 damage
Dumbledore attacks Batman for 8 damage
Batman - HP: 72
Dumbledore - HP: 5
Batman attacks Dumbledore for 8 damage
Batman - HP: 72
Dumbledore - HP: -3
Batman wins!
True
Example 2:
durden = Fighter("Tyler",6,3,2,1)
duel(durden,durden)
Tyler - HP: 72
Tyler - HP: 72
Tyler attacks Tyler for 12 damage
Tyler attacks Tyler for 12 damage
Tyler - HP: 48
Tyler - HP: 48
Tyler attacks Tyler for 12 damage
Tyler attacks Tyler for 12 damage
Tyler - HP: 24
Tyler - HP: 24
Tyler attacks Tyler for 12 damage
Tyler attacks Tyler for 12 damage
Tyler - HP: 0
Tyler - HP: 0
Everyone loses!
False
Example 3:
jack = Thief("Jack",7,2,5,1)
will = Thief("Will",8,3,4,2)
elizabeth = Thief("Elizabeth",5,3,3,2)
duel(will,jack)
Will - HP: 64
Jack - HP: 56
Will can't see Jack
Jack sneak attacks Will for 60 damage
Will - HP: 4
Jack - HP: 56
Will attacks Jack for 7 damage
Jack attacks Will for 6 damage
Will - HP: -2
Jack - HP: 49
Jack wins!
False
duel(jack,will)
Jack - HP: 49
Will - HP: -2
Jack wins!
True
jack.hidden
False
elizabeth.hidden
True
duel(jack,elizabeth)
Jack - HP: 49
Elizabeth - HP: 40
Jack can't see Elizabeth
Elizabeth sneak attacks Jack for 40 damage
Jack - HP: 9
Elizabeth - HP: 40
Jack attacks Elizabeth for 6 damage
Elizabeth attacks Jack for 7 damage
Jack - HP: 2
Elizabeth - HP: 34
Jack attacks Elizabeth for 6 damage
Elizabeth attacks Jack for 7 damage
Jack - HP: -5
Elizabeth - HP: 28
Elizabeth wins!
False
Example 4:
sean_bean = Fighter("Boromir",5,5,3,1)
orc1 = Fighter("Orc",1,5,1,1)
orc2 = Fighter("Orc",1,5,1,1)
orc3 = Fighter("Orc",1,5,1,1)
orc4 = Fighter("Orc",1,5,1,1)
duel(orc1,sean_bean)
Orc - HP: 12
Boromir - HP: 60
Orc attacks Boromir for 16 damage
Boromir attacks Orc for 16 damage
Orc - HP: -4
Boromir - HP: 44
Boromir wins!
False
duel(orc2,sean_bean)
Orc - HP: 12
Boromir - HP: 44
Orc attacks Boromir for 16 damage
Boromir attacks Orc for 16 damage
Orc - HP: -4
Boromir - HP: 28
Boromir wins!
False
duel(orc3,sean_bean)
Orc - HP: 12
Boromir - HP: 28
Orc attacks Boromir for 16 damage
Boromir attacks Orc for 16 damage
Orc - HP: -4
Boromir - HP: 12
Boromir wins!
False
duel(orc4,sean_bean)
Orc - HP: 12
Boromir - HP: 12
Orc attacks Boromir for 16 damage
Orc - HP: 12
Boromir - HP: -4
Orc wins!
True
duel(sean_bean,orc1)
Boromir - HP: -4
Orc - HP: -4
Everyone loses!
False
You have decided to implement a tournament feature within your RPG. Since you want the winner to be somewhat unpredictable, you come up with a scheme to keep the playing field as balanced as possible despite widely varying ability levels: for each round, the two Adventurers with the highest remaining HP will be forced to fight each other until one of them is eliminated. This will hopefully keep the weaker characters in the tournament until the stronger characters have worn each other down.
Create a function called tournament(adv_list), which takes in a single parameter, a list of Adventurer objects adv_list, and pits them against each other until there is a single winner to return. Specifically:
● If adv_list is empty, tournament should return None.
● If adv_list contains exactly one Adventurer object, tournament should return that Adventurer object.
● Otherwise, tournament should do the following until there is only one Adventurer object remaining:
○ Sort adv_list by current HP. You may want to create a key function that returns the current HP of a given Adventurer object to use with the built-in sorted(), or overload the < operator for Adventurer, similar to Homework 10.
○ Pass the second highest HP Adventurer and the highest HP Adventurer into the duel function (in that order, so that the second highest HP Adventurer gets to strike first). You may assume that no Adventurer object is in the tournament list multiple times or entered the tournament list while already at 0 or less HP, so duel is guaranteed to have a clear winner.
○ Whichever Adventurer lost the duel is removed from adv_list, and the process repeats. Remember to re-sort the list, as the winner of the duel may now have substantially less HP.
Constraints:
● Your file should only contain class definitions and functions. No code should be included outside of the classes/functions (though, as usual, comments are fine).
● You must name all classes, methods, and instance variables EXACTLY as specified.
● You should not import any modules.
Examples: (italic text is printed, bold textis returned)
Example 1:
print(tournament([]))
None
Example 2:
mario = Wizard("Mario",8,4,4,2)
link = Fighter("Link",7,4,2,1)
fox = Thief("Fox",9,2,4,2)
ness = Wizard("Ness",6,1,1,4)
smashls = [mario,link,fox,ness]
winner = tournament(smashls)
Fox - HP: 72
Link - HP: 84
Fox sneak attacks Link for 65 damage
Link attacks Fox for 14 damage
Fox - HP: 58
Link - HP: 19
Fox attacks Link for 6 damage
Link attacks Fox for 14 damage
Fox - HP: 44
Link - HP: 13
Fox attacks Link for 6 damage
Link attacks Fox for 14 damage
Fox - HP: 30
Link - HP: 7
Fox attacks Link for 6 damage
Link attacks Fox for 14 damage
Fox - HP: 16
Link - HP: 1
Fox attacks Link for 6 damage
Fox - HP: 16
Link - HP: -5
Fox wins!
Ness - HP: 36
Mario - HP: 48
Ness casts fireball on Mario for 18 damage
Mario casts fireball on Ness for 24 damage
Ness - HP: 12
Mario - HP: 30
Ness casts fireball on Mario for 18 damage
Mario casts fireball on Ness for 24 damage
Ness - HP: -12
Mario - HP: 12
Mario wins!
Mario - HP: 12
Fox - HP: 16
Mario attacks Fox for 8 damage
Fox attacks Mario for 6 damage
Mario - HP: 6
Fox - HP: 8
Mario attacks Fox for 8 damage
Mario - HP: 6
Fox - HP: 0 Mario wins!
winner.name
'Mario'
Example 3:
jaina = Wizard("Jaina",15,1,2,6)
frisk = Fighter("Frisk",1,1,1,1)
madeline = Thief("Madeline",4,1,10,1)
gandalf = Wizard("Gandalf",19,4,3,1)
arthur = Fighter("Arthur",3,4,4,4)
wesley = Thief("Wesley",14,4,5,1)
winner = tournament([jaina,frisk,madeline,gandalf,arthur,wesley])
Wesley - HP: 112
Gandalf - HP: 114
Wesley sneak attacks Gandalf for 95 damage
Gandalf casts fireball on Wesley for 57 damage
Wesley - HP: 55
Gandalf - HP: 19
Wesley attacks Gandalf for 8 damage
Gandalf attacks Wesley for 8 damage
Wesley - HP: 47
Gandalf - HP: 11
Wesley attacks Gandalf for 8 damage
Gandalf attacks Wesley for 8 damage
Wesley - HP: 39
Gandalf - HP: 3
Wesley attacks Gandalf for 8 damage
Wesley - HP: 39 Gandalf - HP: -5
Wesley wins!
Wesley - HP: 39
Jaina - HP: 90
Wesley attacks Jaina for 8 damage
Jaina casts fireball on Wesley for 45 damage
Wesley - HP: -6 Jaina - HP: 82
Jaina wins!
Arthur - HP: 36
Jaina - HP: 82
Arthur attacks Jaina for 14 damage
Jaina casts fireball on Arthur for 45 damage
Arthur - HP: -9 Jaina - HP: 68
Jaina wins!
Madeline - HP: 32
Jaina - HP: 68
Madeline sneak attacks Jaina for 70 damage
Madeline - HP: 32
Jaina - HP: -2 Madeline wins!
Frisk - HP: 12
Madeline - HP: 32
Frisk attacks Madeline for 8 damage
Madeline attacks Frisk for 5 damage
Frisk - HP: 7
Madeline - HP: 24
Frisk attacks Madeline for 8 damage
Madeline attacks Frisk for 5 damage
Frisk - HP: 2
Madeline - HP: 16
Frisk attacks Madeline for 8 damage
Madeline attacks Frisk for 5 damage
Frisk - HP: -3
Madeline - HP: 8
Madeline wins!
winner.name
'Madeline'