From 25c3e8dbd752691490285b1ebd8989e616cb88c6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Lo=C3=AFc=20GUEZO?=
Date: Fri, 19 Dec 2025 16:18:40 +0100
Subject: [PATCH] feat: ajout Menu selection
---
src/Main.java | 11 +-
src/model/Game.java | 6 +-
src/model/car/BasicCar.java | 109 +++++++++---------
src/model/car/Car.java | 15 ++-
src/model/car/CarDecorator.java | 5 +
src/model/car/DrunkCar.java | 9 +-
src/model/car/Selection.java | 80 +++++++++++++
.../{Dashboard.java => DashboardView.java} | 4 +-
src/visual/GameView.java | 3 +-
.../{Rankboard.java => RankboardView.java} | 4 +-
src/visual/SelectionView.java | 84 ++++++++++++++
src/visual/{Track.java => TrackView.java} | 4 +-
12 files changed, 254 insertions(+), 80 deletions(-)
create mode 100644 src/model/car/Selection.java
rename src/visual/{Dashboard.java => DashboardView.java} (97%)
rename src/visual/{Rankboard.java => RankboardView.java} (94%)
create mode 100644 src/visual/SelectionView.java
rename src/visual/{Track.java => TrackView.java} (97%)
diff --git a/src/Main.java b/src/Main.java
index d041a04..fbd376f 100644
--- a/src/Main.java
+++ b/src/Main.java
@@ -5,6 +5,7 @@ import model.car.BasicCar;
import model.car.DrunkCar;
import model.car.HybridCar;
import model.map.Map;
+import visual.SelectionView;
public class Main {
public static void main(String[] args) throws InterruptedException {
@@ -21,14 +22,12 @@ public class Main {
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
});
- Game game = new Game.Builder()
- .car(new HybridCar(new BasicCar("Luwik", Color.RED)))
- .car(new DrunkCar(new BasicCar("Charazade", Color.PINK)))
+ SelectionView game = new SelectionView(3);
+
+ game.getGameBuilder()
.track("Piste Formule 1", 1000, 500, 1, 1)
.rankboard("Score", 200, 200, 0, 510)
.dashboards(300, 200, 1000, 0)
- .map(map)
- .build();
- game.run();
+ .map(map);
}
}
\ No newline at end of file
diff --git a/src/model/Game.java b/src/model/Game.java
index fd3f262..789c240 100644
--- a/src/model/Game.java
+++ b/src/model/Game.java
@@ -39,19 +39,19 @@ public class Game {
public Builder rankboard(String title, int width,
int height, int x, int y) {
- this.OBSERVERS.add(new Rankboard(null, title, width, height, x, y));
+ this.OBSERVERS.add(new RankboardView(null, title, width, height, x, y));
return this;
}
public Builder track(String title, int width,
int height, int x, int y) {
- this.OBSERVERS.add(new Track(null, title, width, height, x, y));
+ this.OBSERVERS.add(new TrackView(null, title, width, height, x, y));
return this;
}
public Builder dashboard(Car car, String title, int width,
int height, int x, int y) {
- this.OBSERVERS.add(new Dashboard(null, car, title, width, height, x, y));
+ this.OBSERVERS.add(new DashboardView(null, car, title, width, height, x, y));
return this;
}
diff --git a/src/model/car/BasicCar.java b/src/model/car/BasicCar.java
index f763059..51218b2 100644
--- a/src/model/car/BasicCar.java
+++ b/src/model/car/BasicCar.java
@@ -122,7 +122,7 @@ public class BasicCar implements Car {
state = next;
return "";
}
-
+
/**
* Fait avancer la voiture d'un certain nombre de positions.
*
@@ -130,73 +130,78 @@ public class BasicCar implements Car {
* incrémenté et
* la position revient à zéro.
*
- *
- * @param move nombre de positions à avancer
- * @return cette même instance (pour chaînage fluide)
- */
- private void move() {
- int jump = RANDOM.nextInt(state.MIN, state.MAX);
-
- for (int i = 0; i < jump; i++) {
- pos = state.move(pos, movement);
-
- Point point = map.getPath(pos);
- Circuit element = map.getElement(point.x, point.y);
-
- if (hasAccident(element, jump)) {
- setDamage();
- return;
+ *
+ * @param move nombre de positions à avancer
+ * @return cette même instance (pour chaînage fluide)
+ */
+ private void move() {
+ int jump = RANDOM.nextInt(state.MIN, state.MAX);
+
+ for (int i = 0; i < jump; i++) {
+ pos = state.move(pos, movement);
+
+ Point point = map.getPath(pos);
+ Circuit element = map.getElement(point.x, point.y);
+
+ if (hasAccident(element, jump)) {
+ setDamage();
+ return;
}
round = pos / map.getPathSize();
}
}
-
+
private boolean hasAccident(Circuit element, int jump) {
return element.isYRoad() && element.getValue() <= jump;
}
-
+
/**
* 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é
- }
+ *
+ * @return cette même instance pour chaînage
+ */
+ public void consumeFuel() {
+ fuel = state.fuelConsumption(fuel);
+ if (fuel < 0)
+ fuel = 0; // sécurité
+}
- public boolean hasFinished() {
- return 3 < round;
- }
+public boolean hasFinished() {
+ return 3 < round;
+}
- /**
- * Exécute une "étape" de la voiture : avance d'une position aléatoire et
- * consomme du carburant.
- *
- * La progression est déterminée par un intervalle aléatoire fourni par l'état
- * du jeu.
- *
- */
- @Override
- public boolean apply() {
- if (state.isDamaged()) {
- decreaseDamage();
- } else if (fuel > 0) {
- move();
- if (isConsuming)
- consumeFuel();
- }
- return !hasFinished();
+/**
+ * Exécute une "étape" de la voiture : avance d'une position aléatoire et
+ * consomme du carburant.
+ *
+ * La progression est déterminée par un intervalle aléatoire fourni par l'état
+ * du jeu.
+ *
+*/
+@Override
+public boolean apply() {
+ if (state.isDamaged()) {
+ decreaseDamage();
+ } else if (fuel > 0) {
+ move();
+ if (isConsuming)
+ consumeFuel();
}
+ return !hasFinished();
+}
+
+@Override
+public void consumption(boolean active) {
+ isConsuming = active;
+}
@Override
- public void consumption(boolean active) {
- isConsuming = active;
+ public Car remove() {
+ return this;
}
- @Override
- public void reverse(boolean active) {
+@Override
+public void reverse(boolean active) {
movement = (active) ? -1 : 1;
}
diff --git a/src/model/car/Car.java b/src/model/car/Car.java
index 45af97d..cae6aac 100644
--- a/src/model/car/Car.java
+++ b/src/model/car/Car.java
@@ -13,18 +13,21 @@ public interface Car extends Observer {
public void reverse(boolean active);
public void consumption(boolean active);
-
+
+ public Car remove();
+
public String getName();
-
+
public int getPosition();
-
+
public int getScore();
-
+
public int getRound();
-
+
public int getFuel();
-
+
public State getState();
+
public Color getColor();
public void setMap(Map map);
diff --git a/src/model/car/CarDecorator.java b/src/model/car/CarDecorator.java
index 0ed8b92..49cbfc4 100644
--- a/src/model/car/CarDecorator.java
+++ b/src/model/car/CarDecorator.java
@@ -11,6 +11,11 @@ public abstract class CarDecorator implements Car {
this.car = car;
}
+ @Override
+ public Car remove() {
+ return car;
+ }
+
@Override
public String accelerate() {
return car.accelerate();
diff --git a/src/model/car/DrunkCar.java b/src/model/car/DrunkCar.java
index b2cba16..0d984cc 100644
--- a/src/model/car/DrunkCar.java
+++ b/src/model/car/DrunkCar.java
@@ -1,7 +1,5 @@
package model.car;
-import java.util.Random;
-
/**
* DrunkCar = décorateur "pilote ivre".
*
@@ -14,8 +12,7 @@ import java.util.Random;
* sans modifier la classe Car.
*/
public class DrunkCar extends CarDecorator {
- /** Générateur de nombres aléatoires pour simuler la progression */
- protected static final Random RANDOM = new Random();
+ private boolean reverse = false;
public DrunkCar(Car car) {
super(car);
@@ -25,9 +22,9 @@ public class DrunkCar extends CarDecorator {
// 50% : fait l'inverse
@Override
public boolean apply() {
- car.reverse(RANDOM.nextBoolean());
+ car.reverse(reverse);
car.apply();
- car.reverse(false);
+ reverse = !reverse;
return true;
}
}
\ No newline at end of file
diff --git a/src/model/car/Selection.java b/src/model/car/Selection.java
new file mode 100644
index 0000000..78e1401
--- /dev/null
+++ b/src/model/car/Selection.java
@@ -0,0 +1,80 @@
+package model.car;
+
+import java.awt.Color;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Function;
+
+import model.Game;
+
+public class Selection {
+ private final Game.Builder gameBuilder;
+ private final List cars = new ArrayList<>();
+
+ public Selection(Game.Builder gameBuilder) {
+ this.gameBuilder = gameBuilder;
+ }
+
+ public List getCars() {
+ return new ArrayList<>(cars);
+ }
+
+ public Car addCar(String name, Color color) {
+ Car car = new BasicCar(name, color);
+ cars.add(car);
+ return car;
+ }
+
+ public void removeCar(Car car) {
+ cars.remove(car);
+ }
+
+ private Car addDecorator(Function fn, Car car) throws IllegalArgumentException {
+ int index = cars.indexOf(car);
+
+ if (index < 0) {
+ throw new IllegalArgumentException(
+ "Aucune voiture dans la classe interne.");
+ }
+
+ car = fn.apply(car);
+ cars.set(index, car);
+ return car;
+ }
+
+ public Car addHybridCarDecorator(Car car) throws IllegalArgumentException {
+ return addDecorator(HybridCar::new, car);
+ }
+
+ public Car addDrunkCarDecorator(Car car) throws IllegalArgumentException {
+ return addDecorator(DrunkCar::new, car);
+ }
+
+ public Car addBoostCarDecorator(Car car) throws IllegalArgumentException {
+ return addDecorator(BoostCar::new, car);
+ }
+
+ public Car removeDecorator(Car car) throws IllegalArgumentException {
+ int index = cars.indexOf(car);
+
+ if (index < 0) {
+ throw new IllegalArgumentException(
+ "Aucune voiture dans la classe interne.");
+ }
+ car = car.remove();
+ cars.set(index, car);
+ return car;
+ }
+
+ public Game.Builder select() {
+ for (Car car : cars) {
+ gameBuilder.car(car);
+ System.out.println("hello world");
+ }
+ return gameBuilder;
+ }
+
+ public int size() {
+ return cars.size();
+ }
+}
diff --git a/src/visual/Dashboard.java b/src/visual/DashboardView.java
similarity index 97%
rename from src/visual/Dashboard.java
rename to src/visual/DashboardView.java
index abce8e8..6a7aec1 100644
--- a/src/visual/Dashboard.java
+++ b/src/visual/DashboardView.java
@@ -24,7 +24,7 @@ import model.car.HybridCar;
* - un bouton Accelerer
* - un bouton Rallentir
*/
-public class Dashboard extends GameView {
+public class DashboardView extends GameView {
/** Label affichant carburant et nombre de tours */
private final JLabel infoLabel = new JLabel();
@@ -58,7 +58,7 @@ public class Dashboard extends GameView {
* @param x position horizontale de la fenêtre
* @param y position verticale de la fenêtre
*/
- public Dashboard(Game game, Car car, String title, int width, int height, int x, int y) {
+ public DashboardView(Game game, Car car, String title, int width, int height, int x, int y) {
super(game, "Dashboard: " + title, width, height, x, y);
this.car = car;
diff --git a/src/visual/GameView.java b/src/visual/GameView.java
index c07f2b3..5e60f31 100644
--- a/src/visual/GameView.java
+++ b/src/visual/GameView.java
@@ -66,7 +66,8 @@ public abstract class GameView extends JComponent implements Game.Observer {
// mettre un layout (la disposition des elements de la fenetre)
frame.setLayout(new BorderLayout());
- game.addObserver(this);
+ if (game != null)
+ game.addObserver(this);
}
protected GameView(Game game, String title, int width, int height, int x, int y) {
diff --git a/src/visual/Rankboard.java b/src/visual/RankboardView.java
similarity index 94%
rename from src/visual/Rankboard.java
rename to src/visual/RankboardView.java
index 6839e8c..ab7a426 100644
--- a/src/visual/Rankboard.java
+++ b/src/visual/RankboardView.java
@@ -18,7 +18,7 @@ import model.car.Car;
* Les scores sont triés du plus grand au plus petit.
*
*/
-public class Rankboard extends GameView {
+public class RankboardView extends GameView {
/** Liste des voitures à afficher */
List cars;
@@ -43,7 +43,7 @@ public class Rankboard extends GameView {
* @param x Position horizontale de la fenêtre
* @param y Position verticale de la fenêtre
*/
- public Rankboard(Game game, String title, int width, int height, int x, int y) {
+ public RankboardView(Game game, String title, int width, int height, int x, int y) {
super(game, title, width, height, x, y);
if (game != null)
init(game);
diff --git a/src/visual/SelectionView.java b/src/visual/SelectionView.java
new file mode 100644
index 0000000..8b3b88c
--- /dev/null
+++ b/src/visual/SelectionView.java
@@ -0,0 +1,84 @@
+package visual;
+
+import java.awt.*;
+import java.awt.event.ActionEvent;
+
+import javax.swing.JButton;
+import javax.swing.JPanel;
+
+import model.Game;
+import model.car.Car;
+import model.car.Selection;
+
+public class SelectionView extends GameView {
+ private Game.Builder gameBuilder = new Game.Builder();
+ private Selection selection = new Selection(gameBuilder);
+ private JPanel buttonPanel = new JPanel();
+
+ public Game.Builder getGameBuilder() {
+ return gameBuilder;
+ }
+
+ public SelectionView(int ncar) {
+ super(null, "Menu de sélection", 500, 300, 400, 400);
+ init(null); // forcer le init
+
+ buttonPanel.setLayout(new GridLayout(0, 3, 5, 5));
+ frame.add(buttonPanel, BorderLayout.CENTER);
+
+ for (int i = 1; i <= ncar; i++) {
+ Car car = selection.addCar("Car " + i, Color.getHSBColor(i / 3f, 0.8f, 0.8f));
+ // bouton Hybrid
+ JButton hybridBtn = new JButton("Hybrid " + car.getName());
+ // bouton Drunk
+ JButton drunkBtn = new JButton("Drunk " + car.getName());
+ // bouton boost
+ JButton boostBtn = new JButton("Boost " + car.getName());
+
+ final int I = i;
+ hybridBtn.addActionListener((ActionEvent e) -> {
+ try {
+ Car current = selection.getCars().get(I-1);
+ selection.addHybridCarDecorator(current);
+ hybridBtn.setEnabled(false);
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ });
+
+ drunkBtn.addActionListener((ActionEvent e) -> {
+ try {
+ Car current = selection.getCars().get(I-1);
+ selection.addDrunkCarDecorator(current);
+ drunkBtn.setEnabled(false);
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ });
+
+ boostBtn.addActionListener((ActionEvent e) -> {
+ try {
+ Car current = selection.getCars().get(I-1);
+ selection.addBoostCarDecorator(current);
+ boostBtn.setEnabled(false);
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ });
+
+ buttonPanel.add(hybridBtn);
+ buttonPanel.add(drunkBtn);
+ buttonPanel.add(boostBtn);
+ }
+
+ JButton startBtn = new JButton("Start");
+ startBtn.addActionListener((ActionEvent e) -> {
+ frame.dispose();
+ new Thread(() -> selection.select().build().run()).start();
+ });
+
+ this.frame.add(startBtn, BorderLayout.SOUTH);
+ frame.revalidate();
+ frame.repaint();
+ }
+}
diff --git a/src/visual/Track.java b/src/visual/TrackView.java
similarity index 97%
rename from src/visual/Track.java
rename to src/visual/TrackView.java
index 4fbf2ae..3638520 100644
--- a/src/visual/Track.java
+++ b/src/visual/TrackView.java
@@ -23,7 +23,7 @@ import model.map.Map;
* est dessinée selon son type. Les voitures sont superposées sur la grille.
*
*/
-public class Track extends GameView {
+public class TrackView extends GameView {
/** La carte du circuit */
private Map map;
/** Liste des voitures à dessiner */
@@ -49,7 +49,7 @@ public class Track extends GameView {
* @param x Position X de la fenêtre
* @param y Position Y de la fenêtre
*/
- public Track(Game game, String title, int width, int height, int x, int y) {
+ public TrackView(Game game, String title, int width, int height, int x, int y) {
super(game, title, width, height, x, y);
if (game != null)
init(game);