diff --git a/src/Car.java b/src/Car.java
new file mode 100644
index 0000000..1ac630f
--- /dev/null
+++ b/src/Car.java
@@ -0,0 +1,112 @@
+import java.util.Random;
+
+/**
+ * Car représente une voiture qui avance sur un circuit en boucles.
+ * Chaque appel à {@link #makeMove()} avance la voiture d'une position.
+ * Quand la position atteint la fin de la boucle, un nouveau tour est compté.
+ */
+public class Car implements GObserver
+{
+ /** Ajout de la classe Random (Evite de le recreer a chaque fois) */
+ private Random rand = new Random();
+
+ /** Position actuelle dans la boucle (entre 0 et loop inclus) */
+ private int pos = 0;
+
+ /** Nombre de tours complétés */
+ private int round = 0;
+
+ /** Nombre total de cases dans une boucle (doit être > 0) */
+ private final int loop;
+ private final State state;
+ /** Nombre de fuel restant */
+ private int fuel = 60;
+
+ /**
+ * Construit une nouvelle voiture.
+ *
+ * @param loop nombre de positions par boucle (doit être > 0)
+ * @throws IllegalArgumentException si {@code loop <= 0}
+ */
+ public Car(int loop, State state)
+ {
+ this.state = state;
+
+ if (loop <= 0)
+ throw new IllegalArgumentException("loop must be > 0!");
+ this.loop = loop;
+ }
+
+ /**
+ * Fait avancer la voiture d'une position.
+ *
Si la position atteint la fin de la boucle, un nouveau tour est compté.
+ * + * @return cette même instance (pour chaînage fluide) + */ + public Car makeMove(int move) + { + pos += move; + if (pos == loop) + { + round++; + pos = 0; + } + return this; + } + + /** + * @return la position actuelle dans la boucle + */ + public int getPosition() + { + return pos; + } + + /** + * @return le score, calculé comme (nombre de tours + progression du tour) × 100 + */ + public int getScore() + { + return (int) ((round + (float) pos / loop) * 100); + } + + /** + * @return le nombre de tours complétés + */ + public int getRound() + { + return round; + } + + /** + * @return la taille de la boucle (nombre de positions) + */ + public int getLoop() + { + return loop; + } + + public int getFuel() + { + return fuel; + } + + public Car consumeFuel() + { + fuel -= state.getConsumption(); + return this; + } + + @Override + public boolean apply() + { + if (this.fuel > 0) + { + int[] interval = state.getInterval(); + int random = rand.nextInt(interval[0], interval[1]); + makeMove(random).consumeFuel(); + } + + return true; + } +} \ No newline at end of file diff --git a/src/Circuit.java b/src/Circuit.java new file mode 100644 index 0000000..8f52aee --- /dev/null +++ b/src/Circuit.java @@ -0,0 +1,138 @@ +/** + * Représente une cellule du circuit. + *+ * 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). + *
+ */ +public class Circuit +{ + /** + *Cell 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 à l’indice 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 d’arrivée.
+ *
+ * @return vrai si la cellule représente la fin du circuit
+ */
+ public boolean isFinish()
+ {
+ return type == Cell.FINISH;
+ }
+}
\ No newline at end of file
diff --git a/src/CircuitCell.java b/src/CircuitCell.java
deleted file mode 100644
index cf4918f..0000000
--- a/src/CircuitCell.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/**
- * CircuitCell est un enum
- * représentant les différents types de
- * cases qui composent le circuit de
- * course.
- */
-public enum CircuitCell {
- /**
- * 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;
-}
\ No newline at end of file
diff --git a/src/GObserver.java b/src/GObserver.java
new file mode 100644
index 0000000..cb2e4f6
--- /dev/null
+++ b/src/GObserver.java
@@ -0,0 +1,13 @@
+@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();
+}
\ No newline at end of file
diff --git a/src/Game.java b/src/Game.java
new file mode 100644
index 0000000..c5ef574
--- /dev/null
+++ b/src/Game.java
@@ -0,0 +1,131 @@
+import java.util.ArrayList;
+
+public class Game
+{
+ private boolean paused;
+ private Car[] cars;
+ private Map map;
+
+ private ArrayList Map représente le circuit de course.
Cette classe contient:
+ *START et FINISHMap
+ */
+ public static Map
+ */
+ public static Map fromInts(Integer[][] map)
+ {
+ return create((i) -> switch (i) {
+ case 0 -> new Circuit(Circuit.Cell.EMPTY);
+ case -1 -> new Circuit(Circuit.Cell.ROAD);
+ case -2 -> new Circuit(Circuit.Cell.START);
+ case -3 -> new Circuit(Circuit.Cell.FINISH);
+ default -> new Circuit(Circuit.Cell.YROAD, i);
+ }, map);
+ }
+
+ /**
+ * Crée une map à partir d'un tableau de caractères.
+ * Map
+ */
+ public static Map fromChars(Character[][] map)
+ {
+ return create((i) -> switch (i) {
+ case '#' -> new Circuit(Circuit.Cell.ROAD);
+ case 'S' -> new Circuit(Circuit.Cell.START);
+ case 'F' -> new Circuit(Circuit.Cell.FINISH);
+ case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
+ -> new Circuit(Circuit.Cell.YROAD, i - '0');
+ default -> new Circuit(Circuit.Cell.EMPTY);
+ }, map);
+ }
+
+ /**
+ * Constructeur privé utilisé par les méthodes statiques de création.
+ * Initialise la map et construit le chemin.
+ * Si la map est invalide ou impossible à résoudre, termine le programme.
+ *
+ * @param map Tableau 2D de Circuit
+ */
+ private Map(Circuit[][] map)
+ {
+ this.map = map;
+ boolean isPossible = this.buildPath();
+
+ if (!isPossible)
+ {
+ System.err.println("La map contient des doublons ou est impossible à finir!");
+ System.exit(1);
+ }
+ }
+
+ /**
+ * Construit le chemin entre START et FINISH.
+ *
+ * @return true si un chemin valide existe, false sinon
+ */
+ private boolean buildPath()
+ {
+ Point[] p = bindPath();
+
+ if (p == null)
+ return false;
+
+ Point start = p[0];
+ Point end = p[1];
+
+ this.pathMap = new ArrayList<>();
+ return followPath(start, end);
+ }
+
+ /**
+ * Cherche les points START et FINISH sur la map.
+ *
+ * @return Un tableau de 2 éléments : {START, FINISH} ou null si la map est invalide
+ */
+ private Point[] bindPath()
+ {
+ Point start = null;
+ Point end = null;
+
+ for (int i = 0; i < map.length; i++)
+ {
+ for (int j = 0; j < map[0].length; j++)
+ {
+ switch (map[i][j].getType())
+ {
+ case Circuit.Cell.START:
+ if (start == null) start = new Point(j, i);
+ else return null;
+ break;
+ case Circuit.Cell.FINISH:
+ if (end == null) end = new Point(j, i);
+ else return null;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ if (start == null || end == null) return null;
+ return new Point[] {start, end};
+ }
+
+ /**
+ * Suivi du chemin depuis START jusqu'à FINISH.
+ * Parcours les cases ROAD et YROAD jusqu'à atteindre FINISH.
+ *
+ * @param start Point de départ
+ * @param end Point d'arrivée
+ * @return true si un chemin complet a été trouvé, false sinon
+ */
+ private boolean followPath(Point start, Point end)
+ {
+ // remettre à 0 la liste
+ pathMap.clear();
+
+ // positions
+ Point current = start;
+ Point previous = null;
+
+ int[][] coord = {
+ {1, 0}, // haut
+ {-1, 0}, // bas
+ {0, -1}, // gauche
+ {0, 1} // droite
+ };
+
+ // sécurité pour éviter les boucles infinie
+ int step = 0;
+ int max = map.length * map[0].length;
+ for (; step < max; step++)
+ {
+ pathMap.add(current);
+
+ if (current.equals(end))
+ return true;
+
+ boolean moved = false;
+
+ for (int[] pos : coord)
+ {
+ int x = current.x + pos[1];
+ int y = current.y + pos[0];
+
+ if ((x >= 0 && map[0].length > x) && (y >= 0 && map.length > y))
+ {
+ Point next = new Point(x, y);
+
+ if (next.equals(previous))
+ continue;
+
+ Circuit element = getElement(x, y);
+ Circuit cElement = getElement(current.x, current.y);
+ if (element.isRoad() || (element.isFinish() && cElement.isRoad()))
+ {
+ previous = current;
+ current = next;
+ moved = true;
+ break;
+ }
+ }
+ }
+
+ // Si il est bloqué
+ if (!moved) break;
+ }
+
+ return false;
+ }
+
+ /**
+ * Retourne l'objet Circuit à la position (x, y).
+ *
+ * @param x Coordonnée X
+ * @param y Coordonnée Y
+ * @return L'objet Circuit
+ */
+ public Circuit getElement(int x, int y)
+ {
+ return map[y][x];
+ }
+
+ /**
+ * Retourne le type de cellule (Circuit.Cell) à la position (x, y).
+ *
+ * @param x Coordonnée X
+ * @param y Coordonnée Y
+ * @return Le type de cellule Circuit.Cell
+ */
+ public Circuit.Cell getCell(int x, int y)
+ {
+ return getElement(x, y).getType();
+ }
+
+ /**
+ * Retourne le point du chemin à l'indice donné.
+ *
+ * @param index Indice dans le chemin
+ * @return Point correspondant
+ */
+ public Point getPath(int i)
+ {
+ return this.pathMap.get(i);
+ }
+
+ /**
+ * Retourne la taille du chemin trouvé.
+ *
+ * @return Nombre de points dans le chemin
+ */
+ public int getPathSize()
+ {
+ return this.pathMap.size();
+ }
+}
diff --git a/src/State.java b/src/State.java
new file mode 100644
index 0000000..148d39a
--- /dev/null
+++ b/src/State.java
@@ -0,0 +1,39 @@
+public class State
+{
+ public static enum DriveMode
+ {
+//