• Army Battles

 

Why the fourth test fails. With army1 and with army2, for some reason, Army 1 wins, although army 2 has a whole unit in reserve.

I came to the conclusion that the unit of the first army, after killing an enemy unit, beats the next enemy unit, and the unit of the second army does not have such an opportunity.

At the end of the task clarification - the first army has the advantage to start each battle. So I understand it means every round of the battle and not the battle itself. Right?

Code:

class Army:
    def __init__(self):
        self.units = []

    def add_units(self, unit, count):
        self.units.extend([unit for i in range(count)])


class Warrior:
    def __init__(self):
        self.health_points = 50
        self.attack_points = 5

    def take_damage(self, damage):
        self.health_points -= damage

    def an_attack(self, enemy_health_point):
        enemy_health_point.take_damage(self.attack_points)

    @property
    def is_alive(self):
        return self.health_points > 0


class Knight(Warrior):
    def __init__(self):
        super(Knight, self).__init__()
        self.attack_points = 7


class Battle:

    def fight(self, army_1, army_2):
        self.army_1 = iter(army_1.units)
        self.army_2 = iter(army_2.units)

        def next_unit(army):
            return next(army)()

        unit_1 = next_unit(self.army_1)
        unit_2 = next_unit(self.army_2)
        count = 0
        while True:
            if unit_1.is_alive:
                unit_1.an_attack(unit_2)
            else:
                try:
                    unit_1 = next_unit(self.army_1)
                except StopIteration:
                    return False

            if unit_2.is_alive:
                unit_2.an_attack(unit_1)
            else:
                try:
                    unit_2 = next_unit(self.army_2)
                except StopIteration:
                    return True


def fight(unit_1, unit_2):
    while True:
        unit_1.an_attack(unit_2)
        if not unit_2.is_alive:
            return True
        unit_2.an_attack(unit_1)
        if not unit_1.is_alive:
            return False


if __name__ == '__main__':
    chuck = Warrior()
    bruce = Warrior()
    carl = Knight()
    dave = Warrior()
    mark = Warrior()

    assert fight(chuck, bruce) == True
    assert fight(dave, carl) == False
    assert chuck.is_alive == True
    assert bruce.is_alive == False
    assert carl.is_alive == True
    assert dave.is_alive == False
    assert fight(carl, mark) == False
    assert carl.is_alive == False

    army_1 = Army()
    army_2 = Army()
    army_1.add_units(Warrior, 20)
    army_2.add_units(Warrior, 21)
    battle = Battle()
    assert battle.fight(army_1, army_2) == True
.