MAJ - affichage verrous & EtatJeu
This commit is contained in:
@@ -21,6 +21,9 @@ public class EtatJeu {
|
||||
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
|
||||
|
||||
@@ -52,6 +55,10 @@ public class EtatJeu {
|
||||
return partieTerminee;
|
||||
}
|
||||
|
||||
public int[] getSeriesParCouleurDernierCoup() {
|
||||
return seriesParCouleurDernierCoup;
|
||||
}
|
||||
|
||||
// -
|
||||
// SAUVEGARDE ET RESTAURATION
|
||||
|
||||
@@ -214,6 +221,10 @@ public class EtatJeu {
|
||||
}
|
||||
|
||||
nbCoups++;
|
||||
|
||||
// Reset des séries du dernier coup
|
||||
for (int i = 0; i < NB_TYPES; i++) seriesParCouleurDernierCoup[i] = 0;
|
||||
|
||||
score += resoudreEtRemplir();
|
||||
|
||||
// Verrou après chaque coup ; 2 verrous en hard mode (plus difficile)
|
||||
@@ -297,7 +308,7 @@ public class EtatJeu {
|
||||
|
||||
public int resoudreEtRemplir() {
|
||||
int baseTotal = 0;
|
||||
int nbSeries = 0;
|
||||
int nbSeriesTotal = 0;
|
||||
|
||||
List<int[]> series = trouverSeries();
|
||||
|
||||
@@ -305,7 +316,11 @@ public class EtatJeu {
|
||||
|
||||
// Accumuler les points de base et le nombre de séries sur toutes les vagues
|
||||
baseTotal += calculerPointsBase(series);
|
||||
nbSeries += compterNbSeries(series);
|
||||
|
||||
// On compte les séries par couleur spécifiquement
|
||||
compterSeriesParCouleur(series);
|
||||
|
||||
nbSeriesTotal += compterNbSeries(series);
|
||||
|
||||
boolean[][] aSupprimer = new boolean[NB_LIGNES][NB_COLONNES];
|
||||
|
||||
@@ -342,13 +357,45 @@ public class EtatJeu {
|
||||
series = trouverSeries();
|
||||
}
|
||||
|
||||
if (nbSeries == 0) return 0;
|
||||
if (nbSeriesTotal == 0) return 0;
|
||||
|
||||
// Bonus : +50% par série supplémentaire après la première (spec SAÉ)
|
||||
double bonus = 1.0 + (nbSeries - 1) * 0.5;
|
||||
double bonus = 1.0 + (nbSeriesTotal - 1) * 0.5;
|
||||
return (int) (baseTotal * bonus);
|
||||
}
|
||||
|
||||
private void compterSeriesParCouleur(List<int[]> 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<int[]> series) {
|
||||
boolean[][] masque = new boolean[NB_LIGNES][NB_COLONNES];
|
||||
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
package sae.chuzzle;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.RectF;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
|
||||
@@ -10,9 +13,7 @@ import androidx.annotation.NonNull;
|
||||
|
||||
public class VueGrille extends View {
|
||||
|
||||
// =========================================================
|
||||
// Constantes
|
||||
// =========================================================
|
||||
|
||||
private static final int NB_LIGNES = 6;
|
||||
private static final int NB_COLONNES = 6;
|
||||
@@ -21,48 +22,30 @@ public class VueGrille extends View {
|
||||
/** Symboles pour le mode daltonien, un par type. */
|
||||
private static final String[] SYMBOLES = {"●", "■", "▲", "✚", "★", "♦", "✿"};
|
||||
|
||||
// =========================================================
|
||||
|
||||
// Données métier
|
||||
// =========================================================
|
||||
|
||||
/** Grille reçue depuis MainActivity (tableau brut). */
|
||||
private int[][] grille = new int[NB_LIGNES][NB_COLONNES];
|
||||
|
||||
/** Verrous reçus depuis MainActivity. */
|
||||
private boolean[][] verrous = new boolean[NB_LIGNES][NB_COLONNES];
|
||||
|
||||
private boolean modeDaltonien = false;
|
||||
|
||||
// =========================================================
|
||||
// État de l'animation de glissement
|
||||
// État du glissement
|
||||
// =========================================================
|
||||
|
||||
/**
|
||||
* true = on anime une ligne,
|
||||
* false = on anime une colonne,
|
||||
* null = pas d'animation en cours.
|
||||
*/
|
||||
private Boolean animEstLigne = null;
|
||||
|
||||
/** Index de la ligne ou colonne en cours de glissement. */
|
||||
private int animIndex = 0;
|
||||
|
||||
/**
|
||||
* Décalage courant en pixels (positif = droite/bas,
|
||||
* négatif = gauche/haut).
|
||||
*/
|
||||
private float animDecalagePx = 0f;
|
||||
|
||||
// =========================================================
|
||||
|
||||
// Outils de dessin
|
||||
// =========================================================
|
||||
|
||||
private final Paint pinceauCase = new Paint();
|
||||
private final Paint pinceauSymbole = new Paint();
|
||||
private final Paint pinceauSelection = new Paint();
|
||||
private Bitmap imageChaine;
|
||||
|
||||
// =========================================================
|
||||
// Constructeurs
|
||||
// =========================================================
|
||||
|
||||
public VueGrille(Context contexte) {
|
||||
super(contexte);
|
||||
@@ -81,17 +64,18 @@ public class VueGrille extends View {
|
||||
pinceauSymbole.setAntiAlias(true);
|
||||
pinceauSymbole.setColor(0xFF000000);
|
||||
pinceauSymbole.setTextAlign(Paint.Align.CENTER);
|
||||
|
||||
pinceauSelection.setAntiAlias(true);
|
||||
pinceauSelection.setStyle(Paint.Style.STROKE);
|
||||
pinceauSelection.setStrokeWidth(12f);
|
||||
pinceauSelection.setColor(0xFFFFFFFF);
|
||||
|
||||
// Chargement de l'image de la chaine
|
||||
imageChaine = BitmapFactory.decodeResource(getResources(), R.drawable.chaine);
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// API publique
|
||||
// =========================================================
|
||||
|
||||
/**
|
||||
* Reçoit une copie de la grille depuis MainActivity.
|
||||
* VueGrille ne sait pas d'où viennent ces données,
|
||||
* elle sait juste les dessiner.
|
||||
*/
|
||||
public void definirGrille(int[][] nouvelleGrille) {
|
||||
for (int l = 0; l < NB_LIGNES; l++) {
|
||||
System.arraycopy(nouvelleGrille[l], 0, grille[l], 0, NB_COLONNES);
|
||||
@@ -111,17 +95,9 @@ public class VueGrille extends View {
|
||||
invalidate();
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// API animation de glissement (appelée par GestionnaireTactile)
|
||||
// =========================================================
|
||||
|
||||
/**
|
||||
* Déclenche l'animation de glissement en temps réel.
|
||||
*
|
||||
* @param estLigne true = on déplace une ligne, false = une colonne
|
||||
* @param index index de la ligne ou colonne (0-based)
|
||||
* @param decalagePx décalage courant en pixels (peut être négatif)
|
||||
*/
|
||||
// API animation de glissement (appelée par GestionnaireTactile)
|
||||
|
||||
public void definirGlissement(boolean estLigne, int index, float decalagePx) {
|
||||
this.animEstLigne = estLigne;
|
||||
this.animIndex = index;
|
||||
@@ -129,22 +105,43 @@ public class VueGrille extends View {
|
||||
invalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Annule l'animation de glissement et revient à l'affichage normal.
|
||||
*/
|
||||
public void annulerGlissement() {
|
||||
this.animEstLigne = null;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
/**
|
||||
* Vérifie si la sélection actuelle (ligne ou colonne) contient au moins un verrou.
|
||||
*/
|
||||
private boolean estSelectionBloquee() {
|
||||
if (animEstLigne == null) return false;
|
||||
if (animEstLigne) {
|
||||
for (int c = 0; c < NB_COLONNES; c++) {
|
||||
if (verrous[animIndex][c]) return true;
|
||||
}
|
||||
} else {
|
||||
for (int l = 0; l < NB_LIGNES; l++) {
|
||||
if (verrous[l][animIndex]) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Dessin
|
||||
// =========================================================
|
||||
|
||||
@Override
|
||||
protected void onDraw(@NonNull Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
|
||||
// Mise à jour de la couleur du contour de sélection si bloqué
|
||||
if (animEstLigne != null) {
|
||||
if (estSelectionBloquee()) {
|
||||
pinceauSelection.setColor(0xFF000000); // Noir
|
||||
} else {
|
||||
pinceauSelection.setColor(0xFFFFFFFF); // Blanc
|
||||
}
|
||||
}
|
||||
|
||||
int largeur = getWidth();
|
||||
int hauteur = getHeight();
|
||||
|
||||
@@ -156,50 +153,41 @@ public class VueGrille extends View {
|
||||
float margeGauche = (largeur - tailleCase * NB_COLONNES) / 2f;
|
||||
float margeHaut = (hauteur - tailleCase * NB_LIGNES) / 2f;
|
||||
|
||||
// - On limite le dessin à la zone de la grille
|
||||
canvas.save();
|
||||
canvas.clipRect(margeGauche, margeHaut,
|
||||
margeGauche + NB_COLONNES * tailleCase,
|
||||
margeHaut + NB_LIGNES * tailleCase);
|
||||
|
||||
pinceauSymbole.setTextSize(tailleCase * 0.4f);
|
||||
|
||||
for (int ligne = 0; ligne < NB_LIGNES; ligne++) {
|
||||
for (int colonne = 0; colonne < NB_COLONNES; colonne++) {
|
||||
|
||||
// --------------------------------------------------
|
||||
// Calcul de l'offset d'animation pour cette case
|
||||
// --------------------------------------------------
|
||||
float offsetX = 0f;
|
||||
float offsetY = 0f;
|
||||
|
||||
if (animEstLigne != null) {
|
||||
int nbCases = Math.round(animDecalagePx / tailleCase);
|
||||
if (animEstLigne && ligne == animIndex) {
|
||||
// Décalage horizontal de toute la ligne
|
||||
offsetX = animDecalagePx;
|
||||
offsetX = nbCases * tailleCase;
|
||||
} else if (!animEstLigne && colonne == animIndex) {
|
||||
// Décalage vertical de toute la colonne
|
||||
offsetY = animDecalagePx;
|
||||
offsetY = nbCases * tailleCase;
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
// Position de base de la case
|
||||
// --------------------------------------------------
|
||||
float x1 = margeGauche + colonne * tailleCase + 6 + offsetX;
|
||||
float y1 = margeHaut + ligne * tailleCase + 6 + offsetY;
|
||||
float x2 = margeGauche + (colonne + 1) * tailleCase - 6 + offsetX;
|
||||
float y2 = margeHaut + (ligne + 1) * tailleCase - 6 + offsetY;
|
||||
|
||||
// --------------------------------------------------
|
||||
// Dessin avec wrap-around (la case qui sort d'un
|
||||
// côté réapparaît de l'autre côté)
|
||||
// --------------------------------------------------
|
||||
dessinerCase(canvas, ligne, colonne, x1, y1, x2, y2,
|
||||
tailleCase, margeGauche, margeHaut, offsetX, offsetY);
|
||||
}
|
||||
}
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
/**
|
||||
* Dessine une case à la position donnée.
|
||||
* Si la case sort des bords (wrap-around), elle est aussi dessinée
|
||||
* du côté opposé de la grille.
|
||||
*/
|
||||
private void dessinerCase(Canvas canvas,
|
||||
int ligne, int colonne,
|
||||
float x1, float y1, float x2, float y2,
|
||||
@@ -208,66 +196,50 @@ public class VueGrille extends View {
|
||||
float offsetX, float offsetY) {
|
||||
|
||||
int type = grille[ligne][colonne];
|
||||
|
||||
// Bornage de la grille (en pixels)
|
||||
float borneGaucheGrille = margeGauche;
|
||||
float bordDroiteGrille = margeGauche + NB_COLONNES * tailleCase;
|
||||
float borneHautGrille = margeHaut;
|
||||
float bordBasGrille = margeHaut + NB_LIGNES * tailleCase;
|
||||
|
||||
// Largeur totale de la ligne / hauteur totale de la colonne en pixels
|
||||
float largeurGrille = NB_COLONNES * tailleCase;
|
||||
float hauteurGrille = NB_LIGNES * tailleCase;
|
||||
|
||||
// Dessine la case principale
|
||||
// Dessin case principale
|
||||
dessinerRectCase(canvas, type, ligne, colonne, x1, y1, x2, y2);
|
||||
|
||||
// Wrap-around horizontal (pour les lignes)
|
||||
// --- Wrap-around (réapparition de l'autre côté) ---
|
||||
if (offsetX != 0f) {
|
||||
float wrapX1 = x1, wrapX2 = x2;
|
||||
|
||||
if (x2 > bordDroiteGrille) {
|
||||
// La case déborde à droite → réapparaît à gauche
|
||||
wrapX1 = x1 - largeurGrille;
|
||||
wrapX2 = x2 - largeurGrille;
|
||||
dessinerRectCase(canvas, type, ligne, colonne, wrapX1, y1, wrapX2, y2);
|
||||
} else if (x1 < borneGaucheGrille) {
|
||||
// La case déborde à gauche → réapparaît à droite
|
||||
wrapX1 = x1 + largeurGrille;
|
||||
wrapX2 = x2 + largeurGrille;
|
||||
dessinerRectCase(canvas, type, ligne, colonne, wrapX1, y1, wrapX2, y2);
|
||||
float bordD = margeGauche + largeurGrille;
|
||||
float bordG = margeGauche;
|
||||
if (x2 > bordD) {
|
||||
dessinerRectCase(canvas, type, ligne, colonne, x1 - largeurGrille, y1, x2 - largeurGrille, y2);
|
||||
} else if (x1 < bordG) {
|
||||
dessinerRectCase(canvas, type, ligne, colonne, x1 + largeurGrille, y1, x2 + largeurGrille, y2);
|
||||
}
|
||||
}
|
||||
|
||||
// Wrap-around vertical (pour les colonnes)
|
||||
if (offsetY != 0f) {
|
||||
float wrapY1 = y1, wrapY2 = y2;
|
||||
|
||||
if (y2 > bordBasGrille) {
|
||||
// La case déborde en bas → réapparaît en haut
|
||||
wrapY1 = y1 - hauteurGrille;
|
||||
wrapY2 = y2 - hauteurGrille;
|
||||
dessinerRectCase(canvas, type, ligne, colonne, x1, wrapY1, x2, wrapY2);
|
||||
} else if (y1 < borneHautGrille) {
|
||||
// La case déborde en haut → réapparaît en bas
|
||||
wrapY1 = y1 + hauteurGrille;
|
||||
wrapY2 = y2 + hauteurGrille;
|
||||
dessinerRectCase(canvas, type, ligne, colonne, x1, wrapY1, x2, wrapY2);
|
||||
float bordB = margeHaut + hauteurGrille;
|
||||
float bordH = margeHaut;
|
||||
if (y2 > bordB) {
|
||||
dessinerRectCase(canvas, type, ligne, colonne, x1, y1 - hauteurGrille, x2, y2 - hauteurGrille);
|
||||
} else if (y1 < bordH) {
|
||||
dessinerRectCase(canvas, type, ligne, colonne, x1, y1 + hauteurGrille, x2, y2 + hauteurGrille);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dessine le rectangle coloré d'une case + verrou + symbole daltonien.
|
||||
* Ajoute un contour gras si la case est sélectionnée.
|
||||
*/
|
||||
private void dessinerRectCase(Canvas canvas, int type,
|
||||
int ligne, int colonne,
|
||||
float x1, float y1, float x2, float y2) {
|
||||
|
||||
// Couleur de fond
|
||||
definirCouleur(type);
|
||||
canvas.drawRoundRect(x1, y1, x2, y2, 20, 20, pinceauCase);
|
||||
|
||||
if (animEstLigne != null) {
|
||||
if ((animEstLigne && ligne == animIndex) || (!animEstLigne && colonne == animIndex)) {
|
||||
canvas.drawRoundRect(x1, y1, x2, y2, 20, 20, pinceauSelection);
|
||||
}
|
||||
}
|
||||
|
||||
// Assombrir si verrouillée
|
||||
if (verrous[ligne][colonne]) {
|
||||
pinceauCase.setARGB(120, 0, 0, 0);
|
||||
@@ -275,24 +247,28 @@ public class VueGrille extends View {
|
||||
}
|
||||
|
||||
float cx = (x1 + x2) / 2f;
|
||||
float cy = (y1 + y2) / 2f
|
||||
- (pinceauSymbole.descent() + pinceauSymbole.ascent()) / 2f;
|
||||
float cy = (y1 + y2) / 2f - (pinceauSymbole.descent() + pinceauSymbole.ascent()) / 2f;
|
||||
|
||||
// Symbole daltonien
|
||||
if (modeDaltonien) {
|
||||
canvas.drawText(SYMBOLES[type % NB_TYPES], cx, cy, pinceauSymbole);
|
||||
}
|
||||
|
||||
// Cadenas par-dessus si verrouillée
|
||||
if (verrous[ligne][colonne]) {
|
||||
// Dessin de l'image de la chaine si verrouillée
|
||||
if (verrous[ligne][colonne] && imageChaine != null) {
|
||||
float size = (x2 - x1);
|
||||
float chainSize = size * 0.55f; // Taille de chaque morceau de chaine
|
||||
|
||||
// Dessin d'une chaine en haut à gauche
|
||||
canvas.drawBitmap(imageChaine, null, new RectF(x1, y1, x1 + chainSize, y1 + chainSize), null);
|
||||
|
||||
// Dessin d'une chaine en bas à droite
|
||||
canvas.drawBitmap(imageChaine, null, new RectF(x2 - chainSize, y2 - chainSize, x2, y2), null);
|
||||
} else if (verrous[ligne][colonne]) {
|
||||
// Fallback si l'image n'est pas trouvée
|
||||
canvas.drawText("🔒", cx, cy, pinceauSymbole);
|
||||
}
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// Utilitaire privé
|
||||
// =========================================================
|
||||
|
||||
private void definirCouleur(int type) {
|
||||
switch (type % NB_TYPES) {
|
||||
case 0: pinceauCase.setARGB(255, 200, 200, 200); break;
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 30 KiB |
Reference in New Issue
Block a user