Derniere version du jeu
This commit is contained in:
@@ -1,28 +1,92 @@
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Représente une case individuelle sur le plateau du Démineur.
|
||||
* Elle contient son état (minée, révélée) et son marqueur (étoile, interrogation).
|
||||
*/
|
||||
public class Case implements Serializable {
|
||||
|
||||
/** Constante indiquant que la case n'a aucun marqueur. */
|
||||
public static final int MARQUEUR_VIDE = 0;
|
||||
|
||||
/** Constante indiquant que la case est marquée d'une étoile (mine supposée). */
|
||||
public static final int MARQUEUR_ETOILE = 1;
|
||||
|
||||
/** Constante indiquant que la case est marquée d'un point d'interrogation (doute). */
|
||||
public static final int MARQUEUR_INTERROGATION = 2;
|
||||
|
||||
/** Constante définissant le nombre total d'états de marqueurs possibles. */
|
||||
private static final int NOMBRE_ETATS_MARQUEUR = 3;
|
||||
|
||||
/** Indique si la case contient une mine (true) ou non (false). */
|
||||
private boolean minee;
|
||||
|
||||
/** Indique si la case a été cliquée et révélée au joueur. */
|
||||
private boolean revelee;
|
||||
|
||||
/** Stocke l'état actuel du marqueur posé par le joueur (clic droit). */
|
||||
private int marqueur;
|
||||
|
||||
/** Stocke le nombre de mines présentes dans les 8 cases adjacentes. */
|
||||
private int nbMinesVoisines;
|
||||
|
||||
/**
|
||||
* Constructeur par défaut d'une Case.
|
||||
* Initialise une case vide, cachée et sans marqueur.
|
||||
*/
|
||||
public Case() {
|
||||
this.minee = false;
|
||||
this.revelee = false;
|
||||
this.marqueur = 0;
|
||||
this.marqueur = MARQUEUR_VIDE;
|
||||
this.nbMinesVoisines = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si la case contient une mine.
|
||||
* @return true si minée, false sinon.
|
||||
*/
|
||||
public boolean isMinee() { return this.minee; }
|
||||
|
||||
/**
|
||||
* Vérifie si la case est révélée.
|
||||
* @return true si révélée, false sinon.
|
||||
*/
|
||||
public boolean isRevelee() { return this.revelee; }
|
||||
|
||||
/**
|
||||
* Récupère le marqueur actuel de la case.
|
||||
* @return l'entier correspondant au type de marqueur.
|
||||
*/
|
||||
public int getMarqueur() { return this.marqueur; }
|
||||
|
||||
/**
|
||||
* Récupère le nombre de mines autour de cette case.
|
||||
* @return le nombre de mines voisines.
|
||||
*/
|
||||
public int getNbMinesVoisines() { return this.nbMinesVoisines; }
|
||||
|
||||
public void setMinee(boolean m) { this.minee = m; }
|
||||
public void setRevelee(boolean r) { this.revelee = r; }
|
||||
public void setNbMinesVoisines(int n) { this.nbMinesVoisines = n; }
|
||||
/**
|
||||
* Définit si la case doit contenir une mine ou non.
|
||||
* @param estMinee true pour placer une mine, false pour l'enlever.
|
||||
*/
|
||||
public void setMinee(boolean estMinee) { this.minee = estMinee; }
|
||||
|
||||
/**
|
||||
* Modifie l'état de révélation de la case.
|
||||
* @param estRevelee true pour révéler la case, false pour la cacher.
|
||||
*/
|
||||
public void setRevelee(boolean estRevelee) { this.revelee = estRevelee; }
|
||||
|
||||
/**
|
||||
* Enregistre le nombre de mines calculé autour de cette case.
|
||||
* @param nombre le nombre de mines voisines (de 0 à 8).
|
||||
*/
|
||||
public void setNbMinesVoisines(int nombre) { this.nbMinesVoisines = nombre; }
|
||||
|
||||
/**
|
||||
* Alterne le marqueur de la case dans l'ordre : Vide -> Étoile -> Interrogation -> Vide.
|
||||
*/
|
||||
public void changerMarqueur() {
|
||||
this.marqueur = (this.marqueur + 1) % 3;
|
||||
this.marqueur = (this.marqueur + 1) % NOMBRE_ETATS_MARQUEUR;
|
||||
}
|
||||
}
|
||||
|
||||
+111
-42
@@ -2,61 +2,130 @@ import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import javax.swing.JOptionPane;
|
||||
|
||||
/**
|
||||
* Observateur gérant les interactions de la souris sur la grille de jeu.
|
||||
*/
|
||||
public class ControleurGrille implements MouseListener {
|
||||
|
||||
/** Constante pour le bouton gauche de la souris (Capture 26). */
|
||||
private static final int BOUTON_GAUCHE = MouseEvent.BUTTON1;
|
||||
|
||||
/** Constante pour le bouton droit de la souris (Capture 26). */
|
||||
private static final int BOUTON_DROIT = MouseEvent.BUTTON3;
|
||||
|
||||
/** Message affiché en cas de défaite. */
|
||||
private static final String MESSAGE_DEFAITE = "BOUM ! Vous avez sauté sur une mine !";
|
||||
|
||||
/** Message affiché en cas de victoire. */
|
||||
private static final String MESSAGE_VICTOIRE = "Félicitations ! Vous avez trouvé toutes les mines !";
|
||||
|
||||
/** Référence à la fenêtre affichant la grille. */
|
||||
private FenetreJeu fenetre;
|
||||
|
||||
/** Référence au modèle contenant la logique du plateau. */
|
||||
private Grille grille;
|
||||
|
||||
public ControleurGrille(FenetreJeu f, Grille g) {
|
||||
this.fenetre = f;
|
||||
this.grille = g;
|
||||
/**
|
||||
* Constructeur de l'écouteur de la grille.
|
||||
* @param fenetreJeu la fenêtre contenant les boutons.
|
||||
* @param grilleJeu la grille contenant les données.
|
||||
*/
|
||||
public ControleurGrille(FenetreJeu fenetreJeu, Grille grilleJeu) {
|
||||
this.fenetre = fenetreJeu;
|
||||
this.grille = grilleJeu;
|
||||
}
|
||||
|
||||
/**
|
||||
* Méthode appelée lors d'un clic sur n'importe quel bouton de la grille.
|
||||
* @param evenement les informations du clic souris.
|
||||
*/
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
if (this.grille.isPartieTerminee()) return;
|
||||
public void mouseClicked(MouseEvent evenement) {
|
||||
if (this.grille.isPartieTerminee()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < grille.getLignes(); i++) {
|
||||
for (int j = 0; j < grille.getColonnes(); j++) {
|
||||
|
||||
if (e.getSource() == fenetre.getBouton(i, j)) {
|
||||
Case caseCliquee = grille.getCase(i, j);
|
||||
|
||||
if (caseCliquee.isRevelee()) return;
|
||||
|
||||
if (e.getButton() == MouseEvent.BUTTON1) {
|
||||
if (caseCliquee.getMarqueur() != 1) {
|
||||
boolean aExplose = grille.revelerCase(i, j);
|
||||
if (aExplose) {
|
||||
grille.setPartieTerminee(true);
|
||||
fenetre.afficherDefaite(i, j);
|
||||
JOptionPane.showMessageDialog(fenetre, "BOUM ! Vous avez sauté sur une mine !");
|
||||
// NOUVEAU : On ne quitte plus de force, on change juste le bouton
|
||||
fenetre.changerBoutonEnRetourMenu();
|
||||
} else {
|
||||
fenetre.rafraichirTouteLaGrille();
|
||||
if (grille.estGagnee()) {
|
||||
grille.setPartieTerminee(true);
|
||||
JOptionPane.showMessageDialog(fenetre, "Félicitations ! Vous avez trouvé toutes les mines !");
|
||||
// NOUVEAU : Idem pour la victoire
|
||||
fenetre.changerBoutonEnRetourMenu();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (e.getButton() == MouseEvent.BUTTON3) {
|
||||
caseCliquee.changerMarqueur();
|
||||
fenetre.rafraichirCase(i, j);
|
||||
fenetre.mettreAJourCompteur();
|
||||
}
|
||||
for (int ligne = 0; ligne < grille.getLignes(); ligne++) {
|
||||
for (int colonne = 0; colonne < grille.getColonnes(); colonne++) {
|
||||
if (evenement.getSource() == fenetre.getBouton(ligne, colonne)) {
|
||||
traiterClicSurCase(evenement, ligne, colonne);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void mousePressed(MouseEvent e) {}
|
||||
public void mouseReleased(MouseEvent e) {}
|
||||
public void mouseEntered(MouseEvent e) {}
|
||||
public void mouseExited(MouseEvent e) {}
|
||||
/**
|
||||
* Identifie le type de clic (gauche ou droit) et appelle la méthode correspondante.
|
||||
* @param evenement l'action de la souris.
|
||||
* @param ligne la ligne de la case cliquée.
|
||||
* @param colonne la colonne de la case cliquée.
|
||||
*/
|
||||
private void traiterClicSurCase(MouseEvent evenement, int ligne, int colonne) {
|
||||
Case caseCliquee = grille.getCase(ligne, colonne);
|
||||
if (caseCliquee.isRevelee()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (evenement.getButton() == BOUTON_GAUCHE) {
|
||||
gererClicGauche(caseCliquee, ligne, colonne);
|
||||
} else if (evenement.getButton() == BOUTON_DROIT) {
|
||||
gererClicDroit(caseCliquee, ligne, colonne);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tente de révéler une case et gère l'éventuelle explosion.
|
||||
* @param caseCliquee la case logique ciblée.
|
||||
* @param ligne index de ligne.
|
||||
* @param colonne index de colonne.
|
||||
*/
|
||||
private void gererClicGauche(Case caseCliquee, int ligne, int colonne) {
|
||||
if (caseCliquee.getMarqueur() == Case.MARQUEUR_ETOILE) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean aExplose = grille.revelerCase(ligne, colonne);
|
||||
if (aExplose) {
|
||||
grille.setPartieTerminee(true);
|
||||
fenetre.afficherDefaite(ligne, colonne);
|
||||
JOptionPane.showMessageDialog(fenetre, MESSAGE_DEFAITE);
|
||||
fenetre.changerBoutonEnRetourMenu();
|
||||
} else {
|
||||
fenetre.rafraichirTouteLaGrille();
|
||||
verifierVictoire();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Teste si toutes les cases saines ont été révélées et annonce la victoire.
|
||||
*/
|
||||
private void verifierVictoire() {
|
||||
if (grille.estGagnee()) {
|
||||
grille.setPartieTerminee(true);
|
||||
JOptionPane.showMessageDialog(fenetre, MESSAGE_VICTOIRE);
|
||||
fenetre.changerBoutonEnRetourMenu();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pose, change ou retire un marqueur sur la case ciblée.
|
||||
* @param caseCliquee la case logique ciblée.
|
||||
* @param ligne index de ligne.
|
||||
* @param colonne index de colonne.
|
||||
*/
|
||||
private void gererClicDroit(Case caseCliquee, int ligne, int colonne) {
|
||||
caseCliquee.changerMarqueur();
|
||||
fenetre.rafraichirCase(ligne, colonne);
|
||||
fenetre.mettreAJourCompteur();
|
||||
}
|
||||
|
||||
/** @param evenement l'événement souris. */
|
||||
public void mousePressed(MouseEvent evenement) {}
|
||||
/** @param evenement l'événement souris. */
|
||||
public void mouseReleased(MouseEvent evenement) {}
|
||||
/** @param evenement l'événement souris. */
|
||||
public void mouseEntered(MouseEvent evenement) {}
|
||||
/** @param evenement l'événement souris. */
|
||||
public void mouseExited(MouseEvent evenement) {}
|
||||
}
|
||||
|
||||
+56
-12
@@ -1,26 +1,70 @@
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.IOException;
|
||||
import javax.swing.JOptionPane;
|
||||
|
||||
/**
|
||||
* Observateur gérant le bouton situé en bas de la fenêtre de jeu.
|
||||
*/
|
||||
public class ControleurJeu implements ActionListener {
|
||||
|
||||
/** Constante définissant le nom du fichier de sauvegarde. */
|
||||
private static final String NOM_FICHIER_SAUVEGARDE = "sauvegarde.dat";
|
||||
|
||||
/** Constante définissant le code de sortie normal de l'application. */
|
||||
private static final int CODE_SORTIE_NORMALE = 0;
|
||||
|
||||
/** Référence à la fenêtre de jeu actuellement ouverte. */
|
||||
private FenetreJeu fenetre;
|
||||
|
||||
public ControleurJeu(FenetreJeu f) {
|
||||
this.fenetre = f;
|
||||
/**
|
||||
* Constructeur de l'écouteur du bouton de jeu.
|
||||
* @param fenetreJeu la fenêtre à observer.
|
||||
*/
|
||||
public ControleurJeu(FenetreJeu fenetreJeu) {
|
||||
this.fenetre = fenetreJeu;
|
||||
}
|
||||
|
||||
/**
|
||||
* Agit selon l'état de la partie : retourne au menu ou sauvegarde la progression.
|
||||
* @param evenement le clic sur le bouton.
|
||||
*/
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
// Si la partie est finie, le bouton sert à retourner au menu
|
||||
public void actionPerformed(ActionEvent evenement) {
|
||||
if (fenetre.getGrille().isPartieTerminee()) {
|
||||
this.fenetre.dispose();
|
||||
MenuPrincipal nouveauMenu = new MenuPrincipal();
|
||||
nouveauMenu.setVisible(true);
|
||||
}
|
||||
// Sinon (partie en cours), c'est bien le bouton "Sauver et Quitter"
|
||||
else {
|
||||
System.out.println("Sauvegarde de la partie en cours... (Bientôt implémenté)");
|
||||
System.exit(0);
|
||||
retournerAuMenu();
|
||||
} else {
|
||||
sauvegarderEtQuitter();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ferme la partie et rouvre une nouvelle instance du menu principal.
|
||||
*/
|
||||
private void retournerAuMenu() {
|
||||
this.fenetre.dispose();
|
||||
MenuPrincipal nouveauMenu = new MenuPrincipal();
|
||||
nouveauMenu.setVisible(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Grave la grille en mémoire dans un fichier et ferme l'application.
|
||||
*/
|
||||
private void sauvegarderEtQuitter() {
|
||||
try {
|
||||
FileOutputStream fluxSortie = new FileOutputStream(NOM_FICHIER_SAUVEGARDE);
|
||||
ObjectOutputStream graveurObjet = new ObjectOutputStream(fluxSortie);
|
||||
|
||||
graveurObjet.writeObject(fenetre.getGrille());
|
||||
|
||||
graveurObjet.close();
|
||||
fluxSortie.close();
|
||||
System.exit(CODE_SORTIE_NORMALE);
|
||||
|
||||
} catch (IOException exception) {
|
||||
JOptionPane.showMessageDialog(fenetre, "Erreur lors de la sauvegarde !");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+121
-36
@@ -1,50 +1,135 @@
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import javax.swing.JOptionPane;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Observateur gérant les interactions avec les boutons du menu principal.
|
||||
*/
|
||||
public class ControleurMenu implements ActionListener {
|
||||
|
||||
|
||||
/** Constante définissant la valeur de retour en cas d'annulation ou d'erreur de saisie. */
|
||||
private static final int ERREUR_SAISIE = -1;
|
||||
|
||||
/** Constante définissant le nombre minimum de lignes ou colonnes. */
|
||||
private static final int DIMENSION_MIN = 4;
|
||||
|
||||
/** Constante définissant le nombre maximum de lignes ou colonnes. */
|
||||
private static final int DIMENSION_MAX = 30;
|
||||
|
||||
/** Référence vers la fenêtre du menu. */
|
||||
private MenuPrincipal menu;
|
||||
|
||||
|
||||
public ControleurMenu(MenuPrincipal m) {
|
||||
this.menu = m;
|
||||
/**
|
||||
* Constructeur de l'écouteur du menu.
|
||||
* @param menuPrincipal la fenêtre du menu principal.
|
||||
*/
|
||||
public ControleurMenu(MenuPrincipal menuPrincipal) {
|
||||
this.menu = menuPrincipal;
|
||||
}
|
||||
|
||||
@Override
|
||||
/**
|
||||
* Déclenchée lors d'un clic sur l'un des boutons du menu.
|
||||
* @param evenement l'action générée par le clic.
|
||||
*/
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent evenement) {
|
||||
if (evenement.getSource() == this.menu.getBtnNouvellePartie()) {
|
||||
try {
|
||||
String strL = JOptionPane.showInputDialog(menu, "Nombre de lignes (entre 4 et 30) :");
|
||||
if (strL == null) return;
|
||||
int l = Integer.parseInt(strL);
|
||||
|
||||
String strC = JOptionPane.showInputDialog(menu, "Nombre de colonnes (entre 4 et 30) :");
|
||||
if (strC == null) return;
|
||||
int c = Integer.parseInt(strC);
|
||||
|
||||
String strM = JOptionPane.showInputDialog(menu, "Nombre total de mines :");
|
||||
if (strM == null) return;
|
||||
int m = Integer.parseInt(strM);
|
||||
|
||||
if (l < 4 || l > 30 || c < 4 || c > 30 || m >= (l * c)) {
|
||||
JOptionPane.showMessageDialog(menu, "Valeurs incorrectes ! Les dimensions doivent être entre 4 et 30, et les mines inférieures au nombre de cases.");
|
||||
return;
|
||||
}
|
||||
|
||||
Grille nouvelleGrille = new Grille(l, c, m);
|
||||
FenetreJeu fenetre = new FenetreJeu(nouvelleGrille);
|
||||
fenetre.setVisible(true);
|
||||
this.menu.dispose();
|
||||
|
||||
} catch (NumberFormatException ex) {
|
||||
JOptionPane.showMessageDialog(menu, "Erreur : Vous devez entrer des nombres entiers !");
|
||||
}
|
||||
|
||||
} else if (evenement.getSource() == this.menu.getBtnReprendre()) {
|
||||
System.out.println("Chargement de la sauvegarde...");
|
||||
} else if (evenement.getSource() == this.menu.getBtnQuitter()) {
|
||||
if (evenement.getSource() == this.menu.getBoutonNouvellePartie()) {
|
||||
lancerNouvellePartie();
|
||||
} else if (evenement.getSource() == this.menu.getBoutonReprendre()) {
|
||||
chargerPartieSauvegardee();
|
||||
} else if (evenement.getSource() == this.menu.getBoutonQuitter()) {
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Demande les dimensions et génère une nouvelle partie si les saisies sont valides.
|
||||
*/
|
||||
private void lancerNouvellePartie() {
|
||||
try {
|
||||
int nbLignes = demanderValeur("Nombre de lignes (entre 4 et 30) :");
|
||||
if (nbLignes == ERREUR_SAISIE) return;
|
||||
|
||||
int nbColonnes = demanderValeur("Nombre de colonnes (entre 4 et 30) :");
|
||||
if (nbColonnes == ERREUR_SAISIE) return;
|
||||
|
||||
int nbMines = demanderValeur("Nombre total de mines :");
|
||||
if (nbMines == ERREUR_SAISIE) return;
|
||||
|
||||
if (!sontDimensionsValides(nbLignes, nbColonnes, nbMines)) {
|
||||
JOptionPane.showMessageDialog(menu, "Valeurs incorrectes !");
|
||||
return;
|
||||
}
|
||||
|
||||
demarrerJeu(nbLignes, nbColonnes, nbMines);
|
||||
|
||||
} catch (NumberFormatException exception) {
|
||||
JOptionPane.showMessageDialog(menu, "Erreur : Vous devez entrer des nombres entiers !");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si les dimensions entrées par l'utilisateur respectent les limites.
|
||||
* @param lignes le nombre de lignes choisi.
|
||||
* @param colonnes le nombre de colonnes choisi.
|
||||
* @param mines le nombre de mines choisi.
|
||||
* @return true si tout est correct, false sinon.
|
||||
*/
|
||||
private boolean sontDimensionsValides(int lignes, int colonnes, int mines) {
|
||||
boolean lignesInvalides = lignes < DIMENSION_MIN || lignes > DIMENSION_MAX;
|
||||
boolean colonnesInvalides = colonnes < DIMENSION_MIN || colonnes > DIMENSION_MAX;
|
||||
boolean minesInvalides = mines >= (lignes * colonnes) || mines <= 0;
|
||||
|
||||
return !lignesInvalides && !colonnesInvalides && !minesInvalides;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise la fenêtre de jeu avec les paramètres validés et ferme le menu.
|
||||
* @param lignes le nombre de lignes.
|
||||
* @param colonnes le nombre de colonnes.
|
||||
* @param mines le nombre de mines.
|
||||
*/
|
||||
private void demarrerJeu(int lignes, int colonnes, int mines) {
|
||||
Grille nouvelleGrille = new Grille(lignes, colonnes, mines);
|
||||
FenetreJeu fenetre = new FenetreJeu(nouvelleGrille);
|
||||
fenetre.setVisible(true);
|
||||
this.menu.dispose();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ouvre une boîte de dialogue pour demander un entier à l'utilisateur.
|
||||
* @param message le texte à afficher.
|
||||
* @return le nombre entier saisi, ou ERREUR_SAISIE en cas d'annulation.
|
||||
*/
|
||||
private int demanderValeur(String message) {
|
||||
String saisie = JOptionPane.showInputDialog(menu, message);
|
||||
if (saisie == null || saisie.trim().isEmpty()) return ERREUR_SAISIE;
|
||||
return Integer.parseInt(saisie);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tente de lire le fichier de sauvegarde et restaure la partie si possible.
|
||||
*/
|
||||
private void chargerPartieSauvegardee() {
|
||||
try {
|
||||
FileInputStream fluxEntree = new FileInputStream("sauvegarde.dat");
|
||||
ObjectInputStream lecteurObjet = new ObjectInputStream(fluxEntree);
|
||||
|
||||
Grille grilleChargee = (Grille) lecteurObjet.readObject();
|
||||
|
||||
lecteurObjet.close();
|
||||
fluxEntree.close();
|
||||
|
||||
FenetreJeu fenetre = new FenetreJeu(grilleChargee);
|
||||
fenetre.rafraichirTouteLaGrille();
|
||||
fenetre.setVisible(true);
|
||||
this.menu.dispose();
|
||||
|
||||
} catch (IOException | ClassNotFoundException exception) {
|
||||
JOptionPane.showMessageDialog(menu, "Aucune sauvegarde trouvée ou fichier corrompu !");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+172
-62
@@ -1,112 +1,222 @@
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* Fenêtre affichant la partie en cours.
|
||||
* Gère l'affichage de la grille, du compteur de mines et du bouton de sauvegarde.
|
||||
*/
|
||||
public class FenetreJeu extends JFrame {
|
||||
|
||||
|
||||
/** Position X initiale de la fenêtre de jeu sur l'écran. */
|
||||
private static final int POSITION_X = 100;
|
||||
|
||||
/** Position Y initiale de la fenêtre de jeu sur l'écran. */
|
||||
private static final int POSITION_Y = 100;
|
||||
|
||||
/** Estimation de la taille en pixels d'une case pour la largeur de la fenêtre. */
|
||||
private static final int LARGEUR_CASE_PIXELS = 50;
|
||||
|
||||
/** Estimation de la taille en pixels d'une case pour la hauteur de la fenêtre. */
|
||||
private static final int HAUTEUR_CASE_PIXELS = 50;
|
||||
|
||||
/** Espace supplémentaire en hauteur pour afficher l'en-tête et le pied de page. */
|
||||
private static final int MARGE_HAUTEUR_PIXELS = 100;
|
||||
|
||||
/** Référence vers le modèle logique du jeu. */
|
||||
private Grille grille;
|
||||
|
||||
/** Tableau à deux dimensions stockant les composants graphiques des cases. */
|
||||
private JButton[][] boutons;
|
||||
|
||||
/** Étiquette textuelle affichant le nombre de mines restantes à trouver. */
|
||||
private JLabel labelCompteur;
|
||||
private JButton btnActionBas; // NOUVEAU : On garde le bouton en mémoire
|
||||
|
||||
/** Bouton dynamique en bas de la fenêtre (Sauvegarder ou Retour Menu). */
|
||||
private JButton boutonActionBas;
|
||||
|
||||
public FenetreJeu(Grille g) {
|
||||
/**
|
||||
* Constructeur de la fenêtre de jeu.
|
||||
* @param grilleJeu la grille logique initialisée à afficher.
|
||||
*/
|
||||
public FenetreJeu(Grille grilleJeu) {
|
||||
super("Démineur - Partie en cours");
|
||||
this.grille = g;
|
||||
this.boutons = new JButton[g.getLignes()][g.getColonnes()];
|
||||
this.grille = grilleJeu;
|
||||
this.boutons = new JButton[grilleJeu.getLignes()][grilleJeu.getColonnes()];
|
||||
|
||||
this.setSize(600, 600);
|
||||
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
this.setLayout(new BorderLayout());
|
||||
|
||||
int largeurFenetre = grilleJeu.getColonnes() * LARGEUR_CASE_PIXELS;
|
||||
int hauteurFenetre = (grilleJeu.getLignes() * HAUTEUR_CASE_PIXELS) + MARGE_HAUTEUR_PIXELS;
|
||||
|
||||
this.setSize(largeurFenetre, hauteurFenetre);
|
||||
this.setLocation(POSITION_X, POSITION_Y);
|
||||
|
||||
this.labelCompteur = new JLabel("Mines restantes : " + g.getMinesRestantes());
|
||||
this.labelCompteur.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
this.labelCompteur.setFont(new Font("Arial", Font.BOLD, 16));
|
||||
initialiserEntete();
|
||||
initialiserPanneauGrille();
|
||||
initialiserBoutonBas();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prépare et ajoute le compteur de mines en haut de la fenêtre.
|
||||
*/
|
||||
private void initialiserEntete() {
|
||||
this.labelCompteur = new JLabel("Mines restantes : " + this.grille.getMinesRestantes());
|
||||
this.labelCompteur.setHorizontalAlignment(JLabel.CENTER);
|
||||
this.add(this.labelCompteur, BorderLayout.NORTH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prépare et ajoute la zone centrale contenant tous les boutons cliquables.
|
||||
*/
|
||||
private void initialiserPanneauGrille() {
|
||||
JPanel panneauGrille = new JPanel();
|
||||
panneauGrille.setLayout(new GridLayout(g.getLignes(), g.getColonnes()));
|
||||
|
||||
panneauGrille.setLayout(new GridLayout(this.grille.getLignes(), this.grille.getColonnes()));
|
||||
ControleurGrille controleurSouris = new ControleurGrille(this, this.grille);
|
||||
|
||||
for (int i = 0; i < g.getLignes(); i++) {
|
||||
for (int j = 0; j < g.getColonnes(); j++) {
|
||||
for (int ligne = 0; ligne < this.grille.getLignes(); ligne++) {
|
||||
for (int colonne = 0; colonne < this.grille.getColonnes(); colonne++) {
|
||||
JButton boutonCase = new JButton("");
|
||||
this.boutons[i][j] = boutonCase;
|
||||
|
||||
this.boutons[ligne][colonne] = boutonCase;
|
||||
panneauGrille.add(boutonCase);
|
||||
boutonCase.addMouseListener(controleurSouris);
|
||||
}
|
||||
}
|
||||
this.add(panneauGrille, BorderLayout.CENTER);
|
||||
}
|
||||
|
||||
// --- MODIFICATION DU BOUTON DU BAS ---
|
||||
this.btnActionBas = new JButton("Sauver et Quitter");
|
||||
this.add(this.btnActionBas, BorderLayout.SOUTH);
|
||||
/**
|
||||
* Prépare et ajoute le bouton de contrôle général en bas de la fenêtre.
|
||||
*/
|
||||
private void initialiserBoutonBas() {
|
||||
this.boutonActionBas = new JButton("Sauver et Quitter");
|
||||
this.add(this.boutonActionBas, BorderLayout.SOUTH);
|
||||
ControleurJeu controleurQuitter = new ControleurJeu(this);
|
||||
this.btnActionBas.addActionListener(controleurQuitter);
|
||||
this.boutonActionBas.addActionListener(controleurQuitter);
|
||||
}
|
||||
|
||||
// --- NOUVEAUX OUTILS ---
|
||||
public JButton getBouton(int l, int c) { return this.boutons[l][c]; }
|
||||
public Grille getGrille() { return this.grille; } // Permet au contrôleur de lire la grille
|
||||
/**
|
||||
* Récupère un bouton graphique spécifique de la grille.
|
||||
* @param indexLigne la ligne du bouton.
|
||||
* @param indexColonne la colonne du bouton.
|
||||
* @return le bouton correspondant.
|
||||
*/
|
||||
public JButton getBouton(int indexLigne, int indexColonne) { return this.boutons[indexLigne][indexColonne]; }
|
||||
|
||||
/**
|
||||
* Accède à l'instance de la grille logique.
|
||||
* @return la grille du jeu.
|
||||
*/
|
||||
public Grille getGrille() { return this.grille; }
|
||||
|
||||
/**
|
||||
* Transforme le bouton de sauvegarde en bouton de retour au menu.
|
||||
*/
|
||||
public void changerBoutonEnRetourMenu() {
|
||||
this.btnActionBas.setText("Retour au Menu");
|
||||
this.boutonActionBas.setText("Retour au Menu");
|
||||
}
|
||||
|
||||
/**
|
||||
* Interroge la grille et rafraîchit le texte du compteur de mines.
|
||||
*/
|
||||
public void mettreAJourCompteur() {
|
||||
this.labelCompteur.setText("Mines restantes : " + this.grille.getMinesRestantes());
|
||||
}
|
||||
|
||||
public void rafraichirCase(int l, int c) {
|
||||
Case caseLogique = this.grille.getCase(l, c);
|
||||
JButton btn = this.boutons[l][c];
|
||||
/**
|
||||
* Met à jour l'apparence visuelle d'un bouton selon son état logique.
|
||||
* @param ligne la ligne du bouton à rafraîchir.
|
||||
* @param colonne la colonne du bouton à rafraîchir.
|
||||
*/
|
||||
public void rafraichirCase(int ligne, int colonne) {
|
||||
Case caseLogique = this.grille.getCase(ligne, colonne);
|
||||
JButton bouton = this.boutons[ligne][colonne];
|
||||
|
||||
if (caseLogique.isRevelee()) {
|
||||
btn.setEnabled(false);
|
||||
if (caseLogique.isMinee()) {
|
||||
btn.setText("M");
|
||||
btn.setBackground(Color.RED);
|
||||
} else if (caseLogique.getNbMinesVoisines() > 0) {
|
||||
btn.setText("" + caseLogique.getNbMinesVoisines());
|
||||
} else {
|
||||
btn.setText("");
|
||||
}
|
||||
appliquerStyleCaseRevelee(caseLogique, bouton);
|
||||
} else {
|
||||
if (caseLogique.getMarqueur() == 1) {
|
||||
btn.setText("★");
|
||||
} else if (caseLogique.getMarqueur() == 2) {
|
||||
btn.setText("?");
|
||||
} else {
|
||||
btn.setText("");
|
||||
}
|
||||
appliquerStyleCaseCachee(caseLogique, bouton);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Applique les couleurs et le texte d'une case qui vient d'être révélée.
|
||||
* @param caseLogique la donnée de la case.
|
||||
* @param bouton le composant graphique associé.
|
||||
*/
|
||||
private void appliquerStyleCaseRevelee(Case caseLogique, JButton bouton) {
|
||||
if (caseLogique.isMinee()) {
|
||||
bouton.setText("M");
|
||||
bouton.setBackground(Color.RED);
|
||||
} else if (caseLogique.getNbMinesVoisines() > 0) {
|
||||
bouton.setText("" + caseLogique.getNbMinesVoisines());
|
||||
bouton.setBackground(Color.WHITE);
|
||||
} else {
|
||||
bouton.setText("");
|
||||
bouton.setBackground(Color.LIGHT_GRAY);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Applique les symboles d'une case qui est encore masquée (marqueurs).
|
||||
* @param caseLogique la donnée de la case.
|
||||
* @param bouton le composant graphique associé.
|
||||
*/
|
||||
private void appliquerStyleCaseCachee(Case caseLogique, JButton bouton) {
|
||||
if (caseLogique.getMarqueur() == Case.MARQUEUR_ETOILE) {
|
||||
bouton.setText("*");
|
||||
} else if (caseLogique.getMarqueur() == Case.MARQUEUR_INTERROGATION) {
|
||||
bouton.setText("?");
|
||||
} else {
|
||||
bouton.setText("");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Force la mise à jour visuelle de toutes les cases de la grille.
|
||||
*/
|
||||
public void rafraichirTouteLaGrille() {
|
||||
for (int i = 0; i < grille.getLignes(); i++) {
|
||||
for (int j = 0; j < grille.getColonnes(); j++) {
|
||||
rafraichirCase(i, j);
|
||||
for (int ligne = 0; ligne < grille.getLignes(); ligne++) {
|
||||
for (int colonne = 0; colonne < grille.getColonnes(); colonne++) {
|
||||
rafraichirCase(ligne, colonne);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void afficherDefaite(int lExplose, int cExplose) {
|
||||
for (int i = 0; i < grille.getLignes(); i++) {
|
||||
for (int j = 0; j < grille.getColonnes(); j++) {
|
||||
Case c = grille.getCase(i, j);
|
||||
JButton btn = boutons[i][j];
|
||||
btn.setEnabled(false);
|
||||
|
||||
if (i == lExplose && j == cExplose) {
|
||||
btn.setText("BOUM");
|
||||
btn.setBackground(Color.RED);
|
||||
} else if (c.isMinee() && c.getMarqueur() != 1) {
|
||||
btn.setText("M");
|
||||
btn.setBackground(Color.ORANGE);
|
||||
} else if (!c.isMinee() && c.getMarqueur() == 1) {
|
||||
btn.setText("X");
|
||||
btn.setBackground(Color.YELLOW);
|
||||
}
|
||||
/**
|
||||
* Affiche l'état de défaite en révélant les erreurs et les mines manquantes.
|
||||
* @param ligneExplosion la ligne de la mine déclenchée.
|
||||
* @param colonneExplosion la colonne de la mine déclenchée.
|
||||
*/
|
||||
public void afficherDefaite(int ligneExplosion, int colonneExplosion) {
|
||||
for (int ligne = 0; ligne < grille.getLignes(); ligne++) {
|
||||
for (int colonne = 0; colonne < grille.getColonnes(); colonne++) {
|
||||
Case caseActuelle = grille.getCase(ligne, colonne);
|
||||
JButton bouton = boutons[ligne][colonne];
|
||||
appliquerStyleDefaite(caseActuelle, bouton, ligne, colonne, ligneExplosion, colonneExplosion);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Détermine la couleur spécifique d'une case en fin de partie (erreur, oubli, ou explosion).
|
||||
* @param caseActuelle la donnée de la case.
|
||||
* @param bouton le composant graphique.
|
||||
* @param ligne la ligne en cours de parcours.
|
||||
* @param colonne la colonne en cours de parcours.
|
||||
* @param ligneExplosion la ligne de la mine fatale.
|
||||
* @param colonneExplosion la colonne de la mine fatale.
|
||||
*/
|
||||
private void appliquerStyleDefaite(Case caseActuelle, JButton bouton, int ligne, int colonne, int ligneExplosion, int colonneExplosion) {
|
||||
if (ligne == ligneExplosion && colonne == colonneExplosion) {
|
||||
bouton.setText("BOUM");
|
||||
bouton.setBackground(Color.RED);
|
||||
} else if (caseActuelle.isMinee() && caseActuelle.getMarqueur() != Case.MARQUEUR_ETOILE) {
|
||||
bouton.setText("M");
|
||||
bouton.setBackground(Color.ORANGE);
|
||||
} else if (!caseActuelle.isMinee() && caseActuelle.getMarqueur() == Case.MARQUEUR_ETOILE) {
|
||||
bouton.setText("X");
|
||||
bouton.setBackground(Color.YELLOW);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+107
-40
@@ -1,24 +1,44 @@
|
||||
import java.io.Serializable;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Gère la logique principale du Démineur (le plateau de jeu).
|
||||
* Initialise les cases, place les mines et contient l'algorithme de révélation.
|
||||
*/
|
||||
public class Grille implements Serializable {
|
||||
|
||||
/** Tableau à deux dimensions contenant toutes les cases du jeu. */
|
||||
private Case[][] plateau;
|
||||
|
||||
/** Nombre total de lignes de la grille. */
|
||||
private int lignes;
|
||||
|
||||
/** Nombre total de colonnes de la grille. */
|
||||
private int colonnes;
|
||||
|
||||
/** Nombre total de mines cachées dans la grille. */
|
||||
private int mines;
|
||||
|
||||
/** Indique si la partie est bloquée (gagnée ou perdue). */
|
||||
private boolean partieTerminee;
|
||||
|
||||
public Grille(int l, int c, int m) {
|
||||
this.lignes = l;
|
||||
this.colonnes = c;
|
||||
this.mines = m;
|
||||
/**
|
||||
* Constructeur de la grille.
|
||||
* Crée le plateau, place les mines aléatoirement et calcule les voisins.
|
||||
* @param nbLignes le nombre de lignes souhaité.
|
||||
* @param nbColonnes le nombre de colonnes souhaité.
|
||||
* @param nbMines le nombre de mines à placer.
|
||||
*/
|
||||
public Grille(int nbLignes, int nbColonnes, int nbMines) {
|
||||
this.lignes = nbLignes;
|
||||
this.colonnes = nbColonnes;
|
||||
this.mines = nbMines;
|
||||
this.partieTerminee = false;
|
||||
|
||||
this.plateau = new Case[this.lignes][this.colonnes];
|
||||
|
||||
for (int i = 0; i < this.lignes; i++) {
|
||||
for (int j = 0; j < this.colonnes; j++) {
|
||||
this.plateau[i][j] = new Case();
|
||||
for (int ligne = 0; ligne < this.lignes; ligne++) {
|
||||
for (int colonne = 0; colonne < this.colonnes; colonne++) {
|
||||
this.plateau[ligne][colonne] = new Case();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,18 +46,47 @@ public class Grille implements Serializable {
|
||||
calculerVoisins();
|
||||
}
|
||||
|
||||
/**
|
||||
* Récupère le nombre de lignes de la grille.
|
||||
* @return le nombre de lignes.
|
||||
*/
|
||||
public int getLignes() { return this.lignes; }
|
||||
|
||||
/**
|
||||
* Récupère le nombre de colonnes de la grille.
|
||||
* @return le nombre de colonnes.
|
||||
*/
|
||||
public int getColonnes() { return this.colonnes; }
|
||||
public Case getCase(int l, int c) { return this.plateau[l][c]; }
|
||||
|
||||
/**
|
||||
* Accède à une case spécifique du plateau.
|
||||
* @param indexLigne la ligne de la case cible.
|
||||
* @param indexColonne la colonne de la case cible.
|
||||
* @return l'objet Case correspondant.
|
||||
*/
|
||||
public Case getCase(int indexLigne, int indexColonne) { return this.plateau[indexLigne][indexColonne]; }
|
||||
|
||||
/**
|
||||
* Vérifie si la partie est verrouillée en état de fin.
|
||||
* @return true si terminée, false si en cours.
|
||||
*/
|
||||
public boolean isPartieTerminee() { return this.partieTerminee; }
|
||||
|
||||
/**
|
||||
* Modifie l'état de fin de partie (verrouillage de la grille).
|
||||
* @param terminee true pour bloquer le jeu, false pour le débloquer.
|
||||
*/
|
||||
public void setPartieTerminee(boolean terminee) { this.partieTerminee = terminee; }
|
||||
|
||||
// --- NOUVELLE MÉTHODE : Calcul des mines restantes ---
|
||||
/**
|
||||
* Calcule le nombre de mines restantes à trouver selon les drapeaux posés.
|
||||
* @return la soustraction des mines totales par le nombre d'étoiles posées.
|
||||
*/
|
||||
public int getMinesRestantes() {
|
||||
int drapeaux = 0;
|
||||
for (int i = 0; i < this.lignes; i++) {
|
||||
for (int j = 0; j < this.colonnes; j++) {
|
||||
if (this.plateau[i][j].getMarqueur() == 1) { // 1 = étoile
|
||||
for (int ligne = 0; ligne < this.lignes; ligne++) {
|
||||
for (int colonne = 0; colonne < this.colonnes; colonne++) {
|
||||
if (this.plateau[ligne][colonne].getMarqueur() == Case.MARQUEUR_ETOILE) {
|
||||
drapeaux++;
|
||||
}
|
||||
}
|
||||
@@ -45,54 +94,68 @@ public class Grille implements Serializable {
|
||||
return this.mines - drapeaux;
|
||||
}
|
||||
|
||||
/**
|
||||
* Place aléatoirement le nombre défini de mines sur le plateau vide.
|
||||
*/
|
||||
private void placerMines() {
|
||||
Random rand = new Random();
|
||||
int minesPlacees = 0;
|
||||
while (minesPlacees < this.mines) {
|
||||
int l = rand.nextInt(this.lignes);
|
||||
int c = rand.nextInt(this.colonnes);
|
||||
if (!this.plateau[l][c].isMinee()) {
|
||||
this.plateau[l][c].setMinee(true);
|
||||
int ligneAleatoire = (int) (Math.random() * this.lignes);
|
||||
int colonneAleatoire = (int) (Math.random() * this.colonnes);
|
||||
|
||||
if (!this.plateau[ligneAleatoire][colonneAleatoire].isMinee()) {
|
||||
this.plateau[ligneAleatoire][colonneAleatoire].setMinee(true);
|
||||
minesPlacees++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parcourt la grille pour calculer le nombre de mines autour de chaque case non-minée.
|
||||
*/
|
||||
private void calculerVoisins() {
|
||||
for (int i = 0; i < this.lignes; i++) {
|
||||
for (int j = 0; j < this.colonnes; j++) {
|
||||
if (!this.plateau[i][j].isMinee()) {
|
||||
for (int ligne = 0; ligne < this.lignes; ligne++) {
|
||||
for (int colonne = 0; colonne < this.colonnes; colonne++) {
|
||||
if (!this.plateau[ligne][colonne].isMinee()) {
|
||||
int compteMines = 0;
|
||||
for (int di = -1; di <= 1; di++) {
|
||||
for (int dj = -1; dj <= 1; dj++) {
|
||||
int voisinI = i + di;
|
||||
int voisinJ = j + dj;
|
||||
if (voisinI >= 0 && voisinI < this.lignes && voisinJ >= 0 && voisinJ < this.colonnes) {
|
||||
if (this.plateau[voisinI][voisinJ].isMinee()) {
|
||||
for (int decalageLigne = -1; decalageLigne <= 1; decalageLigne++) {
|
||||
for (int decalageColonne = -1; decalageColonne <= 1; decalageColonne++) {
|
||||
int voisinLigne = ligne + decalageLigne;
|
||||
int voisinColonne = colonne + decalageColonne;
|
||||
if (voisinLigne >= 0 && voisinLigne < this.lignes && voisinColonne >= 0 && voisinColonne < this.colonnes) {
|
||||
if (this.plateau[voisinLigne][voisinColonne].isMinee()) {
|
||||
compteMines++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.plateau[i][j].setNbMinesVoisines(compteMines);
|
||||
this.plateau[ligne][colonne].setNbMinesVoisines(compteMines);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean revelerCase(int l, int c) {
|
||||
Case caseCliquee = this.plateau[l][c];
|
||||
if (caseCliquee.isRevelee() || caseCliquee.getMarqueur() == 1) return false;
|
||||
/**
|
||||
* Révèle une case et déclenche une réaction en chaîne récursive si elle vaut 0.
|
||||
* @param cibleLigne la ligne de la case à révéler.
|
||||
* @param cibleColonne la colonne de la case à révéler.
|
||||
* @return true si une mine a explosé, false sinon.
|
||||
*/
|
||||
public boolean revelerCase(int cibleLigne, int cibleColonne) {
|
||||
Case caseCliquee = this.plateau[cibleLigne][cibleColonne];
|
||||
|
||||
if (caseCliquee.isRevelee() || caseCliquee.getMarqueur() == Case.MARQUEUR_ETOILE) return false;
|
||||
|
||||
caseCliquee.setRevelee(true);
|
||||
if (caseCliquee.isMinee()) return true;
|
||||
|
||||
if (caseCliquee.getNbMinesVoisines() == 0) {
|
||||
for (int di = -1; di <= 1; di++) {
|
||||
for (int dj = -1; dj <= 1; dj++) {
|
||||
int voisinL = l + di;
|
||||
int voisinC = c + dj;
|
||||
if (voisinL >= 0 && voisinL < this.lignes && voisinC >= 0 && voisinC < this.colonnes) {
|
||||
revelerCase(voisinL, voisinC);
|
||||
for (int decalageLigne = -1; decalageLigne <= 1; decalageLigne++) {
|
||||
for (int decalageColonne = -1; decalageColonne <= 1; decalageColonne++) {
|
||||
int voisinLigne = cibleLigne + decalageLigne;
|
||||
int voisinColonne = cibleColonne + decalageColonne;
|
||||
if (voisinLigne >= 0 && voisinLigne < this.lignes && voisinColonne >= 0 && voisinColonne < this.colonnes) {
|
||||
revelerCase(voisinLigne, voisinColonne);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -100,11 +163,15 @@ public class Grille implements Serializable {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si le joueur a révélé toutes les cases non-minées du plateau.
|
||||
* @return true si la partie est gagnée, false si elle est toujours en cours.
|
||||
*/
|
||||
public boolean estGagnee() {
|
||||
int casesRevelees = 0;
|
||||
for (int i = 0; i < this.lignes; i++) {
|
||||
for (int j = 0; j < this.colonnes; j++) {
|
||||
if (this.plateau[i][j].isRevelee()) casesRevelees++;
|
||||
for (int ligne = 0; ligne < this.lignes; ligne++) {
|
||||
for (int colonne = 0; colonne < this.colonnes; colonne++) {
|
||||
if (this.plateau[ligne][colonne].isRevelee()) casesRevelees++;
|
||||
}
|
||||
}
|
||||
return casesRevelees == ((this.lignes * this.colonnes) - this.mines);
|
||||
|
||||
+98
-47
@@ -1,69 +1,120 @@
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.io.FileInputStream;
|
||||
|
||||
/**
|
||||
* Fenêtre principale affichant le menu du Démineur.
|
||||
* Fenêtre du menu principal s'affichant au lancement de l'application.
|
||||
* Permet de démarrer, reprendre ou quitter une partie.
|
||||
*/
|
||||
public class MenuPrincipal extends JFrame {
|
||||
|
||||
private JButton btnNouvellePartie;
|
||||
private JButton btnReprendre;
|
||||
private JButton btnQuitter;
|
||||
|
||||
/** Largeur de la fenêtre en pixels. */
|
||||
private static final int LARGEUR_FENETRE = 400;
|
||||
|
||||
/** Hauteur de la fenêtre en pixels. */
|
||||
private static final int HAUTEUR_FENETRE = 300;
|
||||
|
||||
/** Position X initiale de la fenêtre sur l'écran. */
|
||||
private static final int POSITION_X = 100;
|
||||
|
||||
/** Position Y initiale de la fenêtre sur l'écran. */
|
||||
private static final int POSITION_Y = 100;
|
||||
|
||||
/** Nombre de lignes pour la disposition des boutons. */
|
||||
private static final int LIGNES_GRILLE = 3;
|
||||
|
||||
/** Nombre de colonnes pour la disposition des boutons. */
|
||||
private static final int COLONNES_GRILLE = 1;
|
||||
|
||||
/** Bouton permettant de lancer une nouvelle partie personnalisée. */
|
||||
private JButton boutonNouvellePartie;
|
||||
|
||||
/** Bouton permettant de recharger la dernière sauvegarde trouvée. */
|
||||
private JButton boutonReprendre;
|
||||
|
||||
/** Bouton permettant de fermer complètement l'application. */
|
||||
private JButton boutonQuitter;
|
||||
|
||||
/**
|
||||
* Constructeur du menu principal.
|
||||
* Initialise l'interface graphique en respectant les méthodes du cours.
|
||||
*/
|
||||
public MenuPrincipal() {
|
||||
// Configuration de la fenêtre (héritée de JFrame)
|
||||
super("Démineur - Menu Principal");
|
||||
this.setSize(300, 250);
|
||||
this.setSize(LARGEUR_FENETRE, HAUTEUR_FENETRE);
|
||||
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
|
||||
// Mise en page principale
|
||||
this.setLayout(new BorderLayout());
|
||||
this.setLocation(POSITION_X, POSITION_Y);
|
||||
|
||||
// Titre en haut
|
||||
JLabel etiquetteTitre = new JLabel("DÉMINEUR");
|
||||
etiquetteTitre.setHorizontalAlignment(JLabel.CENTER);
|
||||
this.add(etiquetteTitre, BorderLayout.NORTH);
|
||||
|
||||
// Panneau pour les boutons au centre
|
||||
JPanel panneauBoutons = new JPanel();
|
||||
panneauBoutons.setLayout(new GridLayout(3, 1)); // 3 lignes, 1 colonne
|
||||
|
||||
// Création des boutons
|
||||
this.btnNouvellePartie = new JButton("Commencer une nouvelle partie");
|
||||
this.btnReprendre = new JButton("Reprendre la partie précédente");
|
||||
this.btnQuitter = new JButton("Quitter");
|
||||
|
||||
// Désactivation du bouton "Reprendre" par défaut (comme demandé dans le sujet)
|
||||
this.btnReprendre.setEnabled(false);
|
||||
|
||||
// Ajout des boutons au panneau
|
||||
panneauBoutons.add(this.btnNouvellePartie);
|
||||
panneauBoutons.add(this.btnReprendre);
|
||||
panneauBoutons.add(this.btnQuitter);
|
||||
|
||||
// Ajout du panneau au centre de la fenêtre
|
||||
this.add(panneauBoutons, BorderLayout.CENTER);
|
||||
|
||||
// Connexion avec l'observateur (le contrôleur)
|
||||
ControleurMenu observateur = new ControleurMenu(this);
|
||||
this.btnNouvellePartie.addActionListener(observateur);
|
||||
this.btnReprendre.addActionListener(observateur);
|
||||
this.btnQuitter.addActionListener(observateur);
|
||||
initialiserPanneauBoutons();
|
||||
}
|
||||
|
||||
// --- Accesseurs pour que l'observateur puisse identifier les boutons ---
|
||||
public JButton getBtnNouvellePartie() { return this.btnNouvellePartie; }
|
||||
public JButton getBtnReprendre() { return this.btnReprendre; }
|
||||
public JButton getBtnQuitter() { return this.btnQuitter; }
|
||||
/**
|
||||
* Crée le panneau, instancie les boutons et les ajoute à l'interface.
|
||||
*/
|
||||
private void initialiserPanneauBoutons() {
|
||||
JPanel panneauBoutons = new JPanel();
|
||||
panneauBoutons.setLayout(new GridLayout(LIGNES_GRILLE, COLONNES_GRILLE));
|
||||
|
||||
this.boutonNouvellePartie = new JButton("Nouvelle Partie");
|
||||
this.boutonReprendre = new JButton("Reprendre une partie");
|
||||
this.boutonQuitter = new JButton("Quitter");
|
||||
|
||||
panneauBoutons.add(this.boutonNouvellePartie);
|
||||
ajouterBoutonReprendreSiSauvegarde(panneauBoutons);
|
||||
panneauBoutons.add(this.boutonQuitter);
|
||||
|
||||
this.add(panneauBoutons, BorderLayout.CENTER);
|
||||
|
||||
connecterControleur();
|
||||
}
|
||||
|
||||
/**
|
||||
* Méthode principale pour lancer le programme.
|
||||
* @param args arguments de la ligne de commande (inutilisés)
|
||||
* Tente de lire le fichier de sauvegarde. Si le fichier existe,
|
||||
* le bouton "Reprendre" est ajouté au panneau. Sinon, l'erreur est ignorée.
|
||||
* @param panneau le panneau graphique qui contiendra le bouton.
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
private void ajouterBoutonReprendreSiSauvegarde(JPanel panneau) {
|
||||
try {
|
||||
FileInputStream testLecture = new FileInputStream("sauvegarde.dat");
|
||||
testLecture.close();
|
||||
panneau.add(this.boutonReprendre);
|
||||
} catch (Exception exception) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Instancie le contrôleur et l'attache aux différents boutons.
|
||||
*/
|
||||
private void connecterControleur() {
|
||||
ControleurMenu controleur = new ControleurMenu(this);
|
||||
this.boutonNouvellePartie.addActionListener(controleur);
|
||||
this.boutonReprendre.addActionListener(controleur);
|
||||
this.boutonQuitter.addActionListener(controleur);
|
||||
}
|
||||
|
||||
/**
|
||||
* Accède au bouton de nouvelle partie.
|
||||
* @return le bouton "Nouvelle Partie".
|
||||
*/
|
||||
public JButton getBoutonNouvellePartie() { return this.boutonNouvellePartie; }
|
||||
|
||||
/**
|
||||
* Accède au bouton de reprise de partie.
|
||||
* @return le bouton "Reprendre une partie".
|
||||
*/
|
||||
public JButton getBoutonReprendre() { return this.boutonReprendre; }
|
||||
|
||||
/**
|
||||
* Accède au bouton pour quitter le jeu.
|
||||
* @return le bouton "Quitter".
|
||||
*/
|
||||
public JButton getBoutonQuitter() { return this.boutonQuitter; }
|
||||
|
||||
/**
|
||||
* Point d'entrée principal du programme.
|
||||
* @param arguments les arguments passés en ligne de commande.
|
||||
*/
|
||||
public static void main(String[] arguments) {
|
||||
MenuPrincipal menu = new MenuPrincipal();
|
||||
menu.setVisible(true);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user