commit 7037378cbe5d60a92c9d2e98388b53a76b6433cf Author: tovjemam Date: Wed Nov 22 22:05:31 2023 +0100 jako jo jo diff --git a/character.py b/character.py new file mode 100644 index 0000000..e369b67 --- /dev/null +++ b/character.py @@ -0,0 +1,111 @@ +from weapon import * + +class Character: + """ + Character reprezentuje postavu v RPG hre + + @Author: zbyv + @Date: 15.11.2023 + """ + + HAND_LEFT = 0 + """ + Leva ruka postavy + """ + + HAND_RIGHT = 1 + """ + Prava ruka postavy + """ + + def __init__(self, name: str, strength: int, agility: int, vitality: int) -> None: + """ + Args: + name: Nazev postavy + strength: Utocna sila postavy + agility: Hbitost postavy + vitality: Zdravi postavi + """ + + self.__name: str = name + self.__strength: int = strength + self.__agility: int = agility + self.__vitality: int = vitality + self.__weapons: list[Weapon|None] = [None, None] + + + def attack(self) -> int: + """ + Zjisti utocnou silu postavy + + Returns: + Utocna sila postavy + """ + + ret = self.__strength + + for weapon in self.__weapons: + if weapon: + ret += weapon.attack + + return ret + + def __defense(self) -> int: + defense = self.__agility + + for weapon in self.__weapons: + if weapon: + defense += weapon.defense + + return defense + + def defend(self, attack: int) -> int: + """ + Vystavi postavu utoku + + Args: + attack: Utocna sila nepritele + + Returns: + Zdravi ztracene pri utoku + """ + + loss = attack - self.__defense() + + if loss < 0: + return 0 + + loss = min(self.__vitality, loss) + self.__vitality -= loss + return loss + + def is_alive(self) -> bool: + """ + Zjisti, jestli je postava nazivu + + Returns: + True pokud (zdravi > 0), jinak False + """ + + return self.__vitality > 0 + + def take_weapon(self, weapon: Weapon|None, hand: int) -> bool: + """ + Vlozi postave do ruky zbran, pokud v teto ruce doposud zadnou zbran nema + + Args: + weapon: Zbran, ktera bude vlozena postave do ruky + hand: Ruka, do ktere postave bude zbran vlozena + + Returns: + True pokud si postava zbran vzala, jinak False + """ + + if not self.__weapons[hand]: + self.__weapons[hand] = weapon + return True + else: + return False + + def __str__(self) -> str: + return f"{self.__name} [{self.__vitality}] ({self.attack()}/{self.__defense()})" diff --git a/rpg.py b/rpg.py new file mode 100644 index 0000000..4585c8e --- /dev/null +++ b/rpg.py @@ -0,0 +1,98 @@ +from character import * + +class RPG: + """ + Hlavni trida RPG hry + + @Author: zbyv + @Date: 15.11.2023 + """ + + def __init__(self) -> None: + pass + + def input_character(self) -> Character: + """ + Vytvori postavu na zaklade udaju nactenych ze standartniho vstupu + + Returns: + vytvorena postava + """ + + return Character(input("Jmeno postavy: "), int(input("Sila: ")), int(input("Hbitost: ")), int(input("Zdravi: "))) + + def input_weapon(self) -> Weapon|None: + """ + Vytvori zbran na zaklade udaju nactenych ze standartniho vstupu + + Returns: + vytvorena zbran, nebo None, pokud byl nazev zbrane prazdny + """ + + name = input("Nazev zbrane: ") + if name == "": + return None + + return Weapon(name, int(input("Utok: ")), int(input("Obrana: "))) + + def equip_character(self, character: Character, left: Weapon|None, right: Weapon|None) -> None: + """ + Vyzbroji postavu zadanymi zbranemi, avsak stavajici zbrane nebudou nahrazeny. + + Args: + character: Postava pro vyzbrojeni + left: Zbran do leve ruky + right: Zbran do prave ruky + """ + + character.take_weapon(left, Character.HAND_LEFT) + character.take_weapon(right, Character.HAND_RIGHT) + + @staticmethod + def __process_attack(attacker: Character, defender: Character) -> bool: + dmg = defender.defend(attacker.attack()) + print(f"utoci {attacker} a dava {dmg} zraneni") + return not defender.is_alive() + + + def fight(self, character1: Character, character2: Character) -> Character: + """ + Spusti souboj mezi postavami + + Args: + character1: postava souboje, ktera utoci jako prvni + character2: postava souboje, ktera brani jako prvni + + Returns: + postava, ktera souboj vyhrala + """ + + + while True: + if RPG.__process_attack(character1, character2): + return character1 + + if RPG.__process_attack(character2, character1): + return character2 + + def run(self) -> None: + """ + Spusti hru + """ + + character1 = self.input_character() + self.equip_character(character1, self.input_weapon(), self.input_weapon()) + + character2 = self.input_character() + self.equip_character(character2, self.input_weapon(), self.input_weapon()) + + winner = self.fight(character1, character2) + + print(f"Vitez: {winner}") + +def main() -> None: + rpg = RPG() + rpg.run() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/tests/character_test.py b/tests/character_test.py new file mode 100644 index 0000000..a4c81c9 --- /dev/null +++ b/tests/character_test.py @@ -0,0 +1,90 @@ +import random +import unittest +from character import Character +from weapon import Weapon + +class CharacterTest(unittest.TestCase): + def setUp(self) -> None: + super().setUp() + self.strength = random.randrange(1,50) + self.attackL = random.randrange(1,50) + self.attackR = random.randrange(1,50) + self.agility = random.randrange(1,50) + self.defenseL = random.randrange(1,50) + self.defenseR = random.randrange(1,50) + self.vitality = random.randrange(1,50) + + def assertCharacter(self, char:Character, name:str, vitality:int, attack:int, defense:int, msg:str): + text = f"{name} [{vitality}] ({attack}/{defense})" + self.assertEqual(text, char.__str__(), msg) + + def test_init(self): + name = "Postava" + text = f"{name} [{self.vitality}] ({self.strength}/{self.agility})" + char = Character(name,self.strength,self.agility,self.vitality) + self.assertCharacter(char, name, self.vitality, self.strength, self.agility,"|Postava o sobe nepodava spravne informace.") + + + def test_take_weapon(self): + name = "vezmiZbran" + left = Weapon("LEVA", self.attackL, self.defenseL) + right = Weapon("PRAVA", self.attackR, self.defenseR) + char = Character(name, self.strength, self.agility, self.vitality) + + self.assertTrue(char.take_weapon(left,Character.HAND_LEFT),"|Postava tvrdi, ze si nemuze vzit zbran do prazdne leve ruky") + self.assertCharacter(char,name,self.vitality,self.strength + self.attackL, self.agility + self.defenseL, "|Postava o sobe nepodava spravne informace") + + self.assertFalse(char.take_weapon(left,Character.HAND_LEFT),"|Postava tvrdi, ze si muze vzit zbran do plne leve ruky") + self.assertCharacter(char,name,self.vitality,self.strength + self.attackL, self.agility + self.defenseL, "|Postava o sobe nepodava spravne informace") + + self.assertTrue(char.take_weapon(right,Character.HAND_RIGHT),"|Postava tvrdi, ze si nemuze vzit zbran do prazdne prave ruky") + self.assertCharacter(char,name,self.vitality,self.strength + self.attackR + self.attackL, self.agility + self.defenseR + self.defenseL, "|Postava o sobe nepodava spravne informace") + + char = Character(name, self.strength, self.agility, self.vitality) + + self.assertTrue(char.take_weapon(right,Character.HAND_RIGHT),"|Postava tvrdi, ze si nemuze vzit zbran do prazdne prave ruky") + self.assertCharacter(char,name,self.vitality,self.strength + self.attackR, self.agility + self.defenseR, "|Postava o sobe nepodava spravne informace") + + self.assertFalse(char.take_weapon(right,Character.HAND_RIGHT),"|Postava tvrdi, ze si muze vzit zbran do plne prave ruky") + self.assertTrue(char.take_weapon(left,Character.HAND_LEFT), "|Postava tvrdi, ze si nemuze vzit zbran do prazdne leve ruky") + + def test_defend(self): + name = "branSe" + attack = random.randint(1,10) + + left = Weapon("LEVA", 0, self.defenseL) + right = Weapon("PRAVA", 0, self.defenseR) + + char = Character(name, 0, self.agility, self.vitality) + char.take_weapon(left,Character.HAND_LEFT) + char.take_weapon(right, Character.HAND_RIGHT) + + self.assertTrue(0==char.defend(self.agility+self.defenseL+self.defenseR-1), "|Postava tvrdi, ze utrpela zraneni, i kdyz je utok mensi nez obrana") + self.assertCharacter(char, name, self.vitality,0,self.agility+self.defenseL+self.defenseR,"|Postava o sobe nepodava spravne informace") + + self.assertTrue(0==char.defend(self.agility+self.defenseL+self.defenseR), "|Postava tvrdi, ze utrpela zraneni, i kdyz je utok mensi nez obrana") + self.assertCharacter(char, name, self.vitality,0,self.agility+self.defenseL+self.defenseR,"|Postava o sobe nepodava spravne informace") + + self.assertTrue(attack==char.defend(self.agility+self.defenseL+self.defenseR+attack), "|Postava tvrdi, ze utrpela jine zraneni, nez mela") + self.assertCharacter(char, name, self.vitality-attack,0,self.agility+self.defenseL+self.defenseR,"|Postava o sobe nepodava spravne informace") + + def test_attack(self): + name = "zautoc" + left = Weapon("LEVA", self.attackL, 0) + right = Weapon("PRAVA", self.attackR, 0) + + char = Character(name, self.strength, 0, self.vitality) + char.take_weapon(left,Character.HAND_LEFT) + char.take_weapon(right, Character.HAND_RIGHT) + + self.assertTrue(self.strength + self.attackL + self.attackR == char.attack(), "|Postava tvrdi, ze utoci jinou silou, nez jaky je jeji utok.") + self.assertCharacter(char, name, self.vitality, self.strength + self.attackL + self.attackR, 0, "|Postava o sobe nepodava spravne informace") + + def test_is_alive(self): + name = "jeZiva" + + char = Character(name, 0,0,self.vitality) + self.assertTrue(char.is_alive(), "|Postava zemrela pri narozeni") + + char.defend(self.vitality) + self.assertFalse(char.is_alive(), "|Postava nezemrela pri brutalnim utoku") diff --git a/tests/rpg_test.py b/tests/rpg_test.py new file mode 100644 index 0000000..6aebd40 --- /dev/null +++ b/tests/rpg_test.py @@ -0,0 +1,118 @@ +import random +import unittest +import builtins +import typing +from typing import Any +from character import Character +from weapon import Weapon +from rpg import RPG + +class RPGTest(unittest.TestCase): + + class InputShim: + """ + Třída pro nahrazení standardní funkce input pro vstup dat + """ + __idx:int = 0 + __lines:list[str] = [] + + @staticmethod + def set_input_data(lines:list[str]): + RPGTest.InputShim.__idx = 0 + RPGTest.InputShim.__lines = lines + builtins.input = typing.cast(Any, RPGTest.InputShim.__next) + + @staticmethod + def get_latest_input() -> str|None: + if RPGTest.InputShim.__idx==0: + return None + else: + return RPGTest.InputShim.__lines[RPGTest.InputShim.__idx-1] + + @staticmethod + def __next(prompt:str=""): + assert RPGTest.InputShim.__idx None: + """ + Args: + name: Nazev zbrane + attack: Utocna sila zbrane + defense: Obranna sila zbrane + """ + self.__name = name + self.__attack = attack + self.__defense = defense + + @property + def attack(self) -> int: + """ + Utocna sila zbrane + """ + return self.__attack + + @property + def defense(self) -> int: + """ + Obranna sila zbrane + """ + return self.__defense + + def __str__(self) -> str: + return f"{self.__name} [{self.__attack}/{self.__defense}]" + \ No newline at end of file