Enable Javascript in your browser and then refresh this page, for a much enhanced experience.
Equipements class for list weapons, and new init_... attributes for manage weapons. solution in Clear category for The Weapons by Phil15
######################### CHANGELOG of 8) The Weapons ##########################
# Some improvments:
# * vampirism: not 0.5 but 50 (and // 100 later)
# * __init__ in Warrior class change for...
# * Shorter __init__ method in Warrior subclasses, thanks to super().__init__
# * Because of that, Rookie from tests distorted results. FIX with lines 73-74.
# * New Army.units property (it's basic).
# New weapons subclasses of new Weapon class.
# New Equipements class: list of weapons, with 5 attributes.
# In Warrior class:
# * hit method in warrior class had two useless lines, so removed.
# * New attribute: weapons, an instance of Equipements.
# * New attributes for unit specifications without weapons:
# init_max_health, init_attack, init_defense, init_vampirism, init_heal_power.
# * equip_weapon method to add a weapon to a warrior.
# * update_attr method to manage attributes according to weapons.
class Warrior:
"""Define a Warrior, and his general abilities."""
def __init__(self, health=50, attack=5):
self.init_max_health = health
self.init_attack = attack
self.health = self.init_max_health
self.weapons = Equipements()
self.update_attr()
@property
def is_alive(self) -> bool:
"""Say if the unit self is alive or not."""
return self.health > 0
########################### Management of a hit ############################
def hit(self, other, half_damage=False):
"""self hit other (with half damage??)."""
if self.is_alive:
damage = self.attack
if half_damage: damage //= 2
taken_damage = other.take_a_hit_of(damage)
self.use_vampirism(taken_damage)
def take_a_hit_of(self, damage):
"""self take a hit of given damage, return taken damage."""
taken_damage = self.use_defense(damage)
self.health -= taken_damage
return taken_damage
######################## Second hit from a Lancer? #########################
def is_lancer_then_hit(self, other):
"""If self is a lancer, then he hits other with half damage."""
if isinstance(self, Lancer) and other:
self.hit(other, True)
########## Use special attributes: defense, vampirism, heal_power ##########
def use_defense(self, damage):
"""damage -= self.defense (if self has defense attribute)."""
if hasattr(self, 'defense'):
taken_damage = max(0, damage - self.defense)
else:
taken_damage = damage
return taken_damage
def use_vampirism(self, damage):
"""self.health += bonus_vampirism (if self has vampirism attribute)."""
if hasattr(self, 'vampirism'):
bonus_vampirism = (damage * self.vampirism) // 100
self.health = min(self.max_health, self.health + bonus_vampirism)
def heal(self, unit):
"""unit.health += self.heal_power (if self has heal_power attribute)."""
if hasattr(self, 'heal_power') and unit.is_alive:
unit.health = min(unit.max_health, unit.health + self.heal_power)
########################## Management of weapons ###########################
def equip_weapon(self, weapon):
"""Add a weapon to the warrior."""
self.weapons.append(weapon)
self.update_attr(weapon)
def update_attr(self, new_weapon=None):
"""Update attributes according to weapons:
max_health, health, attack, defense, vampirism, heal_power."""
if self.__class__ not in (Warrior, Knight, Defender, Vampire, Lancer, Healer):
self.init_attack = 1 ## Rookie warrior from tests distorted the results ##
# This is debatable: what does health do when you add a health weapon?
self.health += new_weapon.health if new_weapon else self.weapons.health
add = lambda *args: max(0, sum(args))
self.max_health = add(self.init_max_health, self.weapons.health)
self.attack = add(self.init_attack, self.weapons.attack)
if hasattr(self, 'init_defense'):
self.defense = add(self.init_defense, self.weapons.defense)
if hasattr(self, 'init_vampirism'):
self.vampirism = add(self.init_vampirism, self.weapons.vampirism)
if hasattr(self, 'init_heal_power'):
self.heal_power = add(self.init_heal_power, self.weapons.heal_power)
########################### Other types of warriors ############################
class Knight(Warrior):
"""Define a knight, it's a warrior with an increased attack of 7."""
def __init__(self):
super().__init__(50, 7)
class Defender(Warrior):
"""Define a defender, it's a warrior with a defense parameter."""
def __init__(self):
self.init_defense = 2
super().__init__(60, 3)
class Vampire(Warrior):
"""Define a vampire, capable of vampirism, a way to heal himself."""
def __init__(self):
self.init_vampirism = 50
super().__init__(40, 4)
class Lancer(Warrior):
"""Define a lancer, who can hit two units at the same time, he's vicious!"""
def __init__(self):
super().__init__(50, 6)
class Healer(Warrior):
"""Define a healer, who can heal a neighboring allied unit when he kills."""
def __init__(self):
self.init_heal_power = 2
super().__init__(60, 0)
############################## Fight of two units ##############################
def fight(unit_1, unit_2):
"""One-on-one duel"""
while unit_1.is_alive and unit_2.is_alive:
unit_1.hit(unit_2)
unit_2.hit(unit_1)
return unit_1.is_alive
############# An army is a list of warriors, with some properties ##############
class Army(list):
"""Army is a list of units."""
@property
def units(self):
"""self.units == self"""
return self
@property
def is_alive(self) -> bool:
"""Is there anyone in this army?"""
return self != [] # or bool(self)
@property
def first_warrior(self):
"""Return the first warrior of this army."""
return self[0]
@property
def second_warrior(self):
"""Is there a second warrior in this army? Return him."""
try:
return self[1]
except:
return None
def add_units(self, unit_type, number_units=1):
"""Add an amount of units of a given type."""
assert issubclass(unit_type, Warrior)
self += [unit_type() for k in range(number_units)]
@property
def remove_up_to_two_deads(self):
"""Second warrior and first warrior... Are they dead?"""
if self.second_warrior and not self.second_warrior.is_alive:
self.pop(1)
if not self.first_warrior.is_alive:
self.pop(0)
@property
def remove_the_dead(self):
"""Remove all dead warriors from this army."""
i = 0
while i < len(self):
if self[i].is_alive:
i += 1
else:
self.pop(i)
############################### EPIC BATTLES !!! ###############################
class Battle:
"""Define epic battles."""
@staticmethod
def fight(army_1, army_2) -> bool:
"""A fight IN LINE of two armies. Return 'army 1 is alive' boolean."""
while army_1.is_alive and army_2.is_alive:
unit_1, unit_2 = army_1.first_warrior, army_2.first_warrior
while unit_1.is_alive and unit_2.is_alive:
unit_1.hit(unit_2)
if army_1.second_warrior:
army_1.second_warrior.heal(unit_1)
unit_1.is_lancer_then_hit(army_2.second_warrior)
army_2.remove_up_to_two_deads
# Same thing in the other direction.
unit_2.hit(unit_1)
if army_2.second_warrior:
army_2.second_warrior.heal(unit_2)
unit_2.is_lancer_then_hit(army_1.second_warrior)
army_1.remove_up_to_two_deads
return army_1.is_alive
@staticmethod
def straight_fight(army_1, army_2) -> bool:
"""A fight between survivors of 2 armies, without help of healer/lancer.
Return 'army 1 is alive' boolean."""
while army_1.is_alive and army_2.is_alive:
for (unit_1, unit_2) in zip(army_1, army_2):
fight(unit_1, unit_2)
army_1.remove_the_dead
army_2.remove_the_dead
return army_1.is_alive
################################### WEAPONS ####################################
class Weapon:
"""Define a weapon."""
def __init__(self, health=0, attack=0, defense=0, vampirism=0, heal=0):
self.health = health
self.attack = attack
self.defense = defense
self.vampirism = vampirism
self.heal_power = heal
class Sword(Weapon):
def __init__(self):
super().__init__( 5, 2)
class Shield(Weapon):
def __init__(self):
super().__init__( 20, -1, 2)
class GreatAxe(Weapon):
def __init__(self):
super().__init__(-15, 5, -2, 10)
class Katana(Weapon):
def __init__(self):
super().__init__(-20, 6, -5, 50)
class MagicWand(Weapon):
def __init__(self):
super().__init__( 30, 3, 0, 0, 3)
class Equipements(list):
"""Define a list of weapons with additionnal attributes."""
def __init__(self):
super().__init__()
self.health = 0
self.attack = 0
self.defense = 0
self.vampirism = 0
self.heal_power = 0
def append(self, weapon):
"""Append a weapon to equipements and update attributes."""
assert isinstance(weapon, Weapon)
super().append(weapon)
self.health += weapon.health
self.attack += weapon.attack
self.defense += weapon.defense
self.vampirism += weapon.vampirism
self.heal_power += weapon.heal_power
Aug. 16, 2018
Comments: