From 5353a1af9c908bef9f83e64ba1aa6561c23cf1e5 Mon Sep 17 00:00:00 2001 From: Oleksii Ivanov Date: Wed, 9 Oct 2024 23:09:01 +0200 Subject: [PATCH] Add knights fighting solution --- .flake8 | 3 +- app/battle/__init__.py | 1 + app/battle/battle.py | 22 ++++ app/config/__init__.py | 1 + app/config/constants.py | 37 +++++++ app/entities/__init__.py | 3 + app/entities/armour.py | 4 + app/entities/potion.py | 4 + app/entities/weapon.py | 4 + app/knight/__init__.py | 2 + app/knight/factory.py | 36 +++++++ app/knight/knight.py | 47 +++++++++ app/main.py | 219 +++------------------------------------ 13 files changed, 175 insertions(+), 208 deletions(-) create mode 100644 app/battle/__init__.py create mode 100644 app/battle/battle.py create mode 100644 app/config/__init__.py create mode 100644 app/config/constants.py create mode 100644 app/entities/__init__.py create mode 100644 app/entities/armour.py create mode 100644 app/entities/potion.py create mode 100644 app/entities/weapon.py create mode 100644 app/knight/__init__.py create mode 100644 app/knight/factory.py create mode 100644 app/knight/knight.py diff --git a/.flake8 b/.flake8 index d7459204..97aeb9a5 100644 --- a/.flake8 +++ b/.flake8 @@ -1,7 +1,8 @@ [flake8] inline-quotes = " -ignore = E203, E266, W503, ANN002, ANN003, ANN101, ANN102, ANN401, N807, N818 +ignore = E203, E266, W503, ANN002, ANN003, ANN101, ANN102, ANN401, N807, N818, F401 max-line-length = 79 max-complexity = 18 select = B,C,E,F,W,T4,B9,ANN,Q0,N8,VNE exclude = venv, tests + diff --git a/app/battle/__init__.py b/app/battle/__init__.py new file mode 100644 index 00000000..1d6ddb8f --- /dev/null +++ b/app/battle/__init__.py @@ -0,0 +1 @@ +from .battle import Battle diff --git a/app/battle/battle.py b/app/battle/battle.py new file mode 100644 index 00000000..aa72a644 --- /dev/null +++ b/app/battle/battle.py @@ -0,0 +1,22 @@ +from typing import Dict +from app.knight import Knight + + +class Battle: + def __init__(self) -> None: + pass + + def fight(self, knight1: Knight, knight2: Knight) -> Dict[str, int]: + damage_to_knight1 = max(0, knight2.power - knight1.protection) + damage_to_knight2 = max(0, knight1.power - knight2.protection) + + knight1.take_damage(damage_to_knight1) + knight2.take_damage(damage_to_knight2) + + knight1.hp = max(knight1.hp, 0) + knight2.hp = max(knight2.hp, 0) + + return { + knight1.name: knight1.hp, + knight2.name: knight2.hp, + } diff --git a/app/config/__init__.py b/app/config/__init__.py new file mode 100644 index 00000000..a1bbc39b --- /dev/null +++ b/app/config/__init__.py @@ -0,0 +1 @@ +from .constants import KNIGHTS diff --git a/app/config/constants.py b/app/config/constants.py new file mode 100644 index 00000000..bddaf8b8 --- /dev/null +++ b/app/config/constants.py @@ -0,0 +1,37 @@ +KNIGHTS = { + "lancelot": { + "name": "Lancelot", + "power": 40, + "hp": 90, + "armour": [ + {"part": "helmet", "protection": 10}, + {"part": "shield", "protection": 15}, + ], + "weapon": {"name": "Sword", "power": 30}, + "potion": {"name": "Blessing", "effect": {"hp": 5, "power": 10}}, + }, + "mordred": { + "name": "Mordred", + "power": 45, + "hp": 100, + "armour": [{"part": "breastplate", "protection": 20}], + "weapon": {"name": "Axe", "power": 35}, + "potion": None, + }, + "arthur": { + "name": "Arthur", + "power": 50, + "hp": 80, + "armour": [], + "weapon": {"name": "Lance", "power": 40}, + "potion": None, + }, + "red_knight": { + "name": "Red Knight", + "power": 35, + "hp": 70, + "armour": [{"part": "breastplate", "protection": 25}], + "weapon": {"name": "Sword", "power": 45}, + "potion": {"name": "Blessing", "effect": {"hp": 10, "power": 5}}, + }, +} diff --git a/app/entities/__init__.py b/app/entities/__init__.py new file mode 100644 index 00000000..898d2cd9 --- /dev/null +++ b/app/entities/__init__.py @@ -0,0 +1,3 @@ +from .armour import Armour +from .weapon import Weapon +from .potion import Potion diff --git a/app/entities/armour.py b/app/entities/armour.py new file mode 100644 index 00000000..96a380ee --- /dev/null +++ b/app/entities/armour.py @@ -0,0 +1,4 @@ +class Armour: + def __init__(self, part: str, protection: int) -> None: + self.part = part + self.protection = protection diff --git a/app/entities/potion.py b/app/entities/potion.py new file mode 100644 index 00000000..c8a7313b --- /dev/null +++ b/app/entities/potion.py @@ -0,0 +1,4 @@ +class Potion: + def __init__(self, name: str, effect: dict) -> None: + self.name = name + self.effect = effect diff --git a/app/entities/weapon.py b/app/entities/weapon.py new file mode 100644 index 00000000..66bd4e76 --- /dev/null +++ b/app/entities/weapon.py @@ -0,0 +1,4 @@ +class Weapon: + def __init__(self, name: str, power: int) -> None: + self.name = name + self.power = power diff --git a/app/knight/__init__.py b/app/knight/__init__.py new file mode 100644 index 00000000..9cddfe49 --- /dev/null +++ b/app/knight/__init__.py @@ -0,0 +1,2 @@ +from .knight import Knight +from .factory import create_knight diff --git a/app/knight/factory.py b/app/knight/factory.py new file mode 100644 index 00000000..02defc9f --- /dev/null +++ b/app/knight/factory.py @@ -0,0 +1,36 @@ +from app.entities import Armour, Weapon, Potion +from .knight import Knight + + +def create_armour(armour_data: list) -> list: + return [Armour(arm["part"], arm["protection"]) for arm in armour_data] + + +def create_weapon(weapon_data: dict) -> Weapon: + return Weapon(weapon_data["name"], weapon_data["power"]) + + +def create_potion(potion_data: dict) -> Potion: + if potion_data is None: + return None + return Potion(potion_data["name"], potion_data["effect"]) + + +def create_knight(knight_data: dict) -> Knight: + armour = create_armour(knight_data["armour"]) + weapon = create_weapon(knight_data["weapon"]) + potion = create_potion(knight_data.get("potion")) + return Knight( + name=knight_data["name"], + base_power=knight_data["power"], + hp=knight_data["hp"], + armour=armour, + weapon=weapon, + potion=potion, + ) + + +def get_knights(knights_config: dict) -> list: + return [ + create_knight(knight_data) for knight_data in knights_config.values() + ] diff --git a/app/knight/knight.py b/app/knight/knight.py new file mode 100644 index 00000000..d69022ff --- /dev/null +++ b/app/knight/knight.py @@ -0,0 +1,47 @@ +from app.entities import Weapon, Potion + + +class Knight: + def __init__( + self, + name: str, + base_power: int, + hp: int, + armour: list, + weapon: Weapon, + potion: Potion = None, + ) -> None: + self.name = name + self.base_power = base_power + self.hp = hp + self.armour = armour + self.weapon = weapon + self.potion = potion + + self.power = self.calculate_power() + self.protection = self.calculate_protection() + self.hp = self.calculate_total_hp() + + def calculate_power(self) -> int: + total_power = self.base_power + self.weapon.power + if self.potion and "power" in self.potion.effect: + total_power += self.potion.effect["power"] + return total_power + + def calculate_protection(self) -> int: + total_protection = sum(arm.protection for arm in self.armour) + if self.potion and "protection" in self.potion.effect: + total_protection += self.potion.effect.get("protection", 0) + return total_protection + + def calculate_total_hp(self) -> int: + total_hp = self.hp + if self.potion and "hp" in self.potion.effect: + total_hp += self.potion.effect["hp"] + return total_hp + + def take_damage(self, damage: int) -> None: + self.hp = max(0, self.hp - damage) + + def is_defeated(self) -> bool: + return self.hp == 0 diff --git a/app/main.py b/app/main.py index 445ffb14..faf6d154 100644 --- a/app/main.py +++ b/app/main.py @@ -1,214 +1,19 @@ -KNIGHTS = { - "lancelot": { - "name": "Lancelot", - "power": 35, - "hp": 100, - "armour": [], - "weapon": { - "name": "Metal Sword", - "power": 50, - }, - "potion": None, - }, - "arthur": { - "name": "Arthur", - "power": 45, - "hp": 75, - "armour": [ - { - "part": "helmet", - "protection": 15, - }, - { - "part": "breastplate", - "protection": 20, - }, - { - "part": "boots", - "protection": 10, - } - ], - "weapon": { - "name": "Two-handed Sword", - "power": 55, - }, - "potion": None, - }, - "mordred": { - "name": "Mordred", - "power": 30, - "hp": 90, - "armour": [ - { - "part": "breastplate", - "protection": 15, - }, - { - "part": "boots", - "protection": 10, - } - ], - "weapon": { - "name": "Poisoned Sword", - "power": 60, - }, - "potion": { - "name": "Berserk", - "effect": { - "power": +15, - "hp": -5, - "protection": +10, - } - } - }, - "red_knight": { - "name": "Red Knight", - "power": 40, - "hp": 70, - "armour": [ - { - "part": "breastplate", - "protection": 25, - } - ], - "weapon": { - "name": "Sword", - "power": 45 - }, - "potion": { - "name": "Blessing", - "effect": { - "hp": +10, - "power": +5, - } - } - } -} +from app.battle import Battle +from app.knight.factory import get_knights +from app.config import KNIGHTS -def battle(knightsConfig): - # BATTLE PREPARATIONS: +def battle(knights_config: dict) -> dict: + knights = get_knights(knights_config) - # lancelot - lancelot = knightsConfig["lancelot"] + first_battle = Battle() + result1 = first_battle.fight(knights[0], knights[2]) - # apply armour - lancelot["protection"] = 0 - for a in lancelot["armour"]: - lancelot["protection"] += a["protection"] + second_battle = Battle() + result2 = second_battle.fight(knights[1], knights[3]) - # apply weapon - lancelot["power"] += lancelot["weapon"]["power"] + return {**result1, **result2} - # apply potion if exist - if lancelot["potion"] is not None: - if "power" in lancelot["potion"]["effect"]: - lancelot["power"] += lancelot["potion"]["effect"]["power"] - if "protection" in lancelot["potion"]["effect"]: - lancelot["protection"] += lancelot["potion"]["effect"]["protection"] - - if "hp" in lancelot["potion"]["effect"]: - lancelot["hp"] += lancelot["potion"]["effect"]["hp"] - - # arthur - arthur = knightsConfig["arthur"] - - # apply armour - arthur["protection"] = 0 - for a in arthur["armour"]: - arthur["protection"] += a["protection"] - - # apply weapon - arthur["power"] += arthur["weapon"]["power"] - - # apply potion if exist - if arthur["potion"] is not None: - if "power" in arthur["potion"]["effect"]: - arthur["power"] += arthur["potion"]["effect"]["power"] - - if "protection" in arthur["potion"]["effect"]: - arthur["protection"] += arthur["potion"]["effect"]["protection"] - - if "hp" in arthur["potion"]["effect"]: - arthur["hp"] += arthur["potion"]["effect"]["hp"] - - # mordred - mordred = knightsConfig["mordred"] - - # apply armour - mordred["protection"] = 0 - for a in mordred["armour"]: - mordred["protection"] += a["protection"] - - # apply weapon - mordred["power"] += mordred["weapon"]["power"] - - # apply potion if exist - if mordred["potion"] is not None: - if "power" in mordred["potion"]["effect"]: - mordred["power"] += mordred["potion"]["effect"]["power"] - - if "protection" in mordred["potion"]["effect"]: - mordred["protection"] += mordred["potion"]["effect"]["protection"] - - if "hp" in mordred["potion"]["effect"]: - mordred["hp"] += mordred["potion"]["effect"]["hp"] - - # red_knight - red_knight = knightsConfig["red_knight"] - - # apply armour - red_knight["protection"] = 0 - for a in red_knight["armour"]: - red_knight["protection"] += a["protection"] - - # apply weapon - red_knight["power"] += red_knight["weapon"]["power"] - - # apply potion if exist - if red_knight["potion"] is not None: - if "power" in red_knight["potion"]["effect"]: - red_knight["power"] += red_knight["potion"]["effect"]["power"] - - if "protection" in red_knight["potion"]["effect"]: - red_knight["protection"] += red_knight["potion"]["effect"]["protection"] - - if "hp" in red_knight["potion"]["effect"]: - red_knight["hp"] += red_knight["potion"]["effect"]["hp"] - - # ------------------------------------------------------------------------------- - # BATTLE: - - # 1 Lancelot vs Mordred: - lancelot["hp"] -= mordred["power"] - lancelot["protection"] - mordred["hp"] -= lancelot["power"] - mordred["protection"] - - # check if someone fell in battle - if lancelot["hp"] <= 0: - lancelot["hp"] = 0 - - if mordred["hp"] <= 0: - mordred["hp"] = 0 - - # 2 Arthur vs Red Knight: - arthur["hp"] -= red_knight["power"] - arthur["protection"] - red_knight["hp"] -= arthur["power"] - red_knight["protection"] - - # check if someone fell in battle - if arthur["hp"] <= 0: - arthur["hp"] = 0 - - if red_knight["hp"] <= 0: - red_knight["hp"] = 0 - - # Return battle results: - return { - lancelot["name"]: lancelot["hp"], - arthur["name"]: arthur["hp"], - mordred["name"]: mordred["hp"], - red_knight["name"]: red_knight["hp"], - } - - -print(battle(KNIGHTS)) +if __name__ == "__main__": + battle(KNIGHTS)