Compare commits
2 Commits
makefile_c
...
023aa9d419
| Author | SHA1 | Date | |
|---|---|---|---|
| 023aa9d419 | |||
| 2cf929e024 |
3
Diagrammes/Diagramme - Avalam.svg
Normal file
3
Diagrammes/Diagramme - Avalam.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 128 KiB |
3
Diagrammes/Diagramme - Bot.svg
Normal file
3
Diagrammes/Diagramme - Bot.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 22 KiB |
3
Diagrammes/Diagramme - GameAPI.svg
Normal file
3
Diagrammes/Diagramme - GameAPI.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 40 KiB |
@@ -3,6 +3,28 @@ title: Avalam - Diagramme de classes (complet)
|
|||||||
---
|
---
|
||||||
classDiagram
|
classDiagram
|
||||||
|
|
||||||
|
class ArenaGame{
|
||||||
|
+ArenaGame(IBoard board, AbstractGamePlayer bot1, AbstractGamePlayer bot2)
|
||||||
|
-createPlayerMap(AbstractGamePlayer bot1, AbstractGamePlayer bot2): EnumMap<Player, AbstractGamePlayer>
|
||||||
|
}
|
||||||
|
|
||||||
|
class ArenaWindow{
|
||||||
|
-resultsTable: JTable
|
||||||
|
-tableModel: DefaultTableModel
|
||||||
|
-results: List<string>
|
||||||
|
|
||||||
|
+ArenaWindows()
|
||||||
|
-createConfigPanel(): JPanel
|
||||||
|
-createResultsTable()
|
||||||
|
-showConfigDialog()
|
||||||
|
-runArena(String bot1Type, String bot2Type, int depth, int nbParties)
|
||||||
|
-createBot(String botType, Player player, int depth): AbstractGamePlayer
|
||||||
|
-getWinnerName(Result result, String bot1Type, String bot2Type): String
|
||||||
|
}
|
||||||
|
|
||||||
|
ArenaWindow *-- AvalamBoard
|
||||||
|
ArenaWindow *-- ArenaGame
|
||||||
|
|
||||||
class AvalamBoard{
|
class AvalamBoard{
|
||||||
+SIZE: int
|
+SIZE: int
|
||||||
-MAX_HEIGHT: int
|
-MAX_HEIGHT: int
|
||||||
@@ -43,8 +65,6 @@ classDiagram
|
|||||||
+toString(): String
|
+toString(): String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class AvalamWindow{
|
class AvalamWindow{
|
||||||
-board : AvalamBoard
|
-board : AvalamBoard
|
||||||
-scoreView : ScoreView
|
-scoreView : ScoreView
|
||||||
@@ -70,14 +90,19 @@ classDiagram
|
|||||||
AvalamWindow *-- BoardView
|
AvalamWindow *-- BoardView
|
||||||
AvalamWindow *-- ScoreView
|
AvalamWindow *-- ScoreView
|
||||||
AvalamWindow *-- TurnView
|
AvalamWindow *-- TurnView
|
||||||
|
AvalamWindow *-- EndGameDialog
|
||||||
AvalamWindow --> GameMode
|
AvalamWindow --> GameMode
|
||||||
|
|
||||||
|
class BackgroundLayer{
|
||||||
|
-img: Image
|
||||||
|
+BackgroundLayer(String resourcePath)
|
||||||
|
#paintComponent(Graphics g): void
|
||||||
|
}
|
||||||
|
|
||||||
class BoardLoader{
|
class BoardLoader{
|
||||||
+loadFromFile(String resourcePath): Tower[][]
|
+loadFromFile(String resourcePath): Tower[][]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class BoardView{
|
class BoardView{
|
||||||
-board: AvalamBoard
|
-board: AvalamBoard
|
||||||
-backgroundLayer: BackgroundLayer
|
-backgroundLayer: BackgroundLayer
|
||||||
@@ -105,14 +130,6 @@ classDiagram
|
|||||||
BoardView *-- InteractionController
|
BoardView *-- InteractionController
|
||||||
BoardView --> AvalamBoard
|
BoardView --> AvalamBoard
|
||||||
|
|
||||||
class BackgroundLayer{
|
|
||||||
-img: Image
|
|
||||||
+BackgroundLayer(String resourcePath)
|
|
||||||
#paintComponent(Graphics g): void
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Color{
|
class Color{
|
||||||
-YELLOW(int r, int g, int b)
|
-YELLOW(int r, int g, int b)
|
||||||
-RED(int r, int g, int b)
|
-RED(int r, int g, int b)
|
||||||
@@ -122,11 +139,17 @@ classDiagram
|
|||||||
+toPlayer(): fr.iut_fbleau.GameAPI.Player
|
+toPlayer(): fr.iut_fbleau.GameAPI.Player
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class EndGameDialog{
|
||||||
|
+EndGameDialog(JFrame parent, Result result, int scoreJaune, int scoreRouge, GameMode mode, int depth, Runnable onReplay, Runnable onMenu, Runnable onQuit)
|
||||||
|
-modeToString(GameMode mode, int depth): String
|
||||||
|
}
|
||||||
|
|
||||||
class GameMode{
|
class GameMode{
|
||||||
PVP
|
PVP
|
||||||
PVBOT
|
PVBOT
|
||||||
PVALPHA
|
PVALPHA
|
||||||
PVGOD
|
PVGOD
|
||||||
|
ARENA
|
||||||
}
|
}
|
||||||
|
|
||||||
class HighlightLayer{
|
class HighlightLayer{
|
||||||
@@ -165,6 +188,7 @@ classDiagram
|
|||||||
|
|
||||||
Main ..> AvalamWindow
|
Main ..> AvalamWindow
|
||||||
Main ..> GameMode
|
Main ..> GameMode
|
||||||
|
Main ..> ArenaWindow
|
||||||
|
|
||||||
class PieceButton{
|
class PieceButton{
|
||||||
-color: java.awt.Color
|
-color: java.awt.Color
|
||||||
|
|||||||
@@ -17,7 +17,16 @@ classDiagram
|
|||||||
}
|
}
|
||||||
|
|
||||||
class DivineBot{
|
class DivineBot{
|
||||||
|
-me: Player
|
||||||
|
-maxDepth: int
|
||||||
|
-rng: Random
|
||||||
|
|
||||||
|
+DivineBot(Player p, int maxDepth)
|
||||||
|
+giveYourMove(IBoard board): AbstractPly
|
||||||
|
-alphaBeta(IBoard board, int depth, int alpha, int beta): int
|
||||||
|
-terminalValue(IBoard board): int
|
||||||
|
-evaluate(IBoard board): int
|
||||||
|
-listMoves(IBoard board): List<AbstractPly>
|
||||||
}
|
}
|
||||||
|
|
||||||
class IdiotBot{
|
class IdiotBot{
|
||||||
|
|||||||
@@ -192,135 +192,64 @@ public class ArenaWindow extends JFrame {
|
|||||||
* @param nbParties nombre de parties à jouer
|
* @param nbParties nombre de parties à jouer
|
||||||
*/
|
*/
|
||||||
private void runArena(String bot1Type, String bot2Type, int depth, int nbParties) {
|
private void runArena(String bot1Type, String bot2Type, int depth, int nbParties) {
|
||||||
|
// Créer les bots
|
||||||
|
AbstractGamePlayer bot1 = createBot(bot1Type, Player.PLAYER1, depth);
|
||||||
|
AbstractGamePlayer bot2 = createBot(bot2Type, Player.PLAYER2, depth);
|
||||||
|
|
||||||
|
if (bot1 == null || bot2 == null) {
|
||||||
|
JOptionPane.showMessageDialog(this, "Erreur lors de la création des bots.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Vider le tableau
|
// Vider le tableau
|
||||||
tableModel.setRowCount(0);
|
tableModel.setRowCount(0);
|
||||||
results.clear();
|
results.clear();
|
||||||
|
|
||||||
// Créer un dialogue de progression
|
// Charger le plateau initial
|
||||||
JDialog progressDialog = new JDialog(this, "Parties en cours...", true);
|
Tower[][] initialGrid = BoardLoader.loadFromFile("fr/iut_fbleau/Res/Plateau.txt");
|
||||||
JLabel progressLabel = new JLabel("Préparation des parties...", JLabel.CENTER);
|
|
||||||
progressLabel.setBorder(BorderFactory.createEmptyBorder(20, 40, 20, 40));
|
|
||||||
progressDialog.add(progressLabel);
|
|
||||||
progressDialog.setSize(300, 100);
|
|
||||||
progressDialog.setLocationRelativeTo(this);
|
|
||||||
progressDialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
|
|
||||||
|
|
||||||
// Exécuter les parties dans un thread séparé pour ne pas bloquer l'interface
|
// Lancer les parties
|
||||||
Thread arenaThread = new Thread(() -> {
|
for (int i = 1; i <= nbParties; i++) {
|
||||||
SwingUtilities.invokeLater(() -> progressDialog.setVisible(true));
|
AvalamBoard board = new AvalamBoard(initialGrid, Player.PLAYER1);
|
||||||
|
ArenaGame game = new ArenaGame(board, bot1, bot2);
|
||||||
|
|
||||||
// Statistiques pour déboguer
|
try {
|
||||||
int bot1Wins = 0;
|
Result result = game.run();
|
||||||
int bot2Wins = 0;
|
String winner = getWinnerName(result, bot1Type, bot2Type);
|
||||||
int draws = 0;
|
|
||||||
int errors = 0;
|
|
||||||
|
|
||||||
for (int i = 1; i <= nbParties; i++) {
|
// Ajouter au tableau
|
||||||
final int partieNum = i;
|
tableModel.addRow(new Object[]{
|
||||||
SwingUtilities.invokeLater(() -> {
|
"Partie " + i,
|
||||||
progressLabel.setText("Partie " + partieNum + " / " + nbParties + " en cours...");
|
bot1Type,
|
||||||
|
bot2Type,
|
||||||
|
winner
|
||||||
|
});
|
||||||
|
} catch (Exception e) {
|
||||||
|
tableModel.addRow(new Object[]{
|
||||||
|
"Partie " + i,
|
||||||
|
bot1Type,
|
||||||
|
bot2Type,
|
||||||
|
"Erreur: " + e.getMessage()
|
||||||
});
|
});
|
||||||
|
|
||||||
// Recréer les bots à chaque partie pour garantir l'indépendance complète
|
|
||||||
// (notamment pour réinitialiser les générateurs aléatoires)
|
|
||||||
AbstractGamePlayer bot1 = createBot(bot1Type, Player.PLAYER1, depth);
|
|
||||||
AbstractGamePlayer bot2 = createBot(bot2Type, Player.PLAYER2, depth);
|
|
||||||
|
|
||||||
if (bot1 == null || bot2 == null) {
|
|
||||||
errors++;
|
|
||||||
SwingUtilities.invokeLater(() -> {
|
|
||||||
tableModel.addRow(new Object[]{
|
|
||||||
"Partie " + partieNum,
|
|
||||||
bot1Type,
|
|
||||||
bot2Type,
|
|
||||||
"Erreur: Impossible de créer les bots"
|
|
||||||
});
|
|
||||||
});
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Recharger le plateau à chaque partie pour garantir l'indépendance complète
|
|
||||||
Tower[][] initialGrid = BoardLoader.loadFromFile("fr/iut_fbleau/Res/Plateau.txt");
|
|
||||||
AvalamBoard board = new AvalamBoard(initialGrid, Player.PLAYER1);
|
|
||||||
ArenaGame game = new ArenaGame(board, bot1, bot2);
|
|
||||||
|
|
||||||
try {
|
|
||||||
Result result = game.run();
|
|
||||||
String winner = getWinnerName(result, bot1Type, bot2Type);
|
|
||||||
|
|
||||||
// Mettre à jour les statistiques
|
|
||||||
if (result == Result.WIN) {
|
|
||||||
bot1Wins++;
|
|
||||||
} else if (result == Result.LOSS) {
|
|
||||||
bot2Wins++;
|
|
||||||
} else if (result == Result.DRAW) {
|
|
||||||
draws++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ajouter au tableau dans le thread EDT
|
|
||||||
SwingUtilities.invokeLater(() -> {
|
|
||||||
tableModel.addRow(new Object[]{
|
|
||||||
"Partie " + partieNum,
|
|
||||||
bot1Type,
|
|
||||||
bot2Type,
|
|
||||||
winner
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} catch (Exception e) {
|
|
||||||
errors++;
|
|
||||||
SwingUtilities.invokeLater(() -> {
|
|
||||||
tableModel.addRow(new Object[]{
|
|
||||||
"Partie " + partieNum,
|
|
||||||
bot1Type,
|
|
||||||
bot2Type,
|
|
||||||
"Erreur: " + e.getMessage()
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Afficher les statistiques finales
|
// Afficher un message de fin avec possibilité de quitter directement
|
||||||
final int finalBot1Wins = bot1Wins;
|
Object[] options = {"OK", "Quitter le jeu"};
|
||||||
final int finalBot2Wins = bot2Wins;
|
int choice = JOptionPane.showOptionDialog(
|
||||||
final int finalDraws = draws;
|
this,
|
||||||
final int finalErrors = errors;
|
"Toutes les parties sont terminées !",
|
||||||
|
"Arène terminée",
|
||||||
|
JOptionPane.DEFAULT_OPTION,
|
||||||
|
JOptionPane.INFORMATION_MESSAGE,
|
||||||
|
null,
|
||||||
|
options,
|
||||||
|
options[0]
|
||||||
|
);
|
||||||
|
|
||||||
// Fermer le dialogue et afficher le message de fin avec statistiques
|
if (choice == 1) {
|
||||||
SwingUtilities.invokeLater(() -> {
|
System.exit(0);
|
||||||
progressDialog.dispose();
|
}
|
||||||
|
|
||||||
String statsMessage = String.format(
|
|
||||||
"Toutes les parties sont terminées !\n\n" +
|
|
||||||
"Statistiques :\n" +
|
|
||||||
"- %s (Bot 1) : %d victoires\n" +
|
|
||||||
"- %s (Bot 2) : %d victoires\n" +
|
|
||||||
"- Matchs nuls : %d\n" +
|
|
||||||
"- Erreurs : %d",
|
|
||||||
bot1Type, finalBot1Wins,
|
|
||||||
bot2Type, finalBot2Wins,
|
|
||||||
finalDraws,
|
|
||||||
finalErrors
|
|
||||||
);
|
|
||||||
|
|
||||||
Object[] options = {"OK", "Quitter le jeu"};
|
|
||||||
int choice = JOptionPane.showOptionDialog(
|
|
||||||
this,
|
|
||||||
statsMessage,
|
|
||||||
"Arène terminée",
|
|
||||||
JOptionPane.DEFAULT_OPTION,
|
|
||||||
JOptionPane.INFORMATION_MESSAGE,
|
|
||||||
null,
|
|
||||||
options,
|
|
||||||
options[0]
|
|
||||||
);
|
|
||||||
|
|
||||||
if (choice == 1) {
|
|
||||||
System.exit(0);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
arenaThread.start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -51,16 +51,9 @@ public class AvalamBoard extends AbstractBoard {
|
|||||||
super(startingPlayer, new ArrayDeque<>());
|
super(startingPlayer, new ArrayDeque<>());
|
||||||
this.grid = new Tower[SIZE][SIZE];
|
this.grid = new Tower[SIZE][SIZE];
|
||||||
|
|
||||||
// Copie profonde : créer de nouvelles tours pour éviter que toutes les parties partagent les mêmes objets
|
|
||||||
for (int r = 0; r < SIZE; r++)
|
for (int r = 0; r < SIZE; r++)
|
||||||
for (int c = 0; c < SIZE; c++) {
|
for (int c = 0; c < SIZE; c++)
|
||||||
Tower t = initialGrid[r][c];
|
this.grid[r][c] = initialGrid[r][c];
|
||||||
if (t == null) {
|
|
||||||
this.grid[r][c] = null;
|
|
||||||
} else {
|
|
||||||
this.grid[r][c] = new Tower(t.getHeight(), t.getColor());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -233,6 +233,7 @@ public class AvalamWindow extends JFrame {
|
|||||||
} else if (mode == GameMode.PVALPHA) {
|
} else if (mode == GameMode.PVALPHA) {
|
||||||
botMove = alphaBot.giveYourMove(board.safeCopy());
|
botMove = alphaBot.giveYourMove(board.safeCopy());
|
||||||
} else {
|
} else {
|
||||||
|
// A FAIRE PLUS TARD (PVGOD)
|
||||||
botMove = divineBot.giveYourMove(board.safeCopy());
|
botMove = divineBot.giveYourMove(board.safeCopy());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -105,38 +105,22 @@ public class DivineBot extends AbstractGamePlayer {
|
|||||||
|
|
||||||
boolean isMax = board.getCurrentPlayer() == me;
|
boolean isMax = board.getCurrentPlayer() == me;
|
||||||
|
|
||||||
List<AbstractPly> moves = listMoves(board);
|
for (AbstractPly m : listMoves(board)) {
|
||||||
if (moves.isEmpty()) {
|
IBoard next = board.safeCopy();
|
||||||
return evaluate(board);
|
next.doPly(m);
|
||||||
}
|
|
||||||
|
|
||||||
if (isMax) {
|
int val = alphaBeta(next, depth - 1, alpha, beta);
|
||||||
int best = Integer.MIN_VALUE;
|
|
||||||
for (AbstractPly m : moves) {
|
|
||||||
IBoard next = board.safeCopy();
|
|
||||||
next.doPly(m);
|
|
||||||
|
|
||||||
int val = alphaBeta(next, depth - 1, alpha, beta);
|
|
||||||
best = Math.max(best, val);
|
|
||||||
alpha = Math.max(alpha, best);
|
|
||||||
|
|
||||||
|
if (isMax) {
|
||||||
|
alpha = Math.max(alpha, val);
|
||||||
if (alpha >= beta) break; // Coupure Beta
|
if (alpha >= beta) break; // Coupure Beta
|
||||||
}
|
} else {
|
||||||
return best;
|
beta = Math.min(beta, val);
|
||||||
} else {
|
|
||||||
int best = Integer.MAX_VALUE;
|
|
||||||
for (AbstractPly m : moves) {
|
|
||||||
IBoard next = board.safeCopy();
|
|
||||||
next.doPly(m);
|
|
||||||
|
|
||||||
int val = alphaBeta(next, depth - 1, alpha, beta);
|
|
||||||
best = Math.min(best, val);
|
|
||||||
beta = Math.min(beta, best);
|
|
||||||
|
|
||||||
if (alpha >= beta) break; // Coupure Alpha
|
if (alpha >= beta) break; // Coupure Alpha
|
||||||
}
|
}
|
||||||
return best;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return isMax ? alpha : beta;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user