автор: Михал Поваля
репозиторий исходного кода: симуляция боя двух героев
симуляция боя двух героев
Этот репозиторий содержит решения для данной задачи (ниже в этом файле), реализованные разными способами. Каждый подход (который завершен) имеет свою ветку и собственный тег. Приложение запускается из командной строки.
Цель этого репозитория (для меня) — попрактиковаться в чистом коде и немного хорошем дизайне кода, а именно:
- Четыре столпа ООП (для меня, если сосредоточиться на SOLID, они возникли сами собой)
- Абстракция
- Наследование
- Инкапсуляция
- Полиморфизм
- НАДЕЖНЫЕ Принципы
- Единая ответственность (у каждого моего класса своя уникальная задача)
- Открытый/закрытый (когда я начал экспериментировать с разными подходами, большинство моих внутренностей остались нетронутыми, просто нужно было добавить новый функционал)
- Принцип замены Лискова (мой код использует абстракцию там, где это необходимо, и не знает базовой реализации; например, посмотрите на классы Unit и Colleague)
- Принцип разделения интерфейсов (много маленьких интерфейсов вместо одного большого)
- Принцип инверсии зависимостей (единственное место, где создаются экземпляры классов - это скрипт и фабрики run.php, и посмотрите на Randomizer - его можно высмеивать! Я не использую rand() напрямую ни в одном классе)
- Шаблоны проектирования
- Декоратор (источник/Модификатор)
- Фабричный метод
- Шаблон наблюдателя (соответствующая ветка)
- Шаблон посредника (соответствующая ветвь)
- Тактические схемы DDD
- Объект значения (источник/свойство)
- Агрегат (src/Unit — каждый бит логики, который можно инкапсулировать здесь, находится здесь)
- Служба домена (TurnService)
- Служба приложений (GamePlayService)
- Фабрики (фабрики)
- События (src/Event) (да, вместо этого я мог бы использовать шину событий)
- Слабая связь (возникает из SOLID)
Регистраторы действий/событий, регистраторы ошибок, принтер (считыватель) и базовая логика слабо связаны друг с другом. - ТДД
Честно говоря, это не чистый TDD, где вы сначала реализуете тесты, которые терпят неудачу, а затем исходный код, после чего тесты проходят (я думаю, что это непрактично), но после того, как я создал некоторый уровень абстракции или класс, я сразу же его протестировал и исправил все мелкие ошибки, если необходимые или логические ошибки, которые я не продумал. Вот почему, когда я реализовал скрипт run.php (который является точкой входа в приложение) и сделал это на последнем этапе, код заработал! Я считаю, что этого достаточно и чистый TDD не нужен.
Как бежать
- Запустите docer:
docker-compose up -d
- запустить приложение:
docker-compose exec cli php run.php
- запустить модульные тесты
docker-compose exec cli vendor/bin/phpunit tests/
ЗАДАЧА
Создайте симуляцию битвы между Ордерусом и зверем. Каждый раз, когда начинается битва, зверь и Ордерус генерируются с разными статистическими данными, которые следуют следующим правилам:
- Заказ:
- Здоровье: 70 - 100
- Сила: 70 - 80
- Защита: 45–55
- Скорость: 40 – 50
- Удача: 10% - 30% (0% означает отсутствие удачи, 100% удача всегда)
- дополнительные навыки:
- Быстрый удар: Ударьте дважды, пока настала его очередь атаковать; есть 10% шанс, что он будет использовать этот навык каждый раз, когда атакует.
- Магический щит: получает только половину обычного урона при атаке врага; изменение на 20%: он будет использовать этот навык каждый раз, когда защищается
- Зверь:
- Здоровье: 60 - 90
- Сила: 60–90
- Защита: 40–60
- Скорость: 40 – 60
- Удача: 25% - 40%
Правила игры:
- Первую атаку совершает игрок с большей скоростью. Если оба игрока имеют одинаковую скорость, атаку осуществляет игрок с наибольшей удачей.
- После атаки игроки меняются ролями: нападающий теперь защищается, а защитник теперь атакует.
- Урон, нанесенный атакующим, рассчитывается по следующей формуле:
Damage = Attacker strength – Defender defence
- Урон вычитается из здоровья защитника. Атакующий может промахнуться и не нанести урона, если защищающемуся в этот ход повезет.
- Навыки Ордеруса возникают случайным образом, в зависимости от их шансов, поэтому учитывайте их на каждом ходу.
- Игра заканчивается, когда у одного из игроков остается без здоровья или количество ходов достигает 20.
- Приложение должно каждый ход выводить результаты: что произошло, какие умения были использованы (если были), нанесенный урон, оставшееся здоровье защитника.
- Если у нас есть победитель до того, как будет достигнуто максимальное количество раундов, его необходимо объявить.
ВЕТВИ и ТЕГИ
- ветка: база; тег: базовое-работающее-приложение:
Содержит базовое решение (основная функциональность, модульное тестирование), которое пока не поддерживает печать. - ветка: шаблон-наблюдатель; тег: шаблон-наблюдателя-запуска приложения:
Содержит весь код из base
ветки и расширяет его печатью и протоколированием с использованием шаблона наблюдателя. - ветка: шаблон-посредник; тег: шаблон-посредника запущенного приложения:
Содержит весь код из base
ветки и расширяет его печатью и протоколированием с использованием шаблона Mediator.
Будут добавлены новые ветки и подходы...
Текущая ветка: базовая
СЛОВО ОБЪЯСНЕНИЯ
Самым простым и наиболее простым решением для «веб-приложений» было бы использование какой-либо внешней или самодельной шины событий, но я просто хочу поиграть с шаблонами проектирования (возможно, когда-нибудь я добавлю это решение).
TODO
- Забыл реализовать способность промаха...
- Исправлено несуществующее делегирование в декораторе MagicShield.