diff --git a/src/main/java/sae/chuzzle/EtatJeu.java b/src/main/java/sae/chuzzle/EtatJeu.java index cf4983b..070cde5 100644 --- a/src/main/java/sae/chuzzle/EtatJeu.java +++ b/src/main/java/sae/chuzzle/EtatJeu.java @@ -1,47 +1,36 @@ package sae.chuzzle; import android.os.Bundle; - -import java.util.ArrayList; import java.util.List; import java.util.Random; +/** + * Gère la session de jeu (score, coups, état de la partie) et délègue la manipulation + * physique de la grille à la classe Plateau. + */ public class EtatJeu { - public static final int NB_LIGNES = 6; - public static final int NB_COLONNES = 6; - public static final int NB_TYPES = 7; - - private final int[][] grille = new int[NB_LIGNES][NB_COLONNES]; - private final boolean[][] verrous = new boolean[NB_LIGNES][NB_COLONNES]; + private final Plateau plateau; private final Random aleatoire; + private final boolean hardMode; private int score = 0; private int nbCoups = 0; private boolean partieTerminee = false; - private boolean hardMode = false; - - // Ajout pour les objectifs : comptage des séries par couleur au dernier coup - private final int[] seriesParCouleurDernierCoup = new int[NB_TYPES]; - - //- - // CONSTRUCTEURS + private final int[] seriesParCouleurDernierCoup = new int[Plateau.NB_TYPES]; public EtatJeu() { - aleatoire = new Random(); - initialiserGrilleSansTriples(); + this(System.currentTimeMillis(), false); } public EtatJeu(long graine, boolean hardMode) { - aleatoire = new Random(graine); + this.aleatoire = new Random(graine); this.hardMode = hardMode; - initialiserGrilleSansTriples(); + this.plateau = new Plateau(this.aleatoire); } - // - - // GETTERS - + // --- Getters --- public int obtenirScore() { return score; @@ -59,587 +48,259 @@ public class EtatJeu { return seriesParCouleurDernierCoup; } - // - - // SAUVEGARDE ET RESTAURATION - - public void sauvegarderEtat(Bundle bundle) { - int[] flatGrille = new int[NB_LIGNES * NB_COLONNES]; - boolean[] flatVerrous = new boolean[NB_LIGNES * NB_COLONNES]; - - for (int l = 0; l < NB_LIGNES; l++) { - for (int c = 0; c < NB_COLONNES; c++) { - flatGrille[l * NB_COLONNES + c] = grille[l][c]; - flatVerrous[l * NB_COLONNES + c] = verrous[l][c]; - } - } - - bundle.putIntArray("grille", flatGrille); - bundle.putBooleanArray("verrous", flatVerrous); - bundle.putInt("score", score); - bundle.putInt("nbCoups", nbCoups); - bundle.putBoolean("partieTerminee", partieTerminee); - } - - public void restaurerEtat(Bundle bundle) { - if (!bundle.containsKey("grille")) return; - - int[] flatGrille = bundle.getIntArray("grille"); - boolean[] flatVerrous = bundle.getBooleanArray("verrous"); - - if (flatGrille != null && flatVerrous != null) { - for (int l = 0; l < NB_LIGNES; l++) { - for (int c = 0; c < NB_COLONNES; c++) { - grille[l][c] = flatGrille[l * NB_COLONNES + c]; - verrous[l][c] = flatVerrous[l * NB_COLONNES + c]; - } - } - } - - score = bundle.getInt("score"); - nbCoups = bundle.getInt("nbCoups"); - partieTerminee = bundle.getBoolean("partieTerminee"); - } - - public int obtenirCase(int ligne, int colonne) { - return grille[ligne][colonne]; - } - public int[][] obtenirGrille() { - int[][] copie = new int[NB_LIGNES][NB_COLONNES]; - - for (int l = 0; l < NB_LIGNES; l++) { - System.arraycopy(grille[l], 0, copie[l], 0, NB_COLONNES); - } - - return copie; + return plateau.copierGrille(); } public boolean[][] obtenirVerrous() { - boolean[][] copie = new boolean[NB_LIGNES][NB_COLONNES]; - - for (int l = 0; l < NB_LIGNES; l++) { - System.arraycopy(verrous[l], 0, copie[l], 0, NB_COLONNES); + // Copie manuelle pour respecter l'encapsulation + boolean[][] v = plateau.getVerrous(); + boolean[][] copie = new boolean[Plateau.NB_LIGNES][Plateau.NB_COLONNES]; + for (int l = 0; l < Plateau.NB_LIGNES; l++) { + System.arraycopy(v[l], 0, copie[l], 0, Plateau.NB_COLONNES); } - return copie; } - // - - // INITIALISATION SANS TRIPLES - // - - private void initialiserGrilleSansTriples() { - for (int ligne = 0; ligne < NB_LIGNES; ligne++) { - for (int colonne = 0; colonne < NB_COLONNES; colonne++) { - - int valeur; - do { - valeur = aleatoire.nextInt(NB_TYPES); - } while (creeTriple(ligne, colonne, valeur)); - - grille[ligne][colonne] = valeur; - } - } - } - - private boolean creeTriple(int ligne, int colonne, int valeur) { - - if (colonne >= 2) { - if (grille[ligne][colonne - 1] == valeur && - grille[ligne][colonne - 2] == valeur) { - return true; - } - } - - if (ligne >= 2) { - if (grille[ligne - 1][colonne] == valeur && - grille[ligne - 2][colonne] == valeur) { - return true; - } - } - - return false; - } - - // - - // DECALAGE CIRCULAIRE - - - public void decalerLigne(int ligne, int sens) { - int s = ((sens % NB_COLONNES) + NB_COLONNES) % NB_COLONNES; - - for (int etape = 0; etape < s; etape++) { - int tmp = grille[ligne][NB_COLONNES - 1]; - - for (int c = NB_COLONNES - 1; c > 0; c--) { - grille[ligne][c] = grille[ligne][c - 1]; - } - - grille[ligne][0] = tmp; - } - } - - public void decalerColonne(int colonne, int sens) { - int s = ((sens % NB_LIGNES) + NB_LIGNES) % NB_LIGNES; - - for (int etape = 0; etape < s; etape++) { - int tmp = grille[NB_LIGNES - 1][colonne]; - - for (int l = NB_LIGNES - 1; l > 0; l--) { - grille[l][colonne] = grille[l - 1][colonne]; - } - - grille[0][colonne] = tmp; - } - } - - // - - // APPLIQUER UN COUP - + // --- Actions --- public boolean appliquerCoup(boolean estLigne, int index, int sens) { - if (partieTerminee) { + if (partieTerminee || plateau.estBloque(estLigne, index)) { return false; } - // Les verrous bloquent toujours, quel que soit le mode - if (estBloque(estLigne, index)) { - return false; - } - - int[][] sauvegarde = copierGrille(); - + int[][] sauvegarde = plateau.copierGrille(); if (estLigne) { - decalerLigne(index, sens); + plateau.decalerLigne(index, sens); } else { - decalerColonne(index, sens); + plateau.decalerColonne(index, sens); } - if (trouverSeries().isEmpty()) { - restaurerGrille(sauvegarde); + if (plateau.trouverSeries().isEmpty()) { + plateau.restaurerGrille(sauvegarde); return false; } nbCoups++; - - // Reset des séries du dernier coup - for (int i = 0; i < NB_TYPES; i++) seriesParCouleurDernierCoup[i] = 0; + resetSeriesDernierCoup(); + score += resoudreCascades(); - score += resoudreEtRemplir(); - - // Verrou après chaque coup ; 2 verrous en hard mode (plus difficile) - ajouterVerrou(); + plateau.ajouterVerrou(nbCoups); if (hardMode) { - ajouterVerrou(); + plateau.ajouterVerrou(nbCoups); } if (!aUnCoupValide()) { partieTerminee = true; } - return true; } - // - - // TROUVER LES SERIES - - - public List trouverSeries() { - boolean[][] aSupprimer = new boolean[NB_LIGNES][NB_COLONNES]; - - for (int l = 0; l < NB_LIGNES; l++) { - int c = 0; - - while (c < NB_COLONNES) { - int type = grille[l][c]; - int fin = c + 1; - - while (fin < NB_COLONNES && grille[l][fin] == type) { - fin++; - } - - if (fin - c >= 3) { - for (int k = c; k < fin; k++) { - aSupprimer[l][k] = true; - } - } - - c = fin; - } - } - - for (int col = 0; col < NB_COLONNES; col++) { - int l = 0; - - while (l < NB_LIGNES) { - int type = grille[l][col]; - int fin = l + 1; - - while (fin < NB_LIGNES && grille[fin][col] == type) { - fin++; - } - - if (fin - l >= 3) { - for (int k = l; k < fin; k++) { - aSupprimer[k][col] = true; - } - } - - l = fin; - } - } - - List positions = new ArrayList<>(); - - for (int l = 0; l < NB_LIGNES; l++) { - for (int col = 0; col < NB_COLONNES; col++) { - if (aSupprimer[l][col]) { - positions.add(new int[]{l, col}); - } - } - } - - return positions; - } - - // - - // RESOLUTION AVEC CASCADE - - - public int resoudreEtRemplir() { + private int resoudreCascades() { int baseTotal = 0; - int nbSeriesTotal = 0; - - List series = trouverSeries(); + int nbSeriesTotal = 0; + List series = plateau.trouverSeries(); while (!series.isEmpty()) { - - // Accumuler les points de base et le nombre de séries sur toutes les vagues baseTotal += calculerPointsBase(series); - - // On compte les séries par couleur spécifiquement - compterSeriesParCouleur(series); + nbSeriesTotal += compterEtEnregistrerSeries(series); - nbSeriesTotal += compterNbSeries(series); + boolean[][] masque = creerMasque(series); + plateau.libererVerrous(masque); + plateau.faireTomber(masque); - boolean[][] aSupprimer = new boolean[NB_LIGNES][NB_COLONNES]; - - for (int[] pos : series) { - aSupprimer[pos[0]][pos[1]] = true; - } - - // Libérer les verrous des cases supprimées - libererVerrous(aSupprimer); - - for (int col = 0; col < NB_COLONNES; col++) { - - List survivants = new ArrayList<>(); - - for (int l = NB_LIGNES - 1; l >= 0; l--) { - if (!aSupprimer[l][col]) { - survivants.add(grille[l][col]); - } - } - - int li = NB_LIGNES - 1; - - for (int val : survivants) { - grille[li][col] = val; - li--; - } - - while (li >= 0) { - grille[li][col] = aleatoire.nextInt(NB_TYPES); - li--; - } - } - - series = trouverSeries(); + series = plateau.trouverSeries(); } - if (nbSeriesTotal == 0) return 0; - - // Bonus : +50% par série supplémentaire après la première (spec SAÉ) - double bonus = 1.0 + (nbSeriesTotal - 1) * 0.5; - return (int) (baseTotal * bonus); + if (nbSeriesTotal == 0) { + return 0; + } + return (int) (baseTotal * (1.0 + (nbSeriesTotal - 1) * 0.5)); } - private void compterSeriesParCouleur(List series) { - boolean[][] masque = new boolean[NB_LIGNES][NB_COLONNES]; - for (int[] pos : series) masque[pos[0]][pos[1]] = true; - - // Horizontales - for (int l = 0; l < NB_LIGNES; l++) { - int c = 0; - while (c < NB_COLONNES) { - if (masque[l][c]) { - int type = grille[l][c]; - int fin = c + 1; - while (fin < NB_COLONNES && masque[l][fin] && grille[l][fin] == type) fin++; - if (fin - c >= 3) seriesParCouleurDernierCoup[type]++; - c = fin; - } else c++; - } - } - // Verticales - for (int col = 0; col < NB_COLONNES; col++) { - int l = 0; - while (l < NB_LIGNES) { - if (masque[l][col]) { - int type = grille[l][col]; - int fin = l + 1; - while (fin < NB_LIGNES && masque[fin][col] && grille[fin][col] == type) fin++; - if (fin - l >= 3) seriesParCouleurDernierCoup[type]++; - l = fin; - } else l++; - } - } - } - - private int calculerPointsBase(List series) { - boolean[][] masque = new boolean[NB_LIGNES][NB_COLONNES]; - - for (int[] pos : series) { - masque[pos[0]][pos[1]] = true; - } - - int total = 0; - - for (int l = 0; l < NB_LIGNES; l++) { - int c = 0; - - while (c < NB_COLONNES) { - if (masque[l][c]) { - int fin = c + 1; - - while (fin < NB_COLONNES && masque[l][fin]) { - fin++; - } - - total += pointsPourLongueur(fin - c); - c = fin; - } else { - c++; - } - } - } - - for (int col = 0; col < NB_COLONNES; col++) { - int l = 0; - - while (l < NB_LIGNES) { - if (masque[l][col]) { - int fin = l + 1; - - while (fin < NB_LIGNES && masque[fin][col]) { - fin++; - } - - total += pointsPourLongueur(fin - l); - l = fin; - } else { - l++; - } - } - } - - return total; - } - - private int compterNbSeries(List series) { - boolean[][] masque = new boolean[NB_LIGNES][NB_COLONNES]; - - for (int[] pos : series) { - masque[pos[0]][pos[1]] = true; - } + // --- Aide à la résolution --- + private int compterEtEnregistrerSeries(List series) { + boolean[][] masque = creerMasque(series); int count = 0; + int[][] g = plateau.getGrille(); - // Séries horizontales - for (int l = 0; l < NB_LIGNES; l++) { + // Horizontal + for (int l = 0; l < Plateau.NB_LIGNES; l++) { int c = 0; - - while (c < NB_COLONNES) { + while (c < Plateau.NB_COLONNES) { if (masque[l][c]) { + int type = g[l][c]; int fin = c + 1; - - while (fin < NB_COLONNES && masque[l][fin]) { + while (fin < Plateau.NB_COLONNES && masque[l][fin] && g[l][fin] == type) { fin++; } - - count++; + if (fin - c >= 3) { + seriesParCouleurDernierCoup[type]++; + count++; + } c = fin; } else { c++; } } } - - // Séries verticales - for (int col = 0; col < NB_COLONNES; col++) { + // Vertical + for (int c = 0; c < Plateau.NB_COLONNES; c++) { int l = 0; - - while (l < NB_LIGNES) { - if (masque[l][col]) { + while (l < Plateau.NB_LIGNES) { + if (masque[l][c]) { + int type = g[l][c]; int fin = l + 1; - - while (fin < NB_LIGNES && masque[fin][col]) { + while (fin < Plateau.NB_LIGNES && masque[fin][c] && g[fin][c] == type) { fin++; } - - count++; + if (fin - l >= 3) { + seriesParCouleurDernierCoup[type]++; + count++; + } l = fin; } else { l++; } } } - return count; } - private int pointsPourLongueur(int longueur) { - if (longueur == 3) { - return 8; - } else if (longueur == 4) { - return 16; - } else if (longueur == 5) { - return 32; - } else { - return 64; - } - } - - // - - // VERROUS (hard mode) - - - private boolean estBloque(boolean estLigne, int index) { - if (estLigne) { - for (int col = 0; col < NB_COLONNES; col++) { - if (verrous[index][col]) { - return true; - } - } - } else { - for (int lig = 0; lig < NB_LIGNES; lig++) { - if (verrous[lig][index]) { - return true; + private int calculerPointsBase(List series) { + boolean[][] masque = creerMasque(series); + int pts = 0; + // Horizontal + for (int l = 0; l < Plateau.NB_LIGNES; l++) { + int c = 0; + while (c < Plateau.NB_COLONNES) { + if (masque[l][c]) { + int fin = c + 1; + while (fin < Plateau.NB_COLONNES && masque[l][fin]) { + fin++; + } + pts += pointsPourLongueur(fin - c); + c = fin; + } else { + c++; } } } - - return false; - } - - private void ajouterVerrou() { - int intervalle = Math.max(1, 5 - nbCoups / 10); - - if (nbCoups % intervalle != 0) { - return; - } - - List casesLibres = new ArrayList<>(); - - for (int l = 0; l < NB_LIGNES; l++) { - for (int col = 0; col < NB_COLONNES; col++) { - if (!verrous[l][col]) { - casesLibres.add(new int[]{l, col}); + // Vertical + for (int c = 0; c < Plateau.NB_COLONNES; c++) { + int l = 0; + while (l < Plateau.NB_LIGNES) { + if (masque[l][c]) { + int fin = l + 1; + while (fin < Plateau.NB_LIGNES && masque[fin][c]) { + fin++; + } + pts += pointsPourLongueur(fin - l); + l = fin; + } else { + l++; } } } - - if (casesLibres.isEmpty()) { - return; - } - - int[] caseChoisie = casesLibres.get(aleatoire.nextInt(casesLibres.size())); - verrous[caseChoisie[0]][caseChoisie[1]] = true; + return pts; } - private void libererVerrous(boolean[][] aSupprimer) { - for (int l = 0; l < NB_LIGNES; l++) { - for (int col = 0; col < NB_COLONNES; col++) { - if (aSupprimer[l][col]) { - verrous[l][col] = false; - } - } - } + private int pointsPourLongueur(int n) { + if (n == 3) return 8; + if (n == 4) return 16; + if (n == 5) return 32; + return 64; } - // - - // DETECTION FIN DE PARTIE + private boolean[][] creerMasque(List positions) { + boolean[][] m = new boolean[Plateau.NB_LIGNES][Plateau.NB_COLONNES]; + for (int[] p : positions) { + m[p[0]][p[1]] = true; + } + return m; + } + private void resetSeriesDernierCoup() { + for (int i = 0; i < Plateau.NB_TYPES; i++) { + seriesParCouleurDernierCoup[i] = 0; + } + } public boolean aUnCoupValide() { - // Teste tous les décalages possibles (1 à N-1) pour les lignes - for (int i = 0; i < NB_LIGNES; i++) { - - // AJOUT : Si la ligne est bloquée par un verrou, on ne peut pas la bouger - if (estBloque(true, i)) continue; - - for (int s = 1; s < NB_COLONNES; s++) { - if (coupCreeSerie(true, i, s)) { + for (int i = 0; i < Plateau.NB_LIGNES; i++) { + if (plateau.estBloque(true, i)) { + continue; + } + for (int s = 1; s < Plateau.NB_COLONNES; s++) { + if (simulerCoup(true, i, s)) { return true; } } } - - // Teste tous les décalages possibles (1 à N-1) pour les colonnes - for (int j = 0; j < NB_COLONNES; j++) { - - // AJOUT : Si la colonne est bloquée par un verrou, on ne peut pas la bouger - if (estBloque(false, j)) continue; - - for (int s = 1; s < NB_LIGNES; s++) { - if (coupCreeSerie(false, j, s)) { + for (int j = 0; j < Plateau.NB_COLONNES; j++) { + if (plateau.estBloque(false, j)) { + continue; + } + for (int s = 1; s < Plateau.NB_LIGNES; s++) { + if (simulerCoup(false, j, s)) { return true; } } } - return false; } + private boolean simulerCoup(boolean estLigne, int idx, int s) { + int[][] save = plateau.copierGrille(); + if (estLigne) { + plateau.decalerLigne(idx, s); + } else { + plateau.decalerColonne(idx, s); + } + boolean ok = !plateau.trouverSeries().isEmpty(); + plateau.restaurerGrille(save); + return ok; + } + public void forcerFinDePartie() { - this.partieTerminee = true; + partieTerminee = true; } - private boolean coupCreeSerie(boolean estLigne, int index, int sens) { - int[][] sauvegarde = copierGrille(); - - if (estLigne) { - decalerLigne(index, sens); - } else { - decalerColonne(index, sens); + public void sauvegarderEtat(Bundle b) { + int[] g = new int[36]; + boolean[] v = new boolean[36]; + int[][] grid = plateau.getGrille(); + boolean[][] lk = plateau.getVerrous(); + for (int i = 0; i < 6; i++) { + for (int j = 0; j < 6; j++) { + g[i * 6 + j] = grid[i][j]; + v[i * 6 + j] = lk[i][j]; + } } - - boolean resultat = !trouverSeries().isEmpty(); - - restaurerGrille(sauvegarde); - - return resultat; + b.putIntArray("grille", g); + b.putBooleanArray("verrous", v); + b.putInt("score", score); + b.putInt("nbCoups", nbCoups); + b.putBoolean("partieTerminee", partieTerminee); } - // - - // UTILITAIRES PRIVES - - - private int[][] copierGrille() { - int[][] copie = new int[NB_LIGNES][NB_COLONNES]; - - for (int l = 0; l < NB_LIGNES; l++) { - System.arraycopy(grille[l], 0, copie[l], 0, NB_COLONNES); + public void restaurerEtat(Bundle b) { + if (!b.containsKey("grille")) { + return; } - - return copie; - } - - private void restaurerGrille(int[][] sauvegarde) { - for (int l = 0; l < NB_LIGNES; l++) { - System.arraycopy(sauvegarde[l], 0, grille[l], 0, NB_COLONNES); + int[] g = b.getIntArray("grille"); + boolean[] v = b.getBooleanArray("verrous"); + int[][] grid = plateau.getGrille(); + boolean[][] lk = plateau.getVerrous(); + for (int i = 0; i < 6; i++) { + for (int j = 0; j < 6; j++) { + grid[i][j] = g[i * 6 + j]; + lk[i][j] = v[i * 6 + j]; + } } + score = b.getInt("score"); + nbCoups = b.getInt("nbCoups"); + partieTerminee = b.getBoolean("partieTerminee"); } - - }