Files
BUT3ProjetJeuGroupe/fr/iut_fbleau/Avalam/ArenaWindow.java
2026-02-05 20:50:23 +01:00

364 lines
13 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package fr.iut_fbleau.Avalam;
import fr.iut_fbleau.Bot.AlphaBetaBot;
import fr.iut_fbleau.Bot.DivineBot;
import fr.iut_fbleau.Bot.IdiotBot;
import fr.iut_fbleau.GameAPI.AbstractGamePlayer;
import fr.iut_fbleau.GameAPI.Player;
import fr.iut_fbleau.GameAPI.Result;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
/**
* Fenêtre pour le mode Arène (bots vs bots).
*
* Elle permet :
* - de sélectionner deux bots parmi Idiot, Alpha-Beta et Divin ;
* - de configurer la profondeur de recherche pour les bots intelligents ;
* - de choisir le nombre de parties à jouer ;
* - dafficher, dans un tableau, le résultat de chaque partie (gagnant ou erreur) ;
* - de revenir au menu principal ou de quitter entièrement le jeu.
*/
public class ArenaWindow extends JFrame {
/** Tableau affichant les résultats des parties. */
private JTable resultsTable;
/** Modèle de données pour le tableau des résultats. */
private DefaultTableModel tableModel;
/** Liste des résultats des parties (non utilisée actuellement). */
private List<String> results;
/**
* Construit la fenêtre Arène.
*/
public ArenaWindow() {
super("Arène - Bot vs Bot");
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setLayout(new BorderLayout());
results = new ArrayList<>();
// Panneau de configuration
JPanel configPanel = createConfigPanel();
add(configPanel, BorderLayout.NORTH);
// Tableau des résultats
createResultsTable();
JScrollPane scrollPane = new JScrollPane(resultsTable);
add(scrollPane, BorderLayout.CENTER);
// Panneau des boutons
JPanel buttonPanel = new JPanel(new FlowLayout());
JButton startButton = new JButton("Lancer les parties");
startButton.addActionListener(e -> showConfigDialog());
buttonPanel.add(startButton);
JButton backButton = new JButton("Retour au menu");
backButton.addActionListener(e -> {
dispose(); // Ferme la fenêtre Arène
Main.showModeSelection(); // Affiche le menu principal
});
buttonPanel.add(backButton);
// Nouveau bouton pour quitter entièrement le jeu
JButton quitButton = new JButton("Quitter");
quitButton.addActionListener(e -> System.exit(0));
buttonPanel.add(quitButton);
add(buttonPanel, BorderLayout.SOUTH);
pack();
setSize(600, 400);
setLocationRelativeTo(null);
setVisible(true);
}
/**
* Crée le panneau de configuration (pour l'instant vide, sera rempli par le dialogue).
*
* @return un JPanel contenant les informations de configuration
*/
private JPanel createConfigPanel() {
JPanel panel = new JPanel();
panel.setBorder(BorderFactory.createTitledBorder("Configuration"));
panel.add(new JLabel("Utilisez le bouton 'Lancer les parties' pour configurer et démarrer."));
return panel;
}
/**
* Crée le tableau des résultats avec les colonnes : Partie, Bot 1, Bot 2, Gagnant.
*/
private void createResultsTable() {
String[] columnNames = {"Partie", "Bot 1", "Bot 2", "Gagnant"};
tableModel = new DefaultTableModel(columnNames, 0) {
@Override
public boolean isCellEditable(int row, int column) {
return false;
}
};
resultsTable = new JTable(tableModel);
resultsTable.setFillsViewportHeight(true);
}
/**
* Affiche le dialogue de configuration et lance les parties.
*/
private void showConfigDialog() {
// Choix du bot 1
String[] botTypes = {"Bot Idiot", "Bot Alpha-Beta", "Bot Divin"};
String bot1Choice = (String) JOptionPane.showInputDialog(
this,
"Choisissez le Bot 1 (Joueur 1) :",
"Configuration Arène - Bot 1",
JOptionPane.QUESTION_MESSAGE,
null,
botTypes,
botTypes[0]
);
if (bot1Choice == null) return;
// Choix du bot 2
String bot2Choice = (String) JOptionPane.showInputDialog(
this,
"Choisissez le Bot 2 (Joueur 2) :",
"Configuration Arène - Bot 2",
JOptionPane.QUESTION_MESSAGE,
null,
botTypes,
botTypes[0]
);
if (bot2Choice == null) return;
// Profondeur pour Alpha-Beta et Divin
int depth = 4;
if (bot1Choice.contains("Alpha") || bot1Choice.contains("Divin") ||
bot2Choice.contains("Alpha") || bot2Choice.contains("Divin")) {
String depthStr = JOptionPane.showInputDialog(
this,
"Profondeur de recherche pour les bots Alpha-Beta/Divin ?\n(Conseil: 4)",
"Profondeur",
JOptionPane.QUESTION_MESSAGE
);
if (depthStr != null) {
try {
depth = Integer.parseInt(depthStr.trim());
if (depth < 1) depth = 1;
} catch (Exception e) {
depth = 4;
}
}
}
// Nombre de parties
String nbPartiesStr = JOptionPane.showInputDialog(
this,
"Combien de parties voulez-vous jouer ?",
"Nombre de parties",
JOptionPane.QUESTION_MESSAGE
);
if (nbPartiesStr == null) return;
int nbParties;
try {
nbParties = Integer.parseInt(nbPartiesStr.trim());
if (nbParties < 1) {
JOptionPane.showMessageDialog(this, "Le nombre de parties doit être au moins 1.");
return;
}
} catch (Exception e) {
JOptionPane.showMessageDialog(this, "Nombre invalide.");
return;
}
// Lancer les parties
runArena(bot1Choice, bot2Choice, depth, nbParties);
}
/**
* Lance les parties entre les deux bots.
*
* @param bot1Type type du bot 1 (Joueur 1)
* @param bot2Type type du bot 2 (Joueur 2)
* @param depth profondeur de recherche pour les bots Alpha-Beta/Divin
* @param nbParties nombre de parties à jouer
*/
private void runArena(String bot1Type, String bot2Type, int depth, int nbParties) {
// Vider le tableau
tableModel.setRowCount(0);
results.clear();
// Créer un dialogue de progression
JDialog progressDialog = new JDialog(this, "Parties en cours...", true);
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
Thread arenaThread = new Thread(() -> {
SwingUtilities.invokeLater(() -> progressDialog.setVisible(true));
// Statistiques pour déboguer
int bot1Wins = 0;
int bot2Wins = 0;
int draws = 0;
int errors = 0;
for (int i = 1; i <= nbParties; i++) {
final int partieNum = i;
SwingUtilities.invokeLater(() -> {
progressLabel.setText("Partie " + partieNum + " / " + nbParties + " en cours...");
});
// 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
final int finalBot1Wins = bot1Wins;
final int finalBot2Wins = bot2Wins;
final int finalDraws = draws;
final int finalErrors = errors;
// Fermer le dialogue et afficher le message de fin avec statistiques
SwingUtilities.invokeLater(() -> {
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();
}
/**
* Crée un bot selon son type.
*
* @param botType type de bot ("Bot Idiot", "Bot Alpha-Beta", "Bot Divin")
* @param player joueur contrôlé par ce bot (PLAYER1 ou PLAYER2)
* @param depth profondeur de recherche pour Alpha-Beta/Divin
* @return une instance de AbstractGamePlayer correspondant au type, ou null si le type est invalide
*/
private AbstractGamePlayer createBot(String botType, Player player, int depth) {
if (botType.equals("Bot Idiot")) {
return new IdiotBot(player);
} else if (botType.equals("Bot Alpha-Beta")) {
return new AlphaBetaBot(player, depth);
} else if (botType.equals("Bot Divin")) {
return new DivineBot(player, depth);
}
return null;
}
/**
* Détermine le nom du gagnant selon le résultat.
*
* @param result résultat de la partie (WIN, LOSS, ou DRAW du point de vue de PLAYER1)
* @param bot1Type nom du bot 1
* @param bot2Type nom du bot 2
* @return une chaîne indiquant le gagnant ou "Match nul"
*/
private String getWinnerName(Result result, String bot1Type, String bot2Type) {
if (result == Result.WIN) {
return bot1Type + " (Joueur 1)";
} else if (result == Result.LOSS) {
return bot2Type + " (Joueur 2)";
} else {
return "Match nul";
}
}
}