Enable Javascript in your browser and then refresh this page, for a much enhanced experience.
Phew; moved defense logic from Defender to Warrior solution in Clear category for The Warlords by kkkkk
class Warrior:
"""Base class for fighting unit."""
def __init__(self):
self.max_health = 50
self.health = self.max_health
self.attack = 5
self.is_alive = True
self.vampirism = 0
self.defense = 0
self.heal_power = 0
self.next = None
def fight(self, opponent, heal=True):
"""Return status of fighter after fight to death.
The 'heal' argument will be False in a straight fight.
"""
while self.is_alive and opponent.is_alive:
# Attack.
self.hit(opponent)
# Heal thyself if a healer is behind this warrior.
if heal and self.next:
self.next.heal(self)
if not opponent.is_alive:
continue
# Opponent counter-attacts, as they're still alive.
opponent.hit(self)
# Heal opponent, if possible.
if heal and opponent.next:
opponent.next.heal(opponent)
return self.is_alive
def hit(self, opponent):
"""Actions taken to wound an opponent."""
opponent.wounded(self.attack)
def wounded(self, attack_amount):
"""Return actual damage and update status when opponent strikes."""
if self.defense:
damage = attack_amount - self.defense
else:
damage = attack_amount
if attack_amount > self.defense:
self.health = max(0, self.health - damage)
self.is_alive = True if self.health > 0 else False
return damage
def heal(self, ally):
"""If a healer, heal ally standing immediately before this healer."""
if self.heal_power:
ally.health = min(ally.max_health, ally.health + self.heal_power)
def equip_weapon(self, weapon):
"""Add the properties of the given weapon."""
self.health = max(0, weapon.health_addition + self.health)
self.is_alive = True if self.health > 0 else False
self.attack = max(0, weapon.attack_addition + self.attack)
if self.defense:
self.defense = max(0, weapon.defense_addition + self.defense)
if self.vampirism:
self.vampirism = max(0, weapon.vampirism_addition + self.vampirism)
if self.heal_power:
self.heal_power = max(0, weapon.healing_addition + self.heal_power)
def __str__(self):
"""Return string representing readable form of this class."""
return (f"type: {type(self)}, alive: {self.is_alive}, "
f"health: {self.health}, attack: {self.attack}\n")
class Knight(Warrior):
"""Specialized fighting unit based on Warrior."""
def __init__(self):
super().__init__()
self.attack = 7
class Vampire(Warrior):
"""Specialized fighting unit that has restorative powers."""
def __init__(self):
super().__init__()
self.max_health = 40
self.health = self.max_health
self.attack = 4
self.vampirism = 50
def hit(self, opponent):
"""Attack opponent, but gain some restorative strength afterwards."""
damage = opponent.wounded(self.attack)
self.health = min(self.health + int(damage * (self.vampirism / 100)),
self.max_health)
self.is_alive = True if self.health > 0 else False
class Defender(Warrior):
"""Specialized fighting unit based on Warrior; provides extra defense."""
def __init__(self):
super().__init__()
self.max_health = 60
self.health = self.max_health
self.defense = 2
self.attack = 3
class Lancer(Warrior):
"""Specialized fighter that wounds two units with the same attack."""
def __init__(self):
super().__init__()
self.max_health = 50
self.health = self.max_health
self.attack = 6
def hit(self, opponent):
"""Attack opponent and half-wound second opponent."""
opponent.wounded(self.attack)
if opponent.next:
opponent.next.wounded(int(self.attack * .5))
class Healer(Warrior):
"""Specialized warrior that cannot attack, only heal."""
def __init__(self):
super().__init__()
self.max_health = 60
self.health = self.max_health
self.attack = 0
self.heal_power = 2
class Warlord(Warrior):
"""Inclusion of this type of warrior allows army unit rearrangement."""
def __init__(self):
super().__init__()
self.max_health = 100
self.health = self.max_health
self.attack = 4
self.defense = 2
class Rookie(Warrior):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.max_health = 50
self.health = self.max_health
self.attack = 1
class Weapon:
"""A weapon changes the soldier's characteristics when using it."""
def __init__(self, health, attack, defense=0, vampirism=0, heal_power=0):
self.health_addition = health
self.attack_addition = attack
self.defense_addition = defense
self.vampirism_addition = vampirism
self.healing_addition = heal_power
class Sword(Weapon):
"""Weapon that updates health and attack points."""
def __init__(self):
super().__init__(5, 2)
class Shield(Weapon):
"""Weapon that modifies health, attack and defense points."""
def __init__(self):
super().__init__(20, -1, defense=2)
class GreatAxe(Weapon):
"""Weapon that modifies health, attack, defense and vampirism points."""
def __init__(self):
super().__init__(-15, 5, defense=-2, vampirism=10)
class Katana(Weapon):
"""Weapon that modifies health, attack, defense and vampirism points."""
def __init__(self):
super().__init__(-20, 6, defense=-5, vampirism=50)
class MagicWand(Weapon):
"""Weapon that updates health, attack and healing points."""
def __init__(self):
super().__init__(30, 3, heal_power=3)
class Army:
"""Collection of fighting units."""
def __init__(self):
self.units = []
self.is_alive = False
self.has_warlord = False
def add_units(self, unit_type, number_of_units):
"""Add fighting units to army.
Units fight in the order they're added.
"""
if unit_type == Warlord:
# Only one Warlord per army.
if self.has_warlord:
return
self.has_warlord = True
number_of_units = 1
self.is_alive = True
self.units.extend([unit_type() for n in range(number_of_units)])
self.link_fighters()
def move_units(self):
"""Rearrange army to its best advantage."""
if not self.has_warlord:
return
# Separate the types of warriors.
lancers = []
damagers = []
healers = []
warlord = None
for fighter in self.units:
if not fighter.is_alive:
continue
if isinstance(fighter, Lancer):
lancers.append(fighter)
elif isinstance(fighter, Warlord):
warlord = fighter
elif isinstance(fighter, Healer):
healers.append(fighter)
else:
damagers.append(fighter)
# Re-order them: lancers first or a damager if no lancer,
# healers, the remaining lancers and damagers, then the warlord.
self.units = []
if lancers:
self.units.append(lancers[0])
del lancers[0]
elif damagers:
self.units.append(damagers[0])
del damagers[0]
self.units.extend(healers)
if lancers:
self.units.extend(lancers)
self.units.extend(damagers)
if warlord:
self.units.append(warlord)
self.link_fighters()
if not self.units:
self.is_alive = False
def link_fighters(self):
"""Set the 'next' field of each fighter in the army."""
for idx in range(len(self.units) - 1):
self.units[idx].next = self.units[idx + 1]
def unlink_fighters(self):
"""Set the 'next' field of each fighter in the army."""
for idx in range(len(self.units)):
self.units[idx].next = None
def fighter(self):
"""Return next fighter that's still alive."""
if not self.units or not self.is_alive:
return None
for fighter in self.units:
if fighter.is_alive:
return fighter
# If none of the units have available fighters, this army is dead.
self.is_alive = False
return None
def fighters(self):
"""Return list of all fighters that are still alive."""
if not self.units or not self.is_alive:
return []
# These fighters do not need to be linked.
self.unlink_fighters()
fighters = []
for fighter in self.units:
if fighter.is_alive:
fighters.append(fighter)
return fighters
def __str__(self):
"""Return string representing readable form of this class."""
output = "ARMY ===============================================\n"
output += f'is_alive: {self.is_alive}\n'
for fighter in self.units:
output += str(fighter)
return output
class Battle:
"""Coordinates fight between two armies."""
def __init__(self):
self.is_alive = True
def fight(self, army1, army2):
"""Loop until one or the other army is dead."""
army1.move_units()
army2.move_units()
fighter1 = army1.fighter()
fighter2 = army2.fighter()
while army1.is_alive and army2.is_alive:
if fighter1.fight(fighter2):
army2.move_units()
fighter2 = army2.fighter()
else:
army1.move_units()
fighter1 = army1.fighter()
return True if army1.is_alive else False
def straight_fight(self, army1, army2):
"""Fight as a series of individual duals until one army is left."""
army1_survivors = army1.fighters()
army2_survivors = army2.fighters()
while army1_survivors and army2_survivors:
for fighter1, fighter2 in zip(army1_survivors, army2_survivors):
fighter1.fight(fighter2, heal=False)
army1.move_units()
army1_survivors = army1.fighters()
army2.move_units()
army2_survivors = army2.fighters()
return True if army1_survivors else False
def fight(unit_1, unit_2):
return unit_1.fight(unit_2)
Dec. 8, 2019
Comments: