# coding=utf-8 from random import randrange import random from abc import abstractmethod class ВзрывоопаснаяЧасть: __врывная_сила = None def __init__(сам, взрывная_сила=10): сам.задаёт_взрывную_силу(взрывная_сила) def взрывается(сам, целевой_объект = None): print("Происходит Взрыв!") if not целевой_объект: попавшие_под_взрыв = сам.__находит_кого_зацепило_взрывной_волной() if попавшие_под_взрыв: print("попавшие под взрыв теряют здоровье") сам.__попавшие_под_взрыв_теряют_здоровье(попавшие_под_взрыв) else: print("Взрывом никого не зацепило.") else: целевой_объект.получает_повреждения(сам.выдаёт_взрывную_силу()) return сам.выдаёт_взрывную_силу() def задаёт_взрывную_силу(сам, взрывная_сила): сам.__врывная_сила = взрывная_сила def выдаёт_взрывную_силу(сам): return сам.__врывная_сила def __находит_кого_зацепило_взрывной_волной(сам): """ Это такая длинная заглушка. Так как расстояний нет, то просто выбирается список случайных кораблей, из обоих флотов. Эта заглушка, позволяет программе-таки работать. """ кол_накрытых_кораблей = random.randrange( (флот_игрока.показывает_свой_размер() + флот_инопланетян.показывает_свой_размер()) // 2) список_всех_кораблей = флот_игрока._АбстрактныйФлот__состав + \ флот_инопланетян._АбстрактныйФлот__состав список = [] for _ in range(кол_накрытых_кораблей): список.append(список_всех_кораблей.pop( random.randrange(len(список_всех_кораблей)))) return список def __попавшие_под_взрыв_теряют_здоровье(сам, попавшие_под_взрыв): print("Эти корабли попали под взрыв: ", end=" ") for корабль in попавшие_под_взрыв: print(корабль.выдаёт_имя(), end=", ") print(".") for объект in попавшие_под_взрыв: объект.получает_повреждения(сам.выдаёт_взрывную_силу()) class Двигатель: __мощность = None def __init__(сам, мощность): сам.задаёт_мощность(мощность) сам.энергоблок = ВзрывоопаснаяЧасть(100) def задаёт_мощность(сам, мощность): сам.__мощность = мощность def выдаёт_мощность(сам): return сам.__мощность def разрушается(сам): print("Энергоблок двигателя разрушен.") сам.энергоблок.взрывается() class АбстрактныйКосмическийОбъект: __прочность = None __скорость = None def __init__(сам, прочность): сам.задаёт_прочность(прочность) сам.задаёт_скорость(0) def задаёт_прочность(сам, прочность): сам.__прочность = прочность def выдаёт_прочность(сам): return сам.__прочность def задаёт_скорость(сам, скорость): сам.__скорость = скорость def выдаёт_скорость(сам): return сам.__скорость @abstractmethod def получает_повреждения(сам, значение): pass def __остался_ли_запас_прочности(сам): if сам.выдаёт_прочность() > 0: return True else: return False class Снаряд(АбстрактныйКосмическийОбъект): def __init__(сам, прочность, взрывная_сила=10): АбстрактныйКосмическийОбъект.__init__(сам, прочность) сам.боеголовка = ВзрывоопаснаяЧасть(взрывная_сила) def летит_в_цель(сам, цель): сам.__следует_правилам_баллистики() print("снаряд полетел ", end="") попадание = сам.__попал_ли_в_цель() if попадание: print("и попал в", цель.выдаёт_имя()) сам.__сталкивается_с(цель) else: print("в бесконечный космос.") def __сталкивается_с(сам, цель): сам.получает_повреждения(сам.выдаёт_прочность()) # отправляет сообщение объекту "корабль"... или любой другой цели цель.получает_повреждения(сам.боеголовка.взрывается(цель)) def __следует_правилам_баллистики(сам): pass def __попал_ли_в_цель(сам): return random.choice([True, False]) def получает_повреждения(сам, значение): сам.задаёт_прочность(значение) # прочность снижается до нуля print("Снаряд разрушается.") class КосмическийКорабль(АбстрактныйКосмическийОбъект): """Более крупный пример агрегации.""" __имя = None def __init__(сам, *, прочность, имя): АбстрактныйКосмическийОбъект.__init__(сам, прочность) сам.двигатель = Двигатель(100) сам.задаёт_прочность(прочность) сам.задаёт_имя(имя) def выдаёт_имя(сам): return сам.__имя def задаёт_имя(сам, прочность): сам.__имя = прочность def полный_вперёд(сам): сам.задаёт_скорость(сам.двигатель.выдаёт_мощность()) print(сам.выдаёт_имя(), "набрал максимальную скорость") def стреляет(сам, цель): print("Корабль :", сам.выдаёт_имя(), "атаковал и его ", end="") снаряд = Снаряд(10) снаряд.летит_в_цель(цель) def __выбирает_цель(сам): цель = сам.цель = "цель" return цель def получает_повреждения(сам, значение): """Грёбаная рекурсия""" print("Корабль", сам.выдаёт_имя(), "получил", значение, "урона.") сам.задаёт_прочность(сам.выдаёт_прочность() - значение) if сам.__был_ли_уничтожен(): if "двигатель" in сам.__dict__: # проверяет, наличие двигателя сам.двигатель.разрушается() if "двигатель" in сам.__dict__: del сам.двигатель сам.уничтожается() else: if "двигатель" in сам.__dict__: if сам.__был_ли_повреждён_двигатель(): сам.двигатель.разрушается() if "двигатель" in сам.__dict__: del сам.двигатель def __был_ли_повреждён_двигатель(сам): # заглушка, с определённой вероятностью повреждается двигатель. процент = random.randint(0, 100) if процент <= 20: return True else: return False def __был_ли_уничтожен(сам): if сам.выдаёт_прочность() <= 0: return True def уничтожается(сам): pass class АбстрактныйФлот: """Флот для наследования.""" __состав = None # список def __init__(сам, количество_кораблей, имя="Линкор"): сам.__состав = [] сам.__пополняет_свой_состав(количество_кораблей, имя) def добавляет_в_свой_состав(сам, корабль): if сам.__является_ли_объект_кораблём(корабль): сам.__состав.append(корабль) def удаляет_из_своего_состава(сам, корабль): if сам.__является_ли_объект_кораблём(корабль): сам.__состав.remove(корабль) def показывает_свой_состав(сам): for корабль in сам.__состав: print("Название: ", корабль.выдаёт_имя(), "|", "прочность:", корабль.выдаёт_прочность()) def выбирает_один_из_своих_кораблей(сам, порядковый_номер=None): if not порядковый_номер: корабль = сам.__выбирает_свой_случайный_корабль() else: корабль = сам.__ищет_корабль_по_порядковому_номеру(порядковый_номер) return корабль def показывает_свой_размер(сам): return len(сам.__состав) @abstractmethod def атакует(сам, флот_противника): """Метод должен переопределяться в обязательном порядке.""" pass def __пополняет_свой_состав(сам, количество_кораблей, имя): порядковый_номер = 0 for _ in range(количество_кораблей): порядковый_номер += 1 корабль = КосмическийКорабль(прочность=100, имя=имя + str(порядковый_номер)) сам.добавляет_в_свой_состав(корабль) def __выбирает_свой_случайный_корабль(сам): корабль = сам.__ищет_корабль_по_порядковому_номеру( random.randrange(сам.показывает_свой_размер())) return корабль def __ищет_корабль_по_порядковому_номеру(сам, порядковый_номер): корабль = сам.__состав[порядковый_номер] return корабль @staticmethod def __является_ли_объект_кораблём(корабль): return корабль.__class__ is КосмическийКорабль class ФлотИгрока(АбстрактныйФлот): """Конкретизация флота. Ассоциация.""" def атакует(сам, флот_противника): """Пример полиморфизма.""" print("Флот игрока атакует!") номер_корабля = сам.__спрашивает_у_игрока_номер_корабля() корабль = сам.выбирает_один_из_своих_кораблей(номер_корабля) корабль_цель = флот_противника.выбирает_один_из_своих_кораблей() корабль.стреляет(корабль_цель) @staticmethod def __спрашивает_у_игрока_номер_корабля(): # Игрок выбирает корабль return 1 # заглушка class ФлотИнопланетян(АбстрактныйФлот): """Конкретизация Флота. Ассоциация.""" def __init__(сам, кол_кораблей): АбстрактныйФлот.__init__(сам, кол_кораблей, "НЛО") def атакует(сам, флот_противника): """Пример полиморфизма.""" print("Флот инопланетян атакует!") сам.__случайно_выбранный_корабль_стреляет(флот_противника) def __случайно_выбранный_корабль_стреляет(сам, флот_противника): корабль = сам.выбирает_один_из_своих_кораблей() корабль.стреляет(флот_противника.выбирает_один_из_своих_кораблей()) флот_игрока = ФлотИгрока(5) print("Флот собран.") print("Состав флота игрока :") флот_игрока.показывает_свой_состав() print("\n\n") флот_инопланетян = ФлотИнопланетян(5) print("Флот собран.") print("Состав флота инопланетян :") флот_инопланетян.показывает_свой_состав() print("\n\n") флот_игрока.атакует(флот_инопланетян) флот_инопланетян.атакует(флот_игрока) print("Состав флота игрока :") флот_игрока.показывает_свой_состав() print("Состав флота инопланетян :") флот_инопланетян.показывает_свой_состав() print("\n\n")
Так как система сложная, всё-таки, то вот диаграмма в помощь.
Реализации постарался сделать минимум, но похоже, что всё равно много получилось, хотелось, чтобы всё-таки работало.
пс: про @property вкурсе, без него решил делать намеренно.