package model.car; import java.awt.Color; import java.awt.Point; import java.util.Random; 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é. *

* 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. *

*/ 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) */ private Map map; /** Carburant restant */ private int fuel = 60; private int movement = 1; private boolean isConsuming = true; /** * Construit une nouvelle voiture. * * @param name nom de la voiture * @param color couleur de la voiture * @param map */ public BasicCar(String name, Color color, Map map) { this.NAME = name; this.COLOR = color; this.map = map; } 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(); } } } 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. *

* Si la position atteint la fin de la boucle, le compteur de tours est * incrémenté et * la position revient à zéro. *

* * @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; } round = pos / map.getPathSize(); } } 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 */ public void consumeFuel() { fuel = state.fuelConsumption(fuel); if (fuel < 0) fuel = 0; // sécurité } public boolean hasFinished() { return 3 < round; } /** * Exécute une "étape" de la voiture : avance d'une position aléatoire et * consomme du carburant. *

* La progression est déterminée par un intervalle aléatoire fourni par l'état * du jeu. *

*/ @Override public boolean apply() { if (state.isDamaged()) { decreaseDamage(); } else if (fuel > 0) { move(); if (isConsuming) consumeFuel(); } return !hasFinished(); } @Override public void consumption(boolean active) { isConsuming = active; } @Override public Car remove() { return this; } @Override public void reverse(boolean active) { movement = (active) ? -1 : 1; } /** * @return la position actuelle dans la boucle */ public int getPosition() { return Math.floorMod(pos, map.getPathSize()); } /** * @return le score de la voiture, calculé comme : * (nombre de tours + progression du tour) × 100 */ public int getScore() { return (int) ((round + (float) pos / map.getPathSize()) * 100); } /** * @return le nombre de tours complétés */ public int getRound() { return round; } /** * @return le carburant restant */ public int getFuel() { return fuel; } /** Retourne l'état courant de la voiture. */ public State getState() { return state; } /** * @return la couleur de la voiture */ public Color getColor() { return COLOR; } /** * @return nom de la voiture */ public String getName() { return NAME; } @Override public void setMap(Map map) { this.map = map; } }