autor: Michał Powała
repositorio de origen: simulación-de-lucha-de-dos-héroes
simulación-de-lucha-de-dos-héroes
Este repositorio contiene soluciones para una tarea determinada (a continuación en este archivo) abordada de diferentes maneras. Cada enfoque (que está terminado) tiene su propia rama y su propia etiqueta. La aplicación se puede ejecutar desde cli.
El propósito de este repositorio es (para mí) practicar código limpio y un poco de buen diseño de código, lo cual sigue:
- Cuatro pilares de la programación orientada a objetos (para mí, si te concentras en SÓLIDO, surgieron solos)
- Abstracción
- Herencia
- Encapsulación
- Polimorfismo
- Principios SÓLIDOS
- Responsabilidad única (cada miembro de mi clase tiene su propia tarea única)
- Abierto/cerrado (cuando comencé a jugar con diferentes enfoques, la mayoría de mis componentes internos estaban intactos, solo necesitaba agregar nuevas funciones)
- Principio de sustitución de Liskov (mi código usa abstracción cuando es necesario y desconoce la implementación subyacente; mire las clases Unidad y Colega, por ejemplo)
- Principio de segregación de interfaces (muchas interfaces pequeñas en lugar de una grande)
- Principio de inversión de dependencia (el único lugar donde se crean instancias de clases es el script run.php y las fábricas, y mire Randomizer: ¡se puede burlar de él! No uso rand() directamente en ninguna clase)
- Patrones de diseño
- Decorador (src/Modificador)
- Método de fábrica
- Patrón de observador (rama adecuada)
- Patrón mediador (rama adecuada)
- Patrones tácticos DDD
- Objeto de valor (fuente/Propiedad)
- Agregado (src/Unit: toda la lógica que podría encapsularse aquí está aquí)
- Servicio de dominio (TurnService)
- Servicio de aplicación (GamePlayService)
- Fábricas (fábricas)
- Eventos (src/Event) (sí, podría usar el bus de eventos en su lugar)
- Acoplamiento flojo (surge de SÓLIDO)
Los registradores de acciones/eventos, los registradores de errores, la impresora (lector) y la lógica central están ligeramente acoplados entre sí. - TDD
Para ser honesto, no es TDD puro donde primero implementas pruebas que fallan y luego el código fuente, después de lo cual las pruebas pasan (creo que no es práctico), pero después de crear algún nivel de abstracción o una clase, lo probé de inmediato y solucioné todos los errores menores si errores necesarios o lógicos en los que no había pensado. Es por eso que cuando implementé el script run.php (que es el punto de entrada a la aplicación) y lo hice como último paso, ¡el código funcionó! Creo que eso es suficientemente bueno y no es necesario TDD puro.
como correr
- Ejecute docer:
docker-compose up -d
- ejecutar aplicación:
docker-compose exec cli php run.php
- ejecutar pruebas unitarias
docker-compose exec cli vendor/bin/phpunit tests/
TAREA
Crea una simulación de batalla entre Orderus y la bestia. Cada vez que comienza la batalla, se generan bestias y Orderus con estadísticas diferentes que siguen las siguientes reglas:
- Orden:
- Salud: 70 - 100
- Fuerza: 70 - 80
- Defensa: 45 – 55
- Velocidad: 40 – 50
- Suerte: 10% - 30% (0% significa sin suerte, 100% suerte todo el tiempo)
- habilidades adicionales:
- Golpe rápido: Golpea dos veces mientras es su turno de atacar; hay un 10% de probabilidad de que use esta habilidad cada vez que ataque
- Escudo mágico: solo recibe la mitad del daño habitual cuando un enemigo ataca; hay un cambio del 20%: usará esta habilidad cada vez que defienda
- Bestia:
- Salud: 60 - 90
- Fuerza: 60 - 90
- Defensa: 40 – 60
- Velocidad: 40 – 60
- Suerte: 25% - 40%
Reglas de juego:
- El primer ataque lo realiza el jugador con mayor velocidad. Si ambos jugadores tienen la misma velocidad, el ataque lo realiza el jugador con mayor suerte.
- Después de un ataque, los jugadores cambian de roles: el atacante ahora defiende y el defensor ataca.
- El daño causado por el atacante se calcula con la siguiente fórmula:
Damage = Attacker strength – Defender defence
- El daño se resta de la salud del defensor. Un atacante puede fallar su golpe y no causar daño si el defensor tiene suerte ese turno.
- Las habilidades de Orderus ocurren aleatoriamente, según sus posibilidades, así que téngalas en cuenta en cada turno.
- El juego termina cuando uno de los jugadores se queda sin salud o el número de turnos llega a 20.
- La aplicación debe mostrar los resultados en cada turno: qué sucedió, qué habilidades se usaron (si las hubo), el daño causado, la salud restante del defensor.
- Si tenemos un ganador antes de que se alcance el número máximo de rondas, deberá ser declarado.
SUCURSALES y ETIQUETAS
- rama: base; Etiqueta: aplicación-base-running:
Contiene una solución básica (funcionalidad principal, unidad probada) que aún no admite la impresión. - rama: patrón de observador; Etiqueta: patrón-observador-de-aplicación-en ejecución:
Contiene todo el código de la rama base
y lo amplía con impresión y registro con el uso de Observer Pattern. - rama: patrón-mediador; Etiqueta: patrón-mediador-de-aplicación-en ejecución:
Contiene todo el código de la rama base
y lo amplía con impresión y registro con el uso de Mediator Pattern.
Se agregarán más sucursales y enfoques...
Sucursal actual: base
PALABRA DE EXPLICACIÓN
La solución más sencilla y de 'aplicación web' sería utilizar algún bus de eventos externo o hecho por mí mismo, pero solo quiero jugar con patrones de diseño (podría agregar esa solución algún día).
HACER
- Olvidé implementar la habilidad de fallar...
- Arreglar la delegación no existente en el decorador MagicShield