diff --git a/src/model/car/BasicCar.java b/src/model/car/BasicCar.java index b88f407..c39bed7 100644 --- a/src/model/car/BasicCar.java +++ b/src/model/car/BasicCar.java @@ -9,42 +9,63 @@ import model.map.Circuit; import model.map.Map; /** - * {@link BasicCar} représente une voiture qui avance sur un circuit en boucles. - * Chaque appel à {@link #run()} avance la voiture d'une certaine position et - * fait perdre de l'essence. - * Quand la position atteint la fin de la boucle, un nouveau tour est compté. + * {@link BasicCar} représente une voiture basique. + * *

- * La voiture consomme du carburant à chaque déplacement, et son score - * est calculé en fonction du nombre de tours complétés et de sa progression sur - * le tour actuel. + * Chaque appel à {@link #apply()} : + *

+ *

+ * + *

+ * La voiture peut subir des dégâts ({@link State#DAMAGED}), inverser son sens, + * ou arrêter la consommation de carburant. *

*/ public class BasicCar implements Car { + /** Générateur de nombres aléatoires pour simuler la progression */ protected static final Random RANDOM = new Random(); + /** Couleur de la voiture pour l'affichage */ private final Color COLOR; + /** Nom de la voiture */ private final String NAME; + /** Position actuelle dans la boucle (entre 0 et loop) */ private int pos = 0; + /** Nombre de tours complétés */ private int round = 0; - /** Nombre de cases dans une boucle (doit être > 0) */ + + /** Référence à la carte/circuit sur lequel la voiture évolue */ private Map map; + /** Carburant restant */ private int fuel = 60; + /** Multiplicateur pour avancer ou reculer */ private int movement = 1; + /** Indique si la voiture consomme du carburant */ private boolean isConsuming = true; + /** État courant de la voiture */ + private State state = State.NORMAL; + + /** Compteur interne pour la durée d'un état endommagé */ + private int damageRound = 0; + /** * Construit une nouvelle voiture. * * @param name nom de la voiture * @param color couleur de la voiture - * @param map + * @param map carte du circuit */ public BasicCar(String name, Color color, Map map) { this.NAME = name; @@ -52,137 +73,111 @@ public class BasicCar implements Car { this.map = map; } + /** + * Construit une nouvelle voiture. + * + * @param name nom de la voiture + * @param color couleur de la voiture + * + */ public BasicCar(String name, Color color) { this.NAME = name; this.COLOR = color; } /** - * Référence à l'état du jeu, pour récupérer les paramètres comme la - * consommation - */ - private State state = State.NORMAL; - - private int damageRound = 0; - - public void setDamage() { - damageRound = 5; - state = State.DAMAGED; - } - - private void decreaseDamage() { - if (state.isDamaged()) { - if (--damageRound <= 0) { - state = state.onDamageEnd(); + * Diminue le compteur de dégâts à chaque tick et rétablit l'état + * si nécessaire. + */ + private void decreaseDamage() { + if (state.isDamaged()) { + if (--damageRound <= 0) { + state = state.onDamageEnd(); } } } - + public BasicCar setState(State state) { this.state = state; return this; } - - /** - * Clique sur "Accelerer" : change d'état et retourne un message (si - * nécessaire). - */ + @Override public String accelerate() { - // Si endommagée => l'énoncé dit qu'on ne peut pas bouger if (state.isDamaged()) { return "Voiture endommagée : impossible d'accélérer"; } State next = state.accelerate(); - - // Énoncé : en BOOST, si on accélère encore => message "déjà max" if (state == State.BOOST && next == State.BOOST) { return "Déjà à la vitesse maximale"; } state = next; return ""; } - - /** - * Clique sur "Rallentir" : change d'état et retourne un message (si - * nécessaire). - */ + @Override public String decelerate() { if (state.isDamaged()) { return "Voiture endommagée : impossible de ralentir"; } - State next = state.decelerate(); - - // Énoncé : en STOPPED, si on ralentit encore => message "déjà arrêtée" if (state == State.STOPPED && next == State.STOPPED) { return "Déjà arrêtée"; } - state = next; return ""; } - + /** - * Fait avancer la voiture d'un certain nombre de positions. + * Déplace la voiture sur le circuit selon l'état courant. *

- * Si la position atteint la fin de la boucle, le compteur de tours est - * incrémenté et - * la position revient à zéro. + * Gère également les accidents et l'incrémentation des tours. *

- * - * @param move nombre de positions à avancer - * @return cette même instance (pour chaînage fluide) - */ - private void move() { - int jump = RANDOM.nextInt(state.MIN, state.MAX); - - for (int i = 0; i < jump; i++) { - pos = state.move(pos, movement); - - Point point = map.getPath(pos); - Circuit element = map.getElement(point.x, point.y); - - if (hasAccident(element, jump)) { - setDamage(); - return; + */ + private void move() { + int jump = RANDOM.nextInt(state.MIN, state.MAX); + for (int i = 0; i < jump; i++) { + pos = state.move(pos, movement); + + Point point = map.getPath(pos); + Circuit element = map.getElement(point.x, point.y); + + if (hasAccident(element, jump)) { + setDamage(); + return; } + round = pos / map.getPathSize(); } } - + + /** Vérifie si la voiture subit un accident selon l'élément du circuit */ private boolean hasAccident(Circuit element, int jump) { return element.isYRoad() && element.getValue() <= jump; } - - /** - * Consomme du carburant en fonction de l'état du jeu. - * - * @return cette même instance pour chaînage - */ + + /** Consomme du carburant en fonction de l'état courant */ public void consumeFuel() { fuel = state.fuelConsumption(fuel); if (fuel < 0) fuel = 0; // sécurité } - + + /** Indique si la voiture a terminé le nombre de tours requis */ public boolean finished() { return 3 < round; } - + /** - * Exécute une "étape" de la voiture : avance d'une position aléatoire et - * consomme du carburant. + * Exécute un tick de la voiture. *

- * La progression est déterminée par un intervalle aléatoire fourni par l'état - * du jeu. + * Si endommagée, diminue les dégâts. Sinon, avance et consomme du carburant. *

- */ - @Override - public boolean apply() { - if (state.isDamaged()) { - decreaseDamage(); + */ + @Override + public boolean apply() { + if (state.isDamaged()) { + decreaseDamage(); } else if (fuel > 0) { move(); if (isConsuming) @@ -190,80 +185,79 @@ public class BasicCar implements Car { } return !finished(); } - + @Override public void consumption(boolean active) { isConsuming = active; } - + @Override public Car remove() { return this; } - + @Override public void reverse(boolean active) { - movement = (active) ? -1 : 1; + movement = active ? -1 : 1; } /** - * @return la position actuelle dans la boucle + * Définit la voiture comme endommagée. + *

+ * Passe l'état de la voiture à {@link State#DAMAGED} et initialise le + * compteur de tours endommagés. + *

*/ + public void setDamage() { + damageRound = 5; + state = State.DAMAGED; + } + + @Override public int getPosition() { return Math.floorMod(pos, map.getPathSize()); } - - /** - * @return le score de la voiture, calculé comme : - * (nombre de tours + progression du tour) × 100 - */ + + @Override public int getScore() { return (int) ((round + (float) pos / map.getPathSize()) * 100); } - - /** - * @return le nombre de tours complétés - */ + + @Override public int getRound() { return round; } - - /** - * @return le carburant restant - */ + + @Override public int getFuel() { return fuel; } - - /** Retourne l'état courant de la voiture. */ + + @Override public State getState() { return state; } - - /** - * @return la couleur de la voiture - */ + + @Override public Color getColor() { return COLOR; } - - /** - * @return nom de la voiture - */ + + @Override public String getName() { return NAME; } - + @Override public void setup(Game game) { this.map = game.getMap(); } - + @Override public String toString() { return "nom: " + NAME + " score: " + getScore(); } - + @Override public void end() { System.out.println(this); diff --git a/src/model/car/BoostCar.java b/src/model/car/BoostCar.java index d5e2d55..b0b7806 100644 --- a/src/model/car/BoostCar.java +++ b/src/model/car/BoostCar.java @@ -1,8 +1,11 @@ package model.car; /** - * Décorateur Sound : - * affiche un message sonore quand la voiture accélère. + * BoostCar est un décorateur qui améliore la voiture en augmentant + * sa vitesse de manière temporaire ou permanente selon la logique du jeu. + *

+ * Il hérite de {@link CarDecorator} et délègue toutes les méthodes à + * la voiture encapsulée sauf celles qu'on veut modifier. */ public class BoostCar extends CarDecorator { public BoostCar(Car car) { diff --git a/src/model/car/Car.java b/src/model/car/Car.java index 1fac0a5..d138181 100644 --- a/src/model/car/Car.java +++ b/src/model/car/Car.java @@ -3,29 +3,92 @@ package model.car; import java.awt.Color; import model.Game.Observer; - +/** + * {@link Car} est l'interface représentant une voiture dans le jeu. + * + *

+ * Elle hérite de {@link Observer} afin de pouvoir être notifiée à chaque tick + * du jeu et participer à la logique principale. + *

+ * + *

+ * L'interface définit les actions possibles sur une voiture, ainsi que les + * méthodes pour obtenir son état, sa position, son score, et sa couleur. + *

+ */ public interface Car extends Observer { + + /** + * Accélère la voiture. + *

+ * Modifie l'état de la voiture selon les règles du {@link State}. + *

+ * @return message explicatif. + */ public String accelerate(); + /** + * Ralentit la voiture. + *

+ * Modifie l'état de la voiture selon les règles du {@link State}. + *

+ * @return message explicatif. + */ public String decelerate(); + /** + * Active ou désactive le mouvement inversé de la voiture. + * + * @param active true pour inverser la direction, false pour avancer normalement + */ public void reverse(boolean active); + /** + * Active ou désactive la consommation de carburant. + * + * @param active true pour consommer du carburant, false pour ne pas consommer + */ public void consumption(boolean active); + /** + * Supprime ou désactive la voiture (selon l'implémentation). + * + * @return l'instance de la voiture (pour chaînage ou gestion interne) + */ public Car remove(); + /** + * @return le nom de la voiture + */ public String getName(); + /** + * @return la position actuelle sur le circuit + */ public int getPosition(); + /** + * @return le score actuel de la voiture + */ public int getScore(); + /** + * @return le nombre de tours complétés + */ public int getRound(); + /** + * @return le carburant restant + */ public int getFuel(); + /** + * @return l'état courant de la voiture ({@link State}) + */ public State getState(); + /** + * @return la couleur de la voiture pour l'affichage + */ public Color getColor(); } diff --git a/src/model/car/CarDecorator.java b/src/model/car/CarDecorator.java index f72cd26..496a33c 100644 --- a/src/model/car/CarDecorator.java +++ b/src/model/car/CarDecorator.java @@ -1,12 +1,28 @@ package model.car; import java.awt.Color; - import model.Game; +/** + * {@link CarDecorator} est une classe abstraite servant de base pour + * les décorateurs de voitures. + * + *

+ * Elle encapsule une voiture existante ({@link Car}) et délègue + * toutes les méthodes à cette voiture. Les sous-classes peuvent + * redéfinir certaines méthodes pour ajouter un comportement + * spécifique (ex. Boost, Drunk, Hybrid). + *

+ */ public abstract class CarDecorator implements Car { + /** La voiture encapsulée à décorer */ protected final Car car; + /** + * Construit un décorateur autour d'une voiture existante. + * + * @param car la voiture à décorer + */ public CarDecorator(Car car) { this.car = car; } diff --git a/src/model/car/DrunkCar.java b/src/model/car/DrunkCar.java index 0d984cc..8bb5082 100644 --- a/src/model/car/DrunkCar.java +++ b/src/model/car/DrunkCar.java @@ -1,15 +1,16 @@ package model.car; /** - * DrunkCar = décorateur "pilote ivre". - * + * DrunkCar est un décorateur simulant un pilote ivre. + *

* Idée : - * - Quand l'utilisateur demande "Accelerer", le pilote peut se tromper - * et faire "Rallentir" à la place (au hasard). - * - Pareil quand on demande "Rallentir". - * - * => On modifie seulement les actions utilisateur (accelerate/decelerate), - * sans modifier la classe Car. + *

+ * On ne modifie que le comportement des actions utilisateur, sans toucher + * à la classe de base {@link Car}. */ public class DrunkCar extends CarDecorator { private boolean reverse = false; diff --git a/src/model/car/HybridCar.java b/src/model/car/HybridCar.java index b7523b5..190c422 100644 --- a/src/model/car/HybridCar.java +++ b/src/model/car/HybridCar.java @@ -1,12 +1,12 @@ package model.car; /** - * HybridCar = décorateur "voiture hybride". - * + * HybridCar est un décorateur représentant une voiture hybride. + *

* Idée : - * - La voiture avance à chaque tour - * - Mais elle consomme du carburant seulement 1 fois sur 2 - * => donc elle économise du carburant. + * - La voiture avance à chaque tick comme une voiture normale + * - Elle consomme du carburant seulement une fois sur deux, économisant ainsi + * l'énergie. */ public class HybridCar extends CarDecorator { private int energy = 100; // énergie batterie (0..100) @@ -16,7 +16,6 @@ public class HybridCar extends CarDecorator { car.consumption(false); } - /** pour afficher l'énergie dans le Dashboard */ public int getEnergy() { return energy; } diff --git a/src/model/car/Selection.java b/src/model/car/Selection.java index 93a134f..367e3c2 100644 --- a/src/model/car/Selection.java +++ b/src/model/car/Selection.java @@ -7,69 +7,96 @@ import java.util.function.Function; import model.Game; +/** + * Selection gère la création et la configuration des voitures + * avant le lancement du jeu. + *

+ * Elle permet : + * - d'ajouter et retirer des voitures, + * - d'ajouter des décorateurs (Hybrid, Drunk, Boost), + * - de lancer le jeu avec les voitures sélectionnées. + *

+ */ public class Selection { + /** Builder du jeu associé */ private final Game.Builder gameBuilder; + + /** Liste interne des voitures sélectionnées */ private final List cars = new ArrayList<>(); public Game.Builder getGameBuilder() { - return gameBuilder; + return gameBuilder; } + /** Constructeur : associe un Builder du jeu */ public Selection(Game.Builder gameBuilder) { this.gameBuilder = gameBuilder; } + /** Retourne une copie de la liste des voitures */ public List getCars() { return new ArrayList<>(cars); } + /** Ajoute une nouvelle voiture basique */ public Car addCar(String name, Color color) { Car car = new BasicCar(name, color); cars.add(car); return car; } + /** Supprime une voiture existante */ public void removeCar(Car car) { cars.remove(car); } + /** + * Ajoute un décorateur à une voiture existante. + * + * @param fn fonction de création du décorateur + * @param car voiture à décorer + * @return voiture décorée + */ private Car addDecorator(Function fn, Car car) throws IllegalArgumentException { int index = cars.indexOf(car); - if (index < 0) { - throw new IllegalArgumentException( - "Aucune voiture dans la classe interne."); + throw new IllegalArgumentException("Aucune voiture dans la classe interne."); } - car = fn.apply(car); - cars.set(index, car); + cars.set(index, car); // remplace l'ancienne voiture par la décorée return car; } + /** Ajoute un décorateur Hybrid */ public Car addHybridCarDecorator(Car car) throws IllegalArgumentException { return addDecorator(HybridCar::new, car); } + /** Ajoute un décorateur Drunk */ public Car addDrunkCarDecorator(Car car) throws IllegalArgumentException { return addDecorator(DrunkCar::new, car); } + /** Ajoute un décorateur Boost */ public Car addBoostCarDecorator(Car car) throws IllegalArgumentException { return addDecorator(BoostCar::new, car); } + /** + * Supprime le décorateur le plus externe d'une voiture + * (retourne la voiture "décorée de base") + */ public Car removeDecorator(Car car) throws IllegalArgumentException { int index = cars.indexOf(car); - if (index < 0) { - throw new IllegalArgumentException( - "Aucune voiture dans la classe interne."); + throw new IllegalArgumentException("Aucune voiture dans la classe interne."); } - car = car.remove(); + car = car.remove(); // enlève le décorateur le plus externe cars.set(index, car); return car; } + /** Ajoute toutes les voitures au Builder */ private Game.Builder select() { for (Car car : cars) { gameBuilder.car(car); @@ -77,11 +104,13 @@ public class Selection { return gameBuilder; } + /** Lance le jeu dans un nouveau thread */ public void run() { new Thread(() -> select().build().run()).start(); } + /** Retourne le nombre de voitures sélectionnées */ public int size() { return cars.size(); } -} +} \ No newline at end of file diff --git a/src/model/car/State.java b/src/model/car/State.java index 874466c..6d54665 100644 --- a/src/model/car/State.java +++ b/src/model/car/State.java @@ -2,88 +2,171 @@ package model.car; import java.util.List; +/** + * {@code State} représente l'état dynamique d'un véhicule. + * + *

+ * Chaque état définit : + *

    + *
  • la consommation de carburant par tour
  • + *
  • l'intervalle de déplacement possible
  • + *
  • le comportement lors d'une accélération ou décélération
  • + *
  • le comportement spécifique en cas de dégâts
  • + *
+ * + *

+ * Ce design correspond au State Pattern : + * le comportement du véhicule varie selon son état courant + * sans avoir recours à des conditions {@code if / switch}. + */ public enum State { + /** - * L'état NORMAL du Vehicule avance selon un chiffre au alentour de 1 à 6 cases - * par tour. Il consomme 2 unités de carburant à chaque tour. Si l'on - * accelere, il passe à l'état BOOST. Si on Rallenti, il passe à l'état LOW. + * État NORMAL du véhicule. + * + *

+ * Le véhicule avance d'un nombre aléatoire de cases + * compris entre 1 et 6 inclus. + * Il consomme 2 unités de carburant par tour. + * + *

+ * Transitions possibles : + *

    + *
  • accélération → {@link #BOOST}
  • + *
  • décélération → {@link #LOW}
  • + *
*/ NORMAL(2, 1, 6) { + @Override public State accelerate() { return BOOST; } + @Override public State decelerate() { return LOW; } }, /** - * L'état BOOST du Vehicule avance selon un chiffre au alentour de 5 à 10 cases - * par tour. Il consomme 5 unités de carburant à chaque tour. Si l'on - * accelere, il reste sur son état et indique un message sur le tableau de bord. - * Si on Rallenti, il passe à l'état LOW. + * État BOOST du véhicule. + * + *

+ * Le véhicule avance rapidement (entre 5 et 10 cases). + * Il consomme 5 unités de carburant par tour. + * + *

+ * Transitions possibles : + *

    + *
  • accélération → reste en {@link #BOOST}
  • + *
  • décélération → {@link #NORMAL}
  • + *
*/ BOOST(5, 5, 10) { + @Override public State accelerate() { return this; } + @Override public State decelerate() { return NORMAL; } }, /** - * L'état LOW du Vehicule avance selon un chiffre au alentour de 1 à 3 cases - * par tour. Il consomme 1 unités de carburant à chaque tour. Si l'on - * accelere, il passe à l'état NORMAL. Si on Rallenti, il passe à l'état - * STOPPED. + * État LOW du véhicule. + * + *

+ * Le véhicule avance lentement (entre 1 et 3 cases). + * Il consomme 1 unité de carburant par tour. + * + *

+ * Transitions possibles : + *

    + *
  • accélération → {@link #NORMAL}
  • + *
  • décélération → {@link #STOPPED}
  • + *
*/ LOW(1, 1, 3) { + @Override public State accelerate() { return NORMAL; } + @Override public State decelerate() { return STOPPED; } }, /** - * L'état STOPPED du Vehicule n'avance pas. Il consomme aucune unités de - * carburant à chaque tour. Si l'on - * accelere, il passe à l'état LOW. Si on Rallenti, il reste sur son état et - * indique un message sur le tableau de bord. + * État STOPPED du véhicule. + * + *

+ * Le véhicule est à l'arrêt : + *

    + *
  • il n'avance pas
  • + *
  • il ne consomme pas de carburant
  • + *
+ * + *

+ * Transitions possibles : + *

    + *
  • accélération → {@link #LOW}
  • + *
  • décélération → reste en {@link #STOPPED}
  • + *
*/ STOPPED(0, 0, 0) { + @Override public State accelerate() { return LOW; } + @Override public State decelerate() { return this; } + /** + * Un véhicule arrêté ne se déplace pas. + */ @Override public int move(int pos, int jump) { return pos; } + /** + * Un véhicule arrêté ne consomme pas de carburant. + */ @Override public int fuelConsumption(int fuel) { return fuel; } }, + /** - * L'état STOPPED du Vehicule n'avance pas. Il consomme aucune unités de - * carburant à chaque tour. Il reste immobile. + * État DAMAGED du véhicule. + * + *

+ * Le véhicule est endommagé : + *

    + *
  • il ne se déplace pas
  • + *
  • il ne consomme pas de carburant
  • + *
  • il ignore les accélérations et décélérations
  • + *
+ * + *

+ * Cet état est temporaire : après réparation, + * le véhicule repasse à l'état {@link #LOW}. */ DAMAGED(0, 0, 0) { + @Override public State accelerate() { return this; } + @Override public State decelerate() { return this; } @@ -108,39 +191,92 @@ public enum State { return LOW; } }; - // @formatter:on + /* ========================================================== + * Attributs communs à tous les états + * ========================================================== */ + + /** Consommation de carburant par tour */ public final int FUELCOST; + + /** Borne maximale (exclusive) de déplacement */ public final int MAX; + + /** Borne minimale (inclusive) de déplacement */ public final int MIN; + /** + * Constructeur interne des états. + * + * @param fuelCost consommation par tour + * @param min déplacement minimal + * @param max déplacement maximal (inclus) + */ private State(int fuelCost, int min, int max) { this.FUELCOST = fuelCost; - this.MAX = max + 1; this.MIN = min; + this.MAX = max + 1; } + /** + * Retourne l'intervalle de déplacement possible pour cet état. + * + * @return liste contenant [MIN, MAX[ + */ public List getInterval() { return List.of(MIN, MAX); } + /** + * Applique la consommation de carburant. + * + * @param fuel carburant actuel + * @return carburant restant + */ public int fuelConsumption(int fuel) { return fuel - FUELCOST; } + /** + * Calcule la nouvelle position du véhicule. + * + * @param pos position actuelle + * @param jump déplacement calculé + * @return nouvelle position + */ public int move(int pos, int jump) { return pos + jump; } + /** + * Indique si l'état correspond à un véhicule endommagé. + * + * @return {@code true} si endommagé, sinon {@code false} + */ public boolean isDamaged() { return false; } + /** + * État à appliquer lorsque les dégâts sont réparés. + * + * @return nouvel état après réparation + */ public State onDamageEnd() { return this; } + /** + * Transition lors d'une accélération. + * + * @return le nouvel état + */ public abstract State accelerate(); + /** + * Transition lors d'une décélération. + * + * @return le nouvel état + */ public abstract State decelerate(); } \ No newline at end of file