import java.awt.Color; import java.awt.Point; import java.util.List; import java.util.Random; /** * {@link Car} 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 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 final Map MAP; /** Carburant restant */ private int fuel = 60; private boolean isReversing = false; /** * Construit une nouvelle voiture. * * @param name nom de la voiture * @param color couleur de la voiture * @param map */ public Car(String name, Color color, Map map) { this.NAME = name; this.COLOR = color; this.MAP = map; } public Car(Car other) { this.NAME = other.NAME; this.COLOR = other.COLOR; this.MAP = other.MAP; } public static 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. */ // @formatter:off NORMAL(2, 1, 6) { public State accelerate() { return BOOST; } 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. */ BOOST(5, 5, 10) { public State accelerate() { return this; } 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. */ LOW(1, 1, 3) { public State accelerate() { return NORMAL; } 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. */ STOPPED(0, 0, 0) { public State accelerate() { return LOW; } public State decelerate() { return this; } @Override public int move(int pos, int jump) { return pos; } @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. */ DAMAGED(0, 0, 0) { public State accelerate() { return this; } public State decelerate() { return this; } @Override public int move(int pos, int jump) { return pos; } @Override public int fuelConsumption(int fuel) { return fuel; } @Override public boolean isDamaged() { return true; } @Override public State onDamageEnd() { return LOW; } }; // @formatter:on public final int FUELCOST; public final int MAX; public final int MIN; private State(int fuelCost, int min, int max) { this.FUELCOST = fuelCost; this.MAX = max + 1; this.MIN = min; } public List* 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) */ public void move() { if (decreaseDamage()) { System.out.println(NAME + " est en\taccident " + damageRound); return; } int jump = RANDOM.nextInt(state.MIN, state.MAX); int direction = (isReversing) ? -1 : 1; for (int i = 0; i < jump; i++) { pos = state.move(pos, direction); Point point = MAP.getPath(pos); Map.Circuit element = MAP.getElement(point.x, point.y); if (hasAccident(element, jump)) { System.out.println(NAME + " a un\taccident"); setDamage(); return; } round = pos / MAP.getPathSize(); } isReversing = false; } private boolean hasAccident(Map.Circuit element, int jump) { return element.isYRoad() && element.getValue() <= jump; } public void reverse() { isReversing = !isReversing; } /** * 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é } /** * 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. *
*/ public void run() { if (fuel > 0) { move(); consumeFuel(); } } /** * @return la position actuelle (synonyme de getPosition) */ public int getPos() { return pos; } /** * @return la couleur de la voiture */ public Color getColor() { return COLOR; } /** * @return nom de la voiture */ public String getName() { return NAME; } }