Files
2026-04-12 16:40:07 +02:00

180 lines
6.7 KiB
Java

import java.io.Serializable;
/**
* 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;
/**
* 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 ligne = 0; ligne < this.lignes; ligne++) {
for (int colonne = 0; colonne < this.colonnes; colonne++) {
this.plateau[ligne][colonne] = new Case();
}
}
placerMines();
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; }
/**
* 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; }
/**
* 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 ligne = 0; ligne < this.lignes; ligne++) {
for (int colonne = 0; colonne < this.colonnes; colonne++) {
if (this.plateau[ligne][colonne].getMarqueur() == Case.MARQUEUR_ETOILE) {
drapeaux++;
}
}
}
return this.mines - drapeaux;
}
/**
* Place aléatoirement le nombre défini de mines sur le plateau vide.
*/
private void placerMines() {
int minesPlacees = 0;
while (minesPlacees < this.mines) {
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 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 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[ligne][colonne].setNbMinesVoisines(compteMines);
}
}
}
}
/**
* 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 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);
}
}
}
}
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 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);
}
}