feat(Game)!: factorise les classes unique au besoin de game et ajout de gameFactory et quelque petite amelioration

This commit is contained in:
2025-12-10 20:00:35 +01:00
parent 4f2a852cb0
commit f2c2585cc0
3 changed files with 151 additions and 287 deletions

View File

@@ -1,138 +0,0 @@
/**
* Représente une cellule du circuit.
* <p>
* Chaque cellule possède un type ({@link Cell}) et éventuellement une valeur
* numérique (par exemple pour indiquer une intensité, une vitesse, ou un identifiant de route).
* </p>
*/
public class Circuit
{
/**
* <code>Cell</code> est un enum
* représentant les différents types de
* cases qui composent le circuit de
* course.
*/
public static enum Cell
{
/**
* Case hors piste, non
* praticable par les
* voitures. */
EMPTY,
/**
* Case de route normale
* sur laquelle les voitures
* peuvent circuler.
*/
ROAD,
/**
* Case correspondant à la
* ligne de départ du circuit.
*/
START,
/**
* Case correspondant à la
* ligne d'arrivée du circuit.
*/
FINISH,
/**
* Case de route jaune, plus
* d'information sur le
* livrable 2
*/
YROAD;
}
/** Type de la cellule (vide, route, départ, arrivée, etc.) */
private final Cell type;
/** Valeur associée à la cellule (optionnelle, dépend du type) */
private int value;
/**
* Construit une cellule avec un type défini et une valeur par défaut
* égale à lindice ordinal du type.
*
* @param type le type de la cellule
*/
public Circuit(Cell type)
{
this.type = type;
this.value = type.ordinal();
}
/**
* Construit une cellule avec un type et une valeur spécifique.
*
* @param type le type de la cellule
* @param value la valeur associée à la cellule
*/
public Circuit(Cell type, int value)
{
this.type = type;
this.value = value;
}
/**
* Modifie la valeur associée à la cellule.
*
* @param value la nouvelle valeur
* @return cette même instance (pour chaînage fluide)
*/
public Circuit setValue(int value)
{
this.value = value;
return this;
}
/**
* @return le type de la cellule
*/
public Cell getType()
{
return type;
}
/**
* @return la valeur associée à la cellule
*/
public int getValue()
{
return value;
}
/**
* Vérifie si la cellule est une route (ROAD ou YROAD).
*
* @return vrai si la cellule représente une route
*/
public boolean isRoad()
{
return type == Cell.ROAD || type == Cell.YROAD;
}
/**
* Vérifie si la cellule est un point de départ.
*
* @return vrai si la cellule représente le départ
*/
public boolean isStart()
{
return type == Cell.START;
}
/**
* Vérifie si la cellule est un point darrivée.
*
* @return vrai si la cellule représente la fin du circuit
*/
public boolean isFinish()
{
return type == Cell.FINISH;
}
}

View File

@@ -1,13 +0,0 @@
@FunctionalInterface
/**
* L'interface utilisée pour Game.
*/
public interface GObserver
{
/**
*
* @return true si la fonction s'est bien passé sinon false (le programme va se
* stopper)
*/
public boolean apply();
}

View File

@@ -9,19 +9,34 @@ import java.util.ArrayList;
* (pause, boucle de jeu, observateurs). * (pause, boucle de jeu, observateurs).
* </p> * </p>
*/ */
public class Game public class Game {
{ @FunctionalInterface
/**
* L'interface utilisée pour Game.
*/
public interface observer {
/**
*
* @return true si la fonction s'est bien passé sinon false (le programme va se
* stopper)
*/
public boolean apply();
}
/** /**
* {@link CarInfo} est une structure simple qui contient les informations * {@link CarInfo} est une structure simple qui contient les informations
* nécessaires pour créer une voiture dans le jeu : son nom et sa couleur. * nécessaires pour créer une voiture dans le jeu : son nom et sa couleur.
*/ */
public record CarInfo(String name, Color color) {} private record CarInfo(String name, Color color) {}
/** /**
* {@link VisualInfo} est un enregistrement (record) qui décrit une vue graphique * {@link VisualInfo} est un enregistrement (record) qui décrit une vue
* à afficher dans le jeu (par exemple un tableau de bord, une piste ou un classement). * graphique
* à afficher dans le jeu (par exemple un tableau de bord, une piste ou un
* classement).
* <p> * <p>
* Chaque instance contient toutes les informations nécessaires pour créer et positionner * Chaque instance contient toutes les informations nécessaires pour créer et
* positionner
* cette vue à lécran. * cette vue à lécran.
* </p> * </p>
* *
@@ -32,13 +47,41 @@ public class Game
* @param x la position horizontale (en pixels) de la vue sur lécran * @param x la position horizontale (en pixels) de la vue sur lécran
* @param y la position verticale (en pixels) de la vue sur lécran * @param y la position verticale (en pixels) de la vue sur lécran
*/ */
public record VisualInfo private record VisualInfo(Class<? extends GameView> type,
( String title, int width, int height, int x, int y) {
Class<? extends GameView> type, }
String title,
int width, int height, public static class GameFactory {
int x, int y public static Map defaultMap() {
) {} return Map.fromInts(new Integer[][] {
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, -1, -1, 5, 0 },
{ 0, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, 0, 0, -1, 0, 0, -1, 0 },
{ 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0 },
{ 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0 },
{ 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, -1, -1, 2, 0, 0, -1, 0 },
{ 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0 },
{ 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0 },
{ 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -3, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
});
}
public static Game defaultGame(Map map) {
return new Game.Builder()
.addCar("Voiture à LUWIK", Color.BLUE)
.addCar("Voiture à CHARAZADE", Color.PINK)
.addCar("Voiture de UPEC", Color.RED)
.addVisual(Dashboard.class, "Voiture à LUWIK", 300, 200, 1000, 0)
.addVisual(Dashboard.class, "Voiture à CHARAZADE", 300, 200, 1000, 200)
.addVisual(Dashboard.class, "Voiture de UPEC", 300, 200, 1000, 400)
.addVisual(Track.class, "Piste Formule 1", 1000, 500, 1, 1)
.addVisual(Rankboard.class, "Score", 200, 200, 0, 510)
.setTime(1000)
.setMap(map)
.build();
}
}
/** /**
* Builder pour créer une instance de {@link Game} de façon fluide. * Builder pour créer une instance de {@link Game} de façon fluide.
@@ -47,84 +90,80 @@ public class Game
* le temps entre les étapes du jeu avant de construire l'objet final. * le temps entre les étapes du jeu avant de construire l'objet final.
* </p> * </p>
*/ */
public static class Builder public static class Builder {
{
/** Liste des voitures à créer pour le jeu */ /** Liste des voitures à créer pour le jeu */
private ArrayList<CarInfo> cars = new ArrayList<>(); private ArrayList<CarInfo> cars = new ArrayList<>();
/** Liste des voitures à créer pour le jeu */ /** Liste des voitures à créer pour le jeu */
private ArrayList<VisualInfo> visuals = new ArrayList<>(); private ArrayList<VisualInfo> visuals = new ArrayList<>();
/** État initial du jeu */ /** État initial du jeu */
private State state = new State(); private Car.State state = Car.State.NORMAL;
/** Temps entre chaque step du jeu */ /** Temps entre chaque step du jeu */
private int time = 1000; private int time = 1000;
/** Carte sur laquelle se déroule le jeu */ /** Carte sur laquelle se déroule le jeu */
private Map map = null; private Map map = null;
/** Ajoute une voiture à la liste */ /** Ajoute une voiture à la liste */
public Builder addCar(CarInfo car) public Builder addCar(String name, Color color) {
{ cars.add(new CarInfo(name, color));
cars.add(car);
return this; return this;
} }
/** Supprime une voiture de la liste */ /** Supprime une voiture de la liste */
public Builder remCar(CarInfo car) public Builder removeCar(String name, Color color) {
{ cars.forEach((car) -> {
cars.remove(car); if (car.name == name && car.color == color)
cars.remove(car);
});
return this; return this;
} }
/** Définit la carte du jeu */ /** Définit la carte du jeu */
public Builder setMap(Map map) public Builder setMap(Map map) {
{
this.map = map; this.map = map;
return this; return this;
} }
/** Définit l'état initial du jeu */ /** Définit l'état initial du jeu */
public Builder setState(State s) public Builder setState(Car.State s) {
{
this.state = s; this.state = s;
return this; return this;
} }
/** Définit le temps entre chaque étape du jeu */ /** Définit le temps entre chaque étape du jeu */
public Builder setTime(int time) public Builder setTime(int time) {
{
this.time = time; this.time = time;
return this; return this;
} }
public Builder addVisual(Class<? extends GameView> type, String title, int width, int height, int x, int y) public Builder addVisual(Class<? extends GameView> type, String title,
{ int width, int height, int x, int y) {
visuals.add(new VisualInfo(type, title, width, height, x, y)); visuals.add(new VisualInfo(type, title, width, height, x, y));
return this; return this;
} }
private void buildVisual(Game game) private void buildVisual(Game game) {
{ for (VisualInfo visual : visuals) {
for (VisualInfo v : visuals) GameView view = null;
{
if (v.type == Rankboard.class) if (visual.type == Rankboard.class) {
game.addObserver(new Rankboard(game, v.title, v.width, v.height, v.x, v.y)); view = new Rankboard(game, visual.title, visual.width,
else if (v.type == Track.class) visual.height, visual.x, visual.y);
game.addObserver(new Track(game, v.title, v.width, v.height, v.x, v.y)); } else if (visual.type == Track.class) {
else if (v.type == Dashboard.class) view = new Track(game, visual.title, visual.width,
{ visual.height, visual.x, visual.y);
for (CarInfo info : cars) } else if (visual.type == Dashboard.class) {
{ Car car = game.getCars().stream()
if (info.name.equals(v.title)) .filter((e) -> visual.title.equals(e.getName()))
{ .findFirst()
Car car = game.getCars().stream() .orElseThrow();
.filter(c -> c.getName().equals(info.name))
.findFirst() view = new Dashboard(game,
.orElse(null); car,
if (car != null) visual.title, visual.width,
game.addObserver(new Dashboard(game, car, v.title, v.width, v.height, v.x, v.y)); visual.height, visual.x, visual.y);
break;
}
}
} }
if (view != null)
game.addObserver(view);
} }
} }
@@ -134,10 +173,8 @@ public class Game
* Si la carte n'a pas été définie, le programme s'arrête. * Si la carte n'a pas été définie, le programme s'arrête.
* </p> * </p>
*/ */
public Game build() public Game build() {
{ if (map == null) {
if (map == null)
{
System.err.println("Vous devez définir une carte avant de construire le jeu !"); System.err.println("Vous devez définir une carte avant de construire le jeu !");
System.exit(1); System.exit(1);
} }
@@ -147,38 +184,37 @@ public class Game
return game; return game;
} }
} }
private final Map map; private final Map map;
/** État du jeu (par exemple, positions, carburant) */ /** État du jeu (par exemple, positions, carburant) */
private final State state; private final Car.State state;
/** Temps entre chaque étape du jeu en millisecondes */ /** Temps entre chaque étape du jeu en millisecondes */
private final int time; private final int time;
/** Liste des voitures du jeu */ /** Liste des voitures du jeu */
private final ArrayList<Car> cars = new ArrayList<>(); private final ArrayList<Car> cars = new ArrayList<>();
/** Liste des observateurs pour la mise à jour des vues */ /** Liste des observateurs pour la mise à jour des vues */
private final ArrayList<GObserver> obs = new ArrayList<>(); private final ArrayList<observer> obs = new ArrayList<>();
/** Indique si le jeu est en pause */ /** Indique si le jeu est en pause */
private boolean isPaused = false; private boolean isPaused = false;
/** /**
* Constructeur principal. * Constructeur principal.
* *
* @param map carte du jeu * @param map carte du jeu
* @param carInfos liste des informations des voitures à créer * @param carInfos liste des informations des voitures à créer
* @param state état initial du jeu * @param state état initial du jeu
* @param time temps entre chaque étape du jeu * @param time temps entre chaque étape du jeu
*/ */
public Game(Map map, ArrayList<CarInfo> carInfos, State state, int time) public Game(Map map, ArrayList<CarInfo> carInfos, Car.State state, int time) {
{
this.map = map; this.map = map;
this.state = state; this.state = state;
this.time = time; this.time = time;
init(carInfos); init(carInfos);
} }
/** /**
* Initialise le jeu en créant les vues et les objets {@link Car}. * Initialise le jeu en créant les vues et les objets {@link Car}.
* <p> * <p>
@@ -189,17 +225,15 @@ public class Game
* @param carInfos liste des informations des voitures * @param carInfos liste des informations des voitures
* @return l'instance de Game * @return l'instance de Game
*/ */
private Game init(ArrayList<CarInfo> carInfos) private Game init(ArrayList<CarInfo> carInfos) {
{
final int loop = map.getPathSize();
// Création de chaque voiture avec son Dashboard // Création de chaque voiture avec son Dashboard
for (CarInfo ci : carInfos) for (CarInfo ci : carInfos)
cars.add(new Car(ci.name, ci.color, loop, state)); cars.add(new Car(ci.name, ci.color, map)
.setState(state));
return this; return this;
} }
/** /**
* Vérifie si le jeu est terminé. * Vérifie si le jeu est terminé.
* <p> * <p>
@@ -208,68 +242,62 @@ public class Game
* *
* @return true si le jeu est terminé * @return true si le jeu est terminé
*/ */
private boolean isFinish() private boolean isFinish() {
{ for (Car car : cars) {
for (Car car : cars)
{
if (car.getFuel() == 0) if (car.getFuel() == 0)
return true; return true;
} }
return false; return false;
} }
/** /**
* Ajoute un observateur pour recevoir les mises à jour du jeu. * Ajoute un observateur pour recevoir les mises à jour du jeu.
* *
* @param o observateur * @param o observateur
* @return instance de Game pour chaîner * @return instance de Game pour chaîner
*/ */
public Game addObserver(GObserver o) public Game addObserver(observer o) {
{
obs.add(o); obs.add(o);
return this; return this;
} }
/** /**
* Supprime un observateur. * Supprime un observateur.
* *
* @param o observateur * @param o observateur
* @return instance de Game pour chaîner * @return instance de Game pour chaîner
*/ */
public Game remObserver(GObserver o) public Game remObserver(observer o) {
{
obs.remove(o); obs.remove(o);
return this; return this;
} }
/** /**
* Bascule l'état de pause du jeu. * Bascule l'état de pause du jeu.
* <p> * <p>
* Si le jeu était en pause, il est relancé et les threads en attente sont notifiés. * Si le jeu était en pause, il est relancé et les threads en attente sont
* notifiés.
* </p> * </p>
* *
* @return true si le jeu est maintenant en pause * @return true si le jeu est maintenant en pause
*/ */
public synchronized boolean togglePause() public synchronized boolean togglePause() {
{ if (isPaused)
if (isPaused) notifyAll(); notifyAll();
isPaused = !isPaused; isPaused = !isPaused;
return isPaused; return isPaused;
} }
public void notifyObservers() public void notifyObservers() {
{ for (observer o : obs) {
for (GObserver o : obs)
{
boolean isSuccess = o.apply(); boolean isSuccess = o.apply();
if (!isSuccess) if (!isSuccess) {
{
System.err.println("Une erreur s'est produite pendant le jeu."); System.err.println("Une erreur s'est produite pendant le jeu.");
System.exit(1); System.exit(1);
} }
} }
} }
/** /**
* Exécute un cycle du jeu * Exécute un cycle du jeu
* <p> * <p>
@@ -279,21 +307,18 @@ public class Game
* *
* @throws InterruptedException si le thread est interrompu pendant wait() * @throws InterruptedException si le thread est interrompu pendant wait()
*/ */
private void step() throws InterruptedException private void step() throws InterruptedException {
{ for (Car car : cars) {
for (Car car : cars) synchronized (this) {
{
synchronized(this)
{
while (isPaused) while (isPaused)
wait(); wait();
} }
car.run(); car.run();
notifyObservers(); notifyObservers();
} }
} }
/** /**
* Boucle principale du jeu. * Boucle principale du jeu.
* <p> * <p>
@@ -301,46 +326,36 @@ public class Game
* les vues toutes les 'time' millisecondes. * les vues toutes les 'time' millisecondes.
* </p> * </p>
*/ */
public void run() public void run() {
{ while (!isFinish()) {
while (!isFinish()) try {
{
try
{
step(); step();
Thread.sleep(time); Thread.sleep(time);
} } catch (InterruptedException e) {
catch (InterruptedException e)
{
e.printStackTrace(); e.printStackTrace();
} }
} }
System.out.println("Fini!\nVoici le score :"); System.out.println("Fini!\nVoici le score :");
for (Car c : cars) for (Car c : cars) {
{
System.out.println(c.getName() + "\t" + c.getScore()); System.out.println(c.getName() + "\t" + c.getScore());
} }
System.exit(0); System.exit(0);
} }
public ArrayList<Car> getCars() public ArrayList<Car> getCars() {
{
return cars; return cars;
} }
public Map getMap() public Map getMap() {
{
return map; return map;
} }
public State getState() public Car.State getState() {
{
return state; return state;
} }
public boolean getPause() public boolean getPause() {
{
return isPaused; return isPaused;
} }
} }