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).
* </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
* 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
* à afficher dans le jeu (par exemple un tableau de bord, une piste ou un classement).
* {@link VisualInfo} est un enregistrement (record) qui décrit une vue
* graphique
* à afficher dans le jeu (par exemple un tableau de bord, une piste ou un
* classement).
* <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.
* </p>
*
@@ -32,13 +47,41 @@ public class Game
* @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
*/
public record VisualInfo
(
Class<? extends GameView> type,
String title,
int width, int height,
int x, int y
) {}
private record VisualInfo(Class<? extends GameView> type,
String title, int width, int height, int x, int y) {
}
public static class GameFactory {
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.
@@ -47,84 +90,80 @@ public class Game
* le temps entre les étapes du jeu avant de construire l'objet final.
* </p>
*/
public static class Builder
{
public static class Builder {
/** Liste des voitures à créer pour le jeu */
private ArrayList<CarInfo> cars = new ArrayList<>();
/** Liste des voitures à créer pour le jeu */
private ArrayList<VisualInfo> visuals = new ArrayList<>();
/** État initial du jeu */
private State state = new State();
private Car.State state = Car.State.NORMAL;
/** Temps entre chaque step du jeu */
private int time = 1000;
/** Carte sur laquelle se déroule le jeu */
private Map map = null;
/** Ajoute une voiture à la liste */
public Builder addCar(CarInfo car)
{
cars.add(car);
public Builder addCar(String name, Color color) {
cars.add(new CarInfo(name, color));
return this;
}
/** Supprime une voiture de la liste */
public Builder remCar(CarInfo car)
{
public Builder removeCar(String name, Color color) {
cars.forEach((car) -> {
if (car.name == name && car.color == color)
cars.remove(car);
});
return this;
}
/** Définit la carte du jeu */
public Builder setMap(Map map)
{
public Builder setMap(Map map) {
this.map = map;
return this;
}
/** Définit l'état initial du jeu */
public Builder setState(State s)
{
public Builder setState(Car.State s) {
this.state = s;
return this;
}
/** Définit le temps entre chaque étape du jeu */
public Builder setTime(int time)
{
public Builder setTime(int time) {
this.time = time;
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));
return this;
}
private void buildVisual(Game game)
{
for (VisualInfo v : visuals)
{
if (v.type == Rankboard.class)
game.addObserver(new Rankboard(game, v.title, v.width, v.height, v.x, v.y));
else if (v.type == Track.class)
game.addObserver(new Track(game, v.title, v.width, v.height, v.x, v.y));
else if (v.type == Dashboard.class)
{
for (CarInfo info : cars)
{
if (info.name.equals(v.title))
{
private void buildVisual(Game game) {
for (VisualInfo visual : visuals) {
GameView view = null;
if (visual.type == Rankboard.class) {
view = new Rankboard(game, visual.title, visual.width,
visual.height, visual.x, visual.y);
} else if (visual.type == Track.class) {
view = new Track(game, visual.title, visual.width,
visual.height, visual.x, visual.y);
} else if (visual.type == Dashboard.class) {
Car car = game.getCars().stream()
.filter(c -> c.getName().equals(info.name))
.filter((e) -> visual.title.equals(e.getName()))
.findFirst()
.orElse(null);
if (car != null)
game.addObserver(new Dashboard(game, car, v.title, v.width, v.height, v.x, v.y));
break;
}
}
.orElseThrow();
view = new Dashboard(game,
car,
visual.title, visual.width,
visual.height, visual.x, visual.y);
}
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.
* </p>
*/
public Game build()
{
if (map == null)
{
public Game build() {
if (map == null) {
System.err.println("Vous devez définir une carte avant de construire le jeu !");
System.exit(1);
}
@@ -150,14 +187,14 @@ public class Game
private final Map map;
/** État du jeu (par exemple, positions, carburant) */
private final State state;
private final Car.State state;
/** Temps entre chaque étape du jeu en millisecondes */
private final int time;
/** Liste des voitures du jeu */
private final ArrayList<Car> cars = new ArrayList<>();
/** 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 */
private boolean isPaused = false;
@@ -170,8 +207,7 @@ public class Game
* @param state état initial 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.state = state;
this.time = time;
@@ -189,13 +225,11 @@ public class Game
* @param carInfos liste des informations des voitures
* @return l'instance de Game
*/
private Game init(ArrayList<CarInfo> carInfos)
{
final int loop = map.getPathSize();
private Game init(ArrayList<CarInfo> carInfos) {
// Création de chaque voiture avec son Dashboard
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;
}
@@ -208,10 +242,8 @@ public class Game
*
* @return true si le jeu est terminé
*/
private boolean isFinish()
{
for (Car car : cars)
{
private boolean isFinish() {
for (Car car : cars) {
if (car.getFuel() == 0)
return true;
}
@@ -224,8 +256,7 @@ public class Game
* @param o observateur
* @return instance de Game pour chaîner
*/
public Game addObserver(GObserver o)
{
public Game addObserver(observer o) {
obs.add(o);
return this;
}
@@ -236,8 +267,7 @@ public class Game
* @param o observateur
* @return instance de Game pour chaîner
*/
public Game remObserver(GObserver o)
{
public Game remObserver(observer o) {
obs.remove(o);
return this;
}
@@ -245,25 +275,23 @@ public class Game
/**
* Bascule l'état de pause du jeu.
* <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>
*
* @return true si le jeu est maintenant en pause
*/
public synchronized boolean togglePause()
{
if (isPaused) notifyAll();
public synchronized boolean togglePause() {
if (isPaused)
notifyAll();
isPaused = !isPaused;
return isPaused;
}
public void notifyObservers()
{
for (GObserver o : obs)
{
public void notifyObservers() {
for (observer o : obs) {
boolean isSuccess = o.apply();
if (!isSuccess)
{
if (!isSuccess) {
System.err.println("Une erreur s'est produite pendant le jeu.");
System.exit(1);
}
@@ -279,12 +307,9 @@ public class Game
*
* @throws InterruptedException si le thread est interrompu pendant wait()
*/
private void step() throws InterruptedException
{
for (Car car : cars)
{
synchronized(this)
{
private void step() throws InterruptedException {
for (Car car : cars) {
synchronized (this) {
while (isPaused)
wait();
}
@@ -301,46 +326,36 @@ public class Game
* les vues toutes les 'time' millisecondes.
* </p>
*/
public void run()
{
while (!isFinish())
{
try
{
public void run() {
while (!isFinish()) {
try {
step();
Thread.sleep(time);
}
catch (InterruptedException e)
{
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Fini!\nVoici le score :");
for (Car c : cars)
{
for (Car c : cars) {
System.out.println(c.getName() + "\t" + c.getScore());
}
System.exit(0);
}
public ArrayList<Car> getCars()
{
public ArrayList<Car> getCars() {
return cars;
}
public Map getMap()
{
public Map getMap() {
return map;
}
public State getState()
{
public Car.State getState() {
return state;
}
public boolean getPause()
{
public boolean getPause() {
return isPaused;
}
}