Auteur : Michał Powała
référentiel source : simulation de combat à deux héros
simulation de combat à deux héros
Ce référentiel contient des solutions à une tâche donnée (ci-dessous dans ce fichier) abordées de différentes manières. Chaque approche (qui est terminée) a sa propre branche et sa propre balise. L'application est exécutable depuis cli.
Le but de ce référentiel est (pour moi) de pratiquer du code propre et un peu de bonne conception de code, qui suivent :
- Quatre piliers de la POO (pour moi, si vous vous concentrez sur SOLID, ils sont apparus tout seuls)
- Abstraction
- Héritage
- Encapsulation
- Polymorphisme
- Principes SOLIDES
- Responsabilité unique (chacun de ma classe a sa propre tâche unique)
- Ouvert/fermé (quand j'ai commencé à jouer avec différentes approches, la plupart de mes composants internes n'étaient pas touchés, il suffisait d'ajouter de nouvelles fonctionnalités)
- Principe de substitution de Liskov (mon code utilise l'abstraction si nécessaire et ignore l'implémentation sous-jacente ; regardez les classes Unit et Colleague par exemple)
- Principe de ségrégation des interfaces (plusieurs petites interfaces au lieu d'une grande)
- Principe d'inversion de dépendance (le seul endroit où les classes sont instanciées est le script run.php et les usines, et regardez Randomizer - on peut s'en moquer ! Je n'utilise rand() directement dans aucune classe)
- Modèles de conception
- Décorateur (src/Modificateur)
- Méthode d'usine
- Modèle d'observateur (branche appropriée)
- Modèle de médiateur (branche appropriée)
- Modèles tactiques DDD
- Objet de valeur (src/Propriété)
- Agrégat (src/Unit - chaque bit de logique qui pourrait être encapsulé ici est ici)
- Service de domaine (TurnService)
- Service d'application (GamePlayService)
- Usines (usines)
- Événements (src/Event) (ouais, je pourrais utiliser le bus d'événements à la place)
- Accouplement lâche (il provient de SOLID)
Les enregistreurs d'actions/d'événements, les enregistreurs d'erreurs, l'imprimante (lecteur) et la logique principale sont tous faiblement couplés les uns aux autres. - TDD
Pour être honnête, ce n'est pas du pur TDD où vous implémentez d'abord des tests qui échouent, puis le code source après quoi les tests réussissent (je pense que ce n'est pas pratique) mais après avoir créé un niveau d'abstraction ou une classe, je l'ai testé tout de suite et j'ai corrigé tous les bugs mineurs si des erreurs nécessaires ou logiques auxquelles je n'avais pas réfléchi. C'est pourquoi lorsque j'ai implémenté le script run.php (qui est le point d'entrée de l'application) et que je l'ai fait comme dernière étape, le code a fonctionné ! Je pense que c'est suffisant et que le TDD pur n'est pas nécessaire.
Comment courir
- Exécutez docer :
docker-compose up -d
- exécuter l'application :
docker-compose exec cli php run.php
- exécuter des tests unitaires
docker-compose exec cli vendor/bin/phpunit tests/
TÂCHE
Créez une simulation de combat entre Orderus et la bête. Chaque fois que la bataille commence, la bête et Orderus sont générés avec des statistiques différentes qui suivent les règles suivantes :
- Commandez-nous :
- Santé : 70 - 100
- Force : 70 - 80
- Défense : 45 – 55
- Vitesse : 40 – 50
- Chance : 10 % - 30 % (0 % signifie pas de chance, 100 % de chance tout le temps)
- compétences supplémentaires :
- Frappe rapide : frappez deux fois pendant que c'est son tour d'attaquer ; il y a 10 % de chances qu'il utilise cette compétence à chaque fois qu'il attaque
- Bouclier magique : ne subit que la moitié des dégâts habituels lorsqu'un ennemi attaque ; il y a un changement de 20 %, il utilisera cette compétence à chaque fois qu'il défendra
- Bête:
- Santé : 60 - 90
- Force : 60 - 90
- Défense : 40 – 60
- Vitesse : 40 – 60
- Chance : 25% - 40%
Règles de jeu :
- La première attaque est effectuée par le joueur ayant la vitesse la plus élevée. Si les deux joueurs ont la même vitesse, l'attaque est menée par le joueur ayant le plus de chance.
- Après une attaque, les joueurs inversent les rôles : l'attaquant défend désormais et le défenseur attaque.
- Les dégâts infligés par l'attaquant sont calculés avec la formule suivante :
Damage = Attacker strength – Defender defence
- Les dégâts sont soustraits de la santé du défenseur. Un attaquant peut rater son coup et ne faire aucun dégât si le défenseur a de la chance ce tour-là.
- Les compétences d'Orderus apparaissent de manière aléatoire, en fonction de leurs chances, alors tenez-en compte à chaque tour.
- Le jeu se termine lorsqu'un des joueurs reste sans santé ou que le nombre de tours atteint 20.
- L'application doit afficher les résultats à chaque tour : ce qui s'est passé, quelles compétences ont été utilisées (le cas échéant), les dégâts infligés, la santé restante du défenseur.
- Si nous avons un gagnant avant que le nombre maximum de tours ne soit atteint, il doit être déclaré.
BRANCHES et ÉTIQUETTES
- branche : base ; balise : base-running-app :
Contient une solution de base (fonctionnalité de base, testée à l'unité) qui ne prend pas encore en charge l'impression - branche : modèle d'observateur ; balise : modèle-d'observateur-d'application en cours d'exécution :
Contient tout le code de la branche base
et l'étend avec l'impression et la journalisation avec l'utilisation d'Observer Pattern - branche : modèle médiateur ; balise : modèle-de-médiateur-d'application en cours d'exécution :
Contient tout le code de la branche base
et l'étend avec l'impression et la journalisation avec l'utilisation de Mediator Pattern
Plus de branches et d'approches à ajouter...
Branche actuelle : base
MOT D'EXPLICATION
La solution la plus simple et la plus « application Web » serait d'utiliser un bus d'événements externe ou créé par moi-même, mais je veux juste jouer avec les modèles de conception (je pourrais ajouter cette solution un jour).
FAIRE
- J'ai oublié d'implémenter la capacité d'échec...
- Correction d'une délégation non existante dans le décorateur MagicShield