import java.io.Serializable; import java.util.Random; /** * Représente le plateau de jeu contenant les cases. */ public class Grille implements Serializable { private Case[][] plateau; private int lignes; private int colonnes; private int mines; /** * Initialise une nouvelle grille et place les mines. */ public Grille(int l, int c, int m) { this.lignes = l; this.colonnes = c; this.mines = m; this.plateau = new Case[this.lignes][this.colonnes]; // 1. Initialisation : on remplit avec des cases vides for (int i = 0; i < this.lignes; i++) { for (int j = 0; j < this.colonnes; j++) { this.plateau[i][j] = new Case(); } } // 2. On appelle nos nouvelles méthodes placerMines(); calculerVoisins(); } // --- Les Getters --- public int getLignes() { return this.lignes; } public int getColonnes() { return this.colonnes; } /** * Permet d'accéder à une case spécifique de la grille. */ public Case getCase(int l, int c) { return this.plateau[l][c]; } // --- Les algorithmes du jeu --- /** * Place les mines aléatoirement dans le tableau. */ private void placerMines() { Random rand = new Random(); int minesPlacees = 0; // Tant qu'on n'a pas placé toutes les mines demandées... while (minesPlacees < this.mines) { int l = rand.nextInt(this.lignes); int c = rand.nextInt(this.colonnes); // Si la case n'est pas déjà minée, on y met une mine if (!this.plateau[l][c].isMinee()) { this.plateau[l][c].setMinee(true); minesPlacees++; } } } /** * Calcule le nombre de mines autour de chaque case. */ private void calculerVoisins() { for (int i = 0; i < this.lignes; i++) { for (int j = 0; j < this.colonnes; j++) { // Si la case elle-même n'est pas une mine if (!this.plateau[i][j].isMinee()) { int compteMines = 0; // On parcourt les 8 cases autour (de -1 à +1 en ligne et colonne) for (int di = -1; di <= 1; di++) { for (int dj = -1; dj <= 1; dj++) { int voisinI = i + di; int voisinJ = j + dj; // On vérifie qu'on ne sort pas du tableau ! // (Pour éviter l'ArrayIndexOutOfBoundsException vu dans ton cours) if (voisinI >= 0 && voisinI < this.lignes && voisinJ >= 0 && voisinJ < this.colonnes) { if (this.plateau[voisinI][voisinJ].isMinee()) { compteMines++; } } } } // On enregistre le chiffre dans la case this.plateau[i][j].setNbMinesVoisines(compteMines); } } } } /** * Révèle une case et déclenche une réaction en chaîne si elle vaut 0. * C'est l'algorithme récursif principal du jeu ! * @return true si on a cliqué sur une mine (défaite), false sinon. */ public boolean revelerCase(int l, int c) { Case caseCliquee = this.plateau[l][c]; // Conditions d'arrêt : on s'arrête si la case est déjà révélée ou a une étoile if (caseCliquee.isRevelee() || caseCliquee.getMarqueur() == 1) { return false; } // On révèle la case caseCliquee.setRevelee(true); // Si c'est une mine, c'est perdu ! if (caseCliquee.isMinee()) { return true; } // RÉACTION EN CHAÎNE : Si c'est un 0, on révèle les voisins 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; // On vérifie qu'on ne sort pas des bords du tableau if (voisinL >= 0 && voisinL < this.lignes && voisinC >= 0 && voisinC < this.colonnes) { // LA RÉCURSIVITÉ EST ICI : la fonction s'appelle elle-même revelerCase(voisinL, voisinC); } } } } return false; // Pas de mine explosée } /** * Vérifie si le joueur a gagné la partie. * @return true si toutes les cases sans mine sont révélées, false sinon. */ public boolean estGagnee() { int casesRevelees = 0; // On compte combien de cases le joueur a réussi à révéler for (int i = 0; i < this.lignes; i++) { for (int j = 0; j < this.colonnes; j++) { if (this.plateau[i][j].isRevelee()) { casesRevelees++; } } } // C'est gagné si le nombre de cases révélées correspond au total des cases vides int casesVidesTotales = (this.lignes * this.colonnes) - this.mines; return casesRevelees == casesVidesTotales; } }