# Python OOP Exam - 10 April 2022 - Medieval Games
# https://judge.softuni.org/Contests/Practice/Index/3426#0
=============================================================================================
# file name: supply.py
from abc import ABC, abstractmethod
class Supply(ABC):
@abstractmethod
def __init__(self, name: str, energy: int):
self.name = name
self.energy = energy
@property
def name(self):
return self.__name
@name.setter
def name(self, value):
if value == '':
raise ValueError("Name cannot be an empty string.")
self.__name = value
@property
def energy(self):
return self.__energy
@energy.setter
def energy(self, value):
if value < 0:
raise ValueError("Energy cannot be less than zero.")
self.__energy = value
def details(self):
return f"{self.__class__.__name__}: {self.name}, {self.energy}"
=============================================================================================
# file name: drink.py
from project.supply.supply import Supply
class Drink(Supply):
def __init__(self, name: str, energy=15):
super().__init__(name, energy)
=============================================================================================
# file name: food.py
from project.supply.supply import Supply
class Food(Supply):
def __init__(self, name: str, energy=25):
super().__init__(name, energy)
=============================================================================================
# file name: player.py
class Player:
MAX_STAMINA = 100
MIN_STAMINA = 0
added_player_names = []
def __init__(self, name: str, age: int, stamina=100):
self.name = name
self.age = age
self.stamina = stamina
@property
def name(self):
return self.__name
@name.setter
def name(self, value):
if value == '':
raise ValueError("Name not valid!")
elif value in Player.added_player_names:
raise Exception(f"Name {value} is already used!")
Player.added_player_names.append(value)
self.__name = value
@property
def age(self):
return self.__age
@age.setter
def age(self, value):
if value < 12:
raise ValueError("The player cannot be under 12 years old!")
self.__age = value
@property
def stamina(self):
return self.__stamina
@stamina.setter
def stamina(self, value):
if not 0 <= value <= 100:
raise ValueError("Stamina not valid!")
self.__stamina = value
@property
def need_sustenance(self):
return self.stamina < 100
def __str__(self):
return f"Player: {self.name}, {self.age}, {self.stamina}, {self.need_sustenance}"
=============================================================================================
# file name: controller.py
from project.player import Player
from project.supply.supply import Supply
class Controller:
def __init__(self):
self.players = []
self.supplies = []
def add_player(self, *players: Player):
added_players_names = []
for player_obj in players:
if player_obj not in self.players:
self.players.append(player_obj)
added_players_names.append(player_obj.name)
return f"Successfully added: {', '.join(added_players_names)}"
def add_supply(self, *supplies: Supply):
for supply_obj in supplies:
self.supplies.append(supply_obj)
def sustain(self, player_name: str, sustenance_type: str):
player = self.__find_player_by_name(player_name)
if player is None:
return
if not player.need_sustenance:
return f"{player_name} have enough stamina."
if sustenance_type not in ['Food', 'Drink']:
return
last_supply = self.__find_last_supply_by_type(sustenance_type)
player.stamina = min(player.stamina + last_supply.energy, 100)
return f"{player_name} sustained successfully with {last_supply.name}."
def __find_last_supply_by_type(self, supply_type_):
for index in range(len(self.supplies) - 1, -1, -1):
if type(self.supplies[index]).__name__ == supply_type_:
return self.supplies.pop(index)
raise Exception(f"There are no {supply_type_.lower()} supplies left!")
def __find_player_by_name(self, player_name_):
for player_obj in self.players:
if player_obj.name == player_name_:
return player_obj
def duel(self, first_player_name: str, second_player_name: str):
player1 = self.__find_player_by_name(first_player_name)
player2 = self.__find_player_by_name(second_player_name)
result_if_both_stamina_is_0 = []
if player1.stamina <= 0 or player2.stamina <= 0:
if player1.stamina <= 0:
result_if_both_stamina_is_0.append(f'Player {first_player_name} does not have enough stamina.')
if player2.stamina <= 0:
result_if_both_stamina_is_0.append(f'Player {second_player_name} does not have enough stamina.')
return '\n'.join(result_if_both_stamina_is_0)
lower_stamina_order = sorted([player1, player2], key=lambda x: x.stamina)
player1, player2 = lower_stamina_order[0], lower_stamina_order[1]
player2.stamina = max(player2.stamina - player1.stamina / 2, 0)
if player2.stamina == 0:
return f'Winner: {player1.name}'
player1.stamina = max(player1.stamina - player2.stamina / 2, 0)
if player1.stamina == 0:
return f'Winner: {player2.name}'
higher_stamina_order = sorted([player1, player2], key=lambda x: -x.stamina)
return f"Winner: {higher_stamina_order[0].name}"
def next_day(self):
for player_obj in self.players:
player_obj.stamina = max(player_obj.stamina - player_obj.age * 2, 0)
for player_obj in self.players:
give_food = self.__find_last_supply_by_type('Food')
player_obj.stamina = min(player_obj.stamina + give_food.energy, 100)
give_drink = self.__find_last_supply_by_type('Drink')
player_obj.stamina = min(player_obj.stamina + give_drink.energy, 100)
def __str__(self):
result = []
for player in self.players:
result.append(str(player))
for supply in self.supplies:
result.append(supply.details())
return '\n'.join(result)