import java.awt.Color; import java.util.ArrayList; /** * La classe {@link Game} représente le moteur principal du jeu. *
* Elle contient le modèle (les voitures, l'état du jeu, la carte), * la vue (Track, Dashboard, Rankboard) et la logique de contrôle * (pause, boucle de jeu, observateurs). *
*/ public class Game { /** * {@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 static class CarInfo { /** Nom de la voiture */ public final String name; /** Couleur de la voiture */ public final Color color; public CarInfo(String name, Color color, boolean visual) { this.name = name; this.color = color; } } /** * Builder pour créer une instance de {@link Game} de façon fluide. ** Permet d'ajouter des voitures, de définir la carte, l'état initial et * le temps entre les étapes du jeu avant de construire l'objet final. *
*/ public static class Builder { /** Liste des voitures à créer pour le jeu */ private ArrayList* Si la carte n'a pas été définie, le programme s'arrête. *
*/ public Game build() { if (map == null) { System.err.println("Vous devez définir une carte avant de construire le jeu !"); System.exit(1); } return new Game(map, cars, state, time); } } private final Map map; /** État du jeu (par exemple, positions, carburant) */ private final State state; /** Temps entre chaque étape du jeu en millisecondes */ private final int time; /** Liste des voitures du jeu */ private final ArrayList* Chaque voiture obtient un Dashboard, la piste est affichée avec Track, * et le Rankboard est créé pour afficher le classement. *
* * @param carInfos liste des informations des voitures * @return l'instance de Game */ private Game init(ArrayList* Le jeu est fini si au moins une voiture a épuisé son carburant. *
* * @return true si le jeu est terminé */ private boolean isFinish() { for (Car car : cars) { if (car.getFuel() == 0) return true; } return false; } /** * Ajoute un observateur pour recevoir les mises à jour du jeu. * * @param o observateur * @return instance de Game pour chaîner */ public Game addObserver(GObserver o) { obs.add(o); return this; } /** * Supprime un observateur. * * @param o observateur * @return instance de Game pour chaîner */ public Game remObserver(GObserver o) { obs.remove(o); return this; } /** * Bascule l'état de pause du jeu. ** Si le jeu était en pause, il est relancé et les threads en attente sont notifiés. *
* * @return true si le jeu est maintenant en pause */ public synchronized boolean togglePause() { if (isPaused) notifyAll(); isPaused = !isPaused; return isPaused; } public void notifyObservers() { for (GObserver o : obs) { boolean isSuccess = o.apply(); if (!isSuccess) { System.err.println("Une erreur s'est produite pendant le jeu."); System.exit(1); } } } /** * Exécute un cycle du jeu ** Chaque voiture effectue son action, puis les observateurs sont notifiés. * La boucle attend si le jeu est en pause. *
* * @throws InterruptedException si le thread est interrompu pendant wait() */ private void step() throws InterruptedException { for (Car car : cars) { synchronized(this) { while (isPaused) wait(); } car.run(); notifyObservers(); } } /** * Boucle principale du jeu. ** Tant que le jeu n'est pas terminé, on exécute les étapes et on met à jour * les vues toutes les 'time' millisecondes. *
*/ public void run() { while (!isFinish()) { try { step(); Thread.sleep(time); } catch (InterruptedException e) { e.printStackTrace(); } } } public ArrayList