diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..341e31e --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +__pycache__ +.idea \ No newline at end of file diff --git a/exceptions.py b/exceptions.py new file mode 100644 index 0000000..97a4533 --- /dev/null +++ b/exceptions.py @@ -0,0 +1,12 @@ +"""exception module""" + +class GameOver(Exception): + """finishes the game""" + @classmethod + def write_score(cls, gm_score, gm_name): + with open("score.txt", "a") as file: + file.write(gm_name + " -" " Очков: " + str(gm_score) + "\n") + + +class EnemyDown(Exception): + pass diff --git a/game.py b/game.py new file mode 100644 index 0000000..e2af450 --- /dev/null +++ b/game.py @@ -0,0 +1,68 @@ +"""main executable""" +from exceptions import GameOver, EnemyDown +from models import Player, Enemy, Score +import settings + +player_list = [0] + + + +def play(): + while True: + command = input("What you want to do? START, SHOW, HELP, TOP, EXIT: ") + if command == "START": + next_lvl = 1 + names = input("Enter your name: ") + print() + while Player.validate_names(names) is False: + print("Name already exists") + names = input("Enter your name: ") + player = Player(names, settings.LIVES, 0, 0) + enemy = Enemy(1, 1) + while True: + try: + while True: + player.allowed_attacks = int(input("Choose your hero: 1-Wizard, 2-Warrior, 3-Rogue ")) + if player.validate_allowed_attacks() is False: + print("The selected hero does not exist") + continue + else: + player.attack(enemy) + break + while True: + player.allowed_attacks = int(input("Choose defense: 1-Wizard, 2-Warrior, 3-Rogue ")) + if player.validate_allowed_attacks() is False: + print("The selected hero does not exist") + continue + else: + player.defence(enemy) + break + except EnemyDown: + next_lvl += 1 + print("------------------------------------") + print("You killed enemy!", "Score:", player.score, "Level:", enemy.level) + print("------------------------------------") + enemy = Enemy(enemy.level+next_lvl, enemy.lives+next_lvl) + player.score += 5 + player_list.append(player) + if command == "SHOW": + with open("score.txt", "r") as file: + print(file.read()) + if command == "HELP": + print("All commands:", ",".join(settings.HELP)) + if command == "TOP": + Score.player_top() + if command == "EXIT": + raise KeyboardInterrupt + + +if __name__ == '__main__': + try: + play() + except GameOver: + GameOver.write_score(player_list[-1].score, player_list[-1].name) + except KeyboardInterrupt: + pass + finally: + print() + print("Good bye!") diff --git a/models.py b/models.py new file mode 100644 index 0000000..daa6931 --- /dev/null +++ b/models.py @@ -0,0 +1,88 @@ +"""all logic""" +import random + + +from exceptions import GameOver, EnemyDown + + +class Enemy: + """Creates enemy""" + def __init__(self, level: int, lives: int): + self.level = level + self.lives = lives + + @staticmethod + def select_attack(): + return random.randint(1, 3) + + def decrease_lives(self): + self.lives -= 1 + print("Enemy HP:", self.lives) + if self.lives == 0: + raise EnemyDown + + +class Player: + """Creates player""" + def __init__(self, name: str, lives: int, score: int, allowed_attacks: int): + self.name = name + self.lives = lives + self.score = score + self.allowed_attacks = allowed_attacks + + @staticmethod + def fight(attack, defense): + if attack == defense: + return 0 + elif attack == 1 and defense == 3 or attack == 2 and defense == 1 or attack == 3 and defense == 2: + return -1 + else: + return 1 + + def decrease_lives(self): + self.lives -= 1 + if self.lives == 0: + raise GameOver + + def attack(self, enemy_obj): + self.fight(self.allowed_attacks, enemy_obj.select_attack()) + if self.fight(self.allowed_attacks, enemy_obj.select_attack()) == 0: + print("Attack: It's a draw!") + elif self.fight(self.allowed_attacks, enemy_obj.select_attack()) == 1: + print("Attack: You attacked successfully!") + enemy_obj.decrease_lives() + else: + print("Attack: You missed!") + + def defence(self, enemy_obj): + self.fight(enemy_obj.select_attack(), self.allowed_attacks) + if self.fight(enemy_obj.select_attack(), self.allowed_attacks) == 0: + print("Defence: It's a draw!") + elif self.fight(enemy_obj.select_attack(), self.allowed_attacks) == 1: + print("Defence: You missed!") + self.decrease_lives() + else: + print("Defence: You attacked successfully!") + self.score += 1 + + @classmethod + def validate_names(cls, names): + with open("score.txt", "r") as file: + for i in file.readlines(): + if names in i.split()[0]: + return False + + def validate_allowed_attacks(self): + if self.allowed_attacks not in [1,2,3]: + return False + + +class Score: + """Shows the top ten players by score""" + @classmethod + def player_top(cls): + with open("score.txt", "r") as file: + lines = file.readlines() + lines.sort(key=lambda x: int(x.split()[-1]), reverse=True) + for i in lines[:10]: + print(i.strip()) diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index e69de29..0000000 diff --git a/score.txt b/score.txt index 1be574b..f2848e7 100644 --- a/score.txt +++ b/score.txt @@ -15,6 +15,24 @@ Igor - lor - Î÷êîâ: 13 nisha - Î÷êîâ: 1 ursa - Î÷êîâ: 2 -Igor - Î÷êîâ: 6 -Igor - Î÷êîâ: 9 fe - Î÷êîâ: 6 +kip[ - Î÷êîâ: 3 +gosha - Î÷êîâ: 5 +vala - Î÷êîâ: 10 +llll - Î÷êîâ: 10 +igol - Î÷êîâ: 10 +gg - Î÷êîâ: 10 +fjkfkf - Î÷êîâ: 6 +fjfjfj - Î÷êîâ: 2 +fkfkfkfk - Î÷êîâ: 1 +jfjfjf - Î÷êîâ: 6 +fkfkfkkf - Î÷êîâ: 11 +kiiie - Î÷êîâ: 1 +fpfpfppf - Î÷êîâ: 1 +fffjfjfj - Î÷êîâ: 17 +flflflflflf - Î÷êîâ: 6 +2 - Î÷êîâ: 1 +jffjfj - Î÷êîâ: 4 +fkfkfkfk2 - Î÷êîâ: 5 +qqqw - Î÷êîâ: 3 +sasuke - Î÷êîâ: 11 diff --git a/settings.py b/settings.py new file mode 100644 index 0000000..79b7021 --- /dev/null +++ b/settings.py @@ -0,0 +1,11 @@ +"""const and command list""" + +LIVES = 1 + +HELP = { + "START", + "SHOW", + "HELP", + "EXIT", + "TOP" +} diff --git a/test.py b/test.py new file mode 100644 index 0000000..0b8d397 --- /dev/null +++ b/test.py @@ -0,0 +1,32 @@ +from unittest import TestCase +from unittest.mock import patch, mock_open + +from models import Player + + +class TestEnemy(TestCase): + + @patch('models.Enemy.select_attack', return_value=1) + def test_select_attack(self, select_attack): + self.assertEqual(select_attack(), 1) + + +class TestPlayer(TestCase): + + def setUp(self): + self.player = Player('test', 1, 1, 1) + + def test_fight(self): + self.assertEqual(self.player.fight(1, 1), 0) + self.assertEqual(self.player.fight(1, 3), -1) + self.assertEqual(self.player.fight(3, 1), 1) + + def test_validate_names(self): + self.assertIsNone(self.player.validate_names(self.player.name)) + + def test_validate_names_mock(self): + with patch('builtins.open', mock_open(read_data='name')): + self.assertIsNone(self.player.validate_names(self.player.name)) + + def test_validate_allowed_attacks(self): + self.assertIsNone(self.player.validate_allowed_attacks())