Files
racing-game/src/Car.java
Loïc GUEZO a5d03178d9 feat(Car): nouveau constructor et fonction reverse
- ajout nouveau constructor pour clone la voiture
- ajout de la fonction reversing pour faire revenir en arriere la voiture
2025-12-18 14:09:52 +01:00

349 lines
9.7 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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é.
* <p>
* 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.
* </p>
*/
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<Integer> getInterval() {
return List.of(MIN, MAX);
}
public int fuelConsumption(int fuel) {
return fuel - FUELCOST;
}
public int move(int pos, int jump) {
return pos + jump;
}
public boolean isDamaged() {
return false;
}
public State onDamageEnd() {
return this;
}
public abstract State accelerate();
public abstract State decelerate();
}
/**
* 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 boolean decreaseDamage() {
if (state.isDamaged()) {
if (--damageRound <= 0) {
state = state.onDamageEnd();
}
return true;
}
return false;
}
public Car setState(State state) {
this.state = state;
return this;
}
/**
* @return la position actuelle dans la boucle
*/
public int getPosition() {
return pos;
}
/**
* @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;
}
/**
* Clique sur "Accelerer" : change d'état et retourne un message (si
* nécessaire).
*/
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).
*/
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.
* <p>
* Si la position atteint la fin de la boucle, le compteur de tours est
* incrémenté et
* la position revient à zéro.
* </p>
*
* @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.
* <p>
* La progression est déterminée par un intervalle aléatoire fourni par l'état
* du jeu.
* </p>
*/
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;
}
}