package sae.chuzzle; import java.util.ArrayList; import java.util.List; import java.util.Random; 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 Random aleatoire; private int score = 0; private int nbCoups = 0; private boolean partieTerminee = false; private boolean hardMode = false; // ========================================================= // CONSTRUCTEURS // ========================================================= public EtatJeu() { aleatoire = new Random(); initialiserGrilleSansTriples(); } public EtatJeu(long graine, boolean hardMode) { aleatoire = new Random(graine); this.hardMode = hardMode; initialiserGrilleSansTriples(); } // ========================================================= // GETTERS // ========================================================= public int obtenirScore() { return score; } public int obtenirNbCoups() { return nbCoups; } public boolean estTerminee() { return 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; } 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); } 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 // ========================================================= public boolean appliquerCoup(boolean estLigne, int index, int sens) { if (partieTerminee) { return false; } if (hardMode && estBloque(estLigne, index)) { return false; } int[][] sauvegarde = copierGrille(); if (estLigne) { decalerLigne(index, sens); } else { decalerColonne(index, sens); } if (trouverSeries().isEmpty()) { restaurerGrille(sauvegarde); return false; } nbCoups++; score += resoudreEtRemplir(); if (hardMode) { ajouterVerrou(); } 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() { int pointsTotal = 0; int vague = 0; List series = trouverSeries(); while (!series.isEmpty()) { int pointsBase = calculerPointsBase(series); double multiplicateur = 1.0 + vague * 0.5; pointsTotal += (int) (pointsBase * multiplicateur); 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--; } } vague++; series = trouverSeries(); } return pointsTotal; } 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 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; } } } 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}); } } } if (casesLibres.isEmpty()) { return; } int[] caseChoisie = casesLibres.get(aleatoire.nextInt(casesLibres.size())); verrous[caseChoisie[0]][caseChoisie[1]] = true; } 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; } } } } // ========================================================= // DETECTION FIN DE PARTIE // ========================================================= public boolean aUnCoupValide() { for (int i = 0; i < NB_LIGNES; i++) { if (coupCreeSerie(true, i, +1)) { return true; } if (coupCreeSerie(true, i, -1)) { return true; } } for (int j = 0; j < NB_COLONNES; j++) { if (coupCreeSerie(false, j, +1)) { return true; } if (coupCreeSerie(false, j, -1)) { return true; } } return false; } private boolean coupCreeSerie(boolean estLigne, int index, int sens) { int[][] sauvegarde = copierGrille(); if (estLigne) { decalerLigne(index, sens); } else { decalerColonne(index, sens); } boolean resultat = !trouverSeries().isEmpty(); restaurerGrille(sauvegarde); return resultat; } // ========================================================= // 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); } 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); } } }