From 8283bc0475098ad11634efc4593cd7a1a9f270e2 Mon Sep 17 00:00:00 2001 From: val Date: Sun, 29 Mar 2026 18:17:36 +0200 Subject: [PATCH] =?UTF-8?q?R=C3=A9organisation=20du=20dossier?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 16 +- .idea/.gitignore | 3 + .idea/.name | 1 + .idea/AndroidProjectSystem.xml | 6 + .idea/compiler.xml | 6 + .idea/deploymentTargetSelector.xml | 26 + .idea/deviceManager.xml | 13 + .idea/gradle.xml | 19 + .idea/migrations.xml | 10 + .idea/misc.xml | 9 + .idea/runConfigurations.xml | 17 + app/.gitignore | 1 + app/build.gradle.kts | 42 ++ proguard-rules.pro => app/proguard-rules.pro | 0 .../sae/chuzzle/ExampleInstrumentedTest.java | 0 {src => app/src}/main/AndroidManifest.xml | 80 +-- .../main/java/sae/chuzzle/Controleur.java | 416 ++++++------- .../src}/main/java/sae/chuzzle/EtatJeu.java | 558 +++++++++--------- .../java/sae/chuzzle/FinPartieActivity.java | 0 .../java/sae/chuzzle/FinPartieControleur.java | 0 .../sae/chuzzle/GestionnaireObjectifs.java | 204 +++---- .../java/sae/chuzzle/GestionnaireTactile.java | 0 .../main/java/sae/chuzzle/MainActivity.java | 0 .../main/java/sae/chuzzle/MainController.java | 0 .../main/java/sae/chuzzle/MenuActivity.java | 0 .../main/java/sae/chuzzle/MenuController.java | 0 .../src}/main/java/sae/chuzzle/Objectif.java | 216 +++---- .../java/sae/chuzzle/OptionsActivity.java | 62 +- .../java/sae/chuzzle/OptionsController.java | 0 .../src}/main/java/sae/chuzzle/Plateau.java | 0 .../main/java/sae/chuzzle/SeedActivity.java | 128 ++-- .../src}/main/java/sae/chuzzle/VueGrille.java | 0 .../drawable-v24/ic_launcher_foreground.xml | 0 {src => app/src}/main/res/drawable/chaine.png | Bin .../res/drawable/ic_launcher_background.xml | 0 .../res/drawable/ic_launcher_foreground.xml | 0 .../main/res/layout/activity_fin_partie.xml | 0 .../src}/main/res/layout/activity_menu.xml | 0 .../src}/main/res/layout/activity_seed.xml | 0 .../res/mipmap-anydpi-v26/ic_launcher.xml | 0 .../mipmap-anydpi-v26/ic_launcher_round.xml | 0 .../main/res/mipmap-hdpi/ic_launcher.webp | Bin .../res/mipmap-hdpi/ic_launcher_round.webp | Bin .../main/res/mipmap-mdpi/ic_launcher.webp | Bin .../res/mipmap-mdpi/ic_launcher_round.webp | Bin .../main/res/mipmap-xhdpi/ic_launcher.webp | Bin .../res/mipmap-xhdpi/ic_launcher_round.webp | Bin .../main/res/mipmap-xxhdpi/ic_launcher.webp | Bin .../res/mipmap-xxhdpi/ic_launcher_round.webp | Bin .../main/res/mipmap-xxxhdpi/ic_launcher.webp | Bin .../res/mipmap-xxxhdpi/ic_launcher_round.webp | Bin .../src}/main/res/values-night/themes.xml | 0 {src => app/src}/main/res/values/colors.xml | 0 {src => app/src}/main/res/values/strings.xml | 0 {src => app/src}/main/res/values/themes.xml | 0 .../src}/main/res/xml/backup_rules.xml | 0 .../main/res/xml/data_extraction_rules.xml | 0 {src => app/src}/main/res/xml/preferences.xml | 0 .../java/sae/chuzzle/ExampleUnitTest.java | 0 build.gradle.kts | 42 +- gradle.properties | 21 + gradle/libs.versions.toml | 22 + gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 45457 bytes gradle/wrapper/gradle-wrapper.properties | 9 + gradlew | 251 ++++++++ gradlew.bat | 94 +++ settings.gradle.kts | 24 + src/main/res/layout/activity_main.xml | 93 --- src/main/res/layout/activity_options.xml | 69 --- 69 files changed, 1423 insertions(+), 1035 deletions(-) create mode 100644 .idea/.gitignore create mode 100644 .idea/.name create mode 100644 .idea/AndroidProjectSystem.xml create mode 100644 .idea/compiler.xml create mode 100644 .idea/deploymentTargetSelector.xml create mode 100644 .idea/deviceManager.xml create mode 100644 .idea/gradle.xml create mode 100644 .idea/migrations.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/runConfigurations.xml create mode 100644 app/.gitignore create mode 100644 app/build.gradle.kts rename proguard-rules.pro => app/proguard-rules.pro (100%) rename {src => app/src}/androidTest/java/sae/chuzzle/ExampleInstrumentedTest.java (100%) rename {src => app/src}/main/AndroidManifest.xml (97%) rename {src => app/src}/main/java/sae/chuzzle/Controleur.java (97%) rename {src => app/src}/main/java/sae/chuzzle/EtatJeu.java (96%) rename {src => app/src}/main/java/sae/chuzzle/FinPartieActivity.java (100%) rename {src => app/src}/main/java/sae/chuzzle/FinPartieControleur.java (100%) rename {src => app/src}/main/java/sae/chuzzle/GestionnaireObjectifs.java (96%) rename {src => app/src}/main/java/sae/chuzzle/GestionnaireTactile.java (100%) rename {src => app/src}/main/java/sae/chuzzle/MainActivity.java (100%) rename {src => app/src}/main/java/sae/chuzzle/MainController.java (100%) rename {src => app/src}/main/java/sae/chuzzle/MenuActivity.java (100%) rename {src => app/src}/main/java/sae/chuzzle/MenuController.java (100%) rename {src => app/src}/main/java/sae/chuzzle/Objectif.java (96%) rename {src => app/src}/main/java/sae/chuzzle/OptionsActivity.java (96%) rename {src => app/src}/main/java/sae/chuzzle/OptionsController.java (100%) rename {src => app/src}/main/java/sae/chuzzle/Plateau.java (100%) rename {src => app/src}/main/java/sae/chuzzle/SeedActivity.java (96%) rename {src => app/src}/main/java/sae/chuzzle/VueGrille.java (100%) rename {src => app/src}/main/res/drawable-v24/ic_launcher_foreground.xml (100%) rename {src => app/src}/main/res/drawable/chaine.png (100%) rename {src => app/src}/main/res/drawable/ic_launcher_background.xml (100%) rename {src => app/src}/main/res/drawable/ic_launcher_foreground.xml (100%) rename {src => app/src}/main/res/layout/activity_fin_partie.xml (100%) rename {src => app/src}/main/res/layout/activity_menu.xml (100%) rename {src => app/src}/main/res/layout/activity_seed.xml (100%) rename {src => app/src}/main/res/mipmap-anydpi-v26/ic_launcher.xml (100%) rename {src => app/src}/main/res/mipmap-anydpi-v26/ic_launcher_round.xml (100%) rename {src => app/src}/main/res/mipmap-hdpi/ic_launcher.webp (100%) rename {src => app/src}/main/res/mipmap-hdpi/ic_launcher_round.webp (100%) rename {src => app/src}/main/res/mipmap-mdpi/ic_launcher.webp (100%) rename {src => app/src}/main/res/mipmap-mdpi/ic_launcher_round.webp (100%) rename {src => app/src}/main/res/mipmap-xhdpi/ic_launcher.webp (100%) rename {src => app/src}/main/res/mipmap-xhdpi/ic_launcher_round.webp (100%) rename {src => app/src}/main/res/mipmap-xxhdpi/ic_launcher.webp (100%) rename {src => app/src}/main/res/mipmap-xxhdpi/ic_launcher_round.webp (100%) rename {src => app/src}/main/res/mipmap-xxxhdpi/ic_launcher.webp (100%) rename {src => app/src}/main/res/mipmap-xxxhdpi/ic_launcher_round.webp (100%) rename {src => app/src}/main/res/values-night/themes.xml (100%) rename {src => app/src}/main/res/values/colors.xml (100%) rename {src => app/src}/main/res/values/strings.xml (100%) rename {src => app/src}/main/res/values/themes.xml (100%) rename {src => app/src}/main/res/xml/backup_rules.xml (100%) rename {src => app/src}/main/res/xml/data_extraction_rules.xml (100%) rename {src => app/src}/main/res/xml/preferences.xml (100%) rename {src => app/src}/test/java/sae/chuzzle/ExampleUnitTest.java (100%) create mode 100644 gradle.properties create mode 100644 gradle/libs.versions.toml create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100644 gradlew create mode 100644 gradlew.bat create mode 100644 settings.gradle.kts delete mode 100644 src/main/res/layout/activity_main.xml delete mode 100644 src/main/res/layout/activity_options.xml diff --git a/.gitignore b/.gitignore index 42afabf..aa724b7 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,15 @@ -/build \ No newline at end of file +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild +.cxx +local.properties diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..8f9c6a1 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Real Chuzzle \ No newline at end of file diff --git a/.idea/AndroidProjectSystem.xml b/.idea/AndroidProjectSystem.xml new file mode 100644 index 0000000..4a53bee --- /dev/null +++ b/.idea/AndroidProjectSystem.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..b86273d --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml new file mode 100644 index 0000000..682aaf8 --- /dev/null +++ b/.idea/deploymentTargetSelector.xml @@ -0,0 +1,26 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/deviceManager.xml b/.idea/deviceManager.xml new file mode 100644 index 0000000..91f9558 --- /dev/null +++ b/.idea/deviceManager.xml @@ -0,0 +1,13 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..639c779 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/migrations.xml b/.idea/migrations.xml new file mode 100644 index 0000000..f8051a6 --- /dev/null +++ b/.idea/migrations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..b2c751a --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..16660f1 --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts new file mode 100644 index 0000000..882d8c5 --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,42 @@ +plugins { + alias(libs.plugins.android.application) +} + +android { + namespace = "sae.chuzzle" + compileSdk { + version = release(36) + } + + defaultConfig { + applicationId = "sae.chuzzle" + minSdk = 24 + targetSdk = 36 + versionCode = 1 + versionName = "1.0" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } +} + +dependencies { + + implementation(libs.activity) + testImplementation(libs.junit) + androidTestImplementation(libs.ext.junit) + androidTestImplementation(libs.espresso.core) +} \ No newline at end of file diff --git a/proguard-rules.pro b/app/proguard-rules.pro similarity index 100% rename from proguard-rules.pro rename to app/proguard-rules.pro diff --git a/src/androidTest/java/sae/chuzzle/ExampleInstrumentedTest.java b/app/src/androidTest/java/sae/chuzzle/ExampleInstrumentedTest.java similarity index 100% rename from src/androidTest/java/sae/chuzzle/ExampleInstrumentedTest.java rename to app/src/androidTest/java/sae/chuzzle/ExampleInstrumentedTest.java diff --git a/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml similarity index 97% rename from src/main/AndroidManifest.xml rename to app/src/main/AndroidManifest.xml index 34cdb93..63d5740 100644 --- a/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,41 +1,41 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/java/sae/chuzzle/Controleur.java b/app/src/main/java/sae/chuzzle/Controleur.java similarity index 97% rename from src/main/java/sae/chuzzle/Controleur.java rename to app/src/main/java/sae/chuzzle/Controleur.java index 74d2d82..6c96353 100644 --- a/src/main/java/sae/chuzzle/Controleur.java +++ b/app/src/main/java/sae/chuzzle/Controleur.java @@ -1,209 +1,209 @@ -package sae.chuzzle; - -import android.app.Activity; -import android.os.Bundle; -import android.view.View; -import android.widget.Button; -import android.widget.TextView; -import android.widget.Toast; - -public class Controleur { - - private final Activity activite; - private final EtatJeu etatJeu; - private final VueGrille vueGrille; - private final long graine; - - private final TextView tvScore; - private final TextView tvCoups; - - // Hard Mode logic - private final boolean hardMode; - private GestionnaireObjectifs gestionnaireObjectifs; - private Objectif objectifActuel; - private TextView tvObjectif; - private TextView tvNbObjectifs; - private TextView tvCles; - private Button btnReinitialisationObjectif; - private View layoutCles; - - public Controleur(Activity activite, EtatJeu etatJeu, VueGrille vueGrille, - long graine, TextView tvScore, TextView tvCoups, - boolean hardMode) { - - - - this.activite = activite; - this.etatJeu = etatJeu; - this.vueGrille = vueGrille; - this.graine = graine; - this.tvScore = tvScore; - this.tvCoups = tvCoups; - this.hardMode = hardMode; - - if (hardMode) { - this.gestionnaireObjectifs = new GestionnaireObjectifs(graine); - this.tvObjectif = activite.findViewById(R.id.tvObjectif); - this.tvNbObjectifs = activite.findViewById(R.id.tvNbObjectifs); - this.tvCles = activite.findViewById(R.id.tvCles); - this.layoutCles = activite.findViewById(R.id.layoutCles); - this.btnReinitialisationObjectif = activite.findViewById(R.id.btnReinitialisationObjectif); - - if (tvObjectif != null) tvObjectif.setVisibility(View.VISIBLE); - if (tvNbObjectifs != null) tvNbObjectifs.setVisibility(View.VISIBLE); - if (layoutCles != null) layoutCles.setVisibility(View.VISIBLE); - - - if (btnReinitialisationObjectif != null) { - btnReinitialisationObjectif.setOnClickListener(v -> reinitialiserObjectif()); - } - } - - - rafraichirAffichage(); - } - - - - /** - * Initialise l'objectif au début de la partie ou lors de la restauration. - */ - public void initialiserObjectif(Bundle savedState) { - if (!hardMode) return; - - gestionnaireObjectifs.restaurer(savedState); - objectifActuel = Objectif.restaurer(savedState); - - if (objectifActuel == null) { - objectifActuel = gestionnaireObjectifs.genererObjectif(); - } - rafraichirAffichage(); - } - - /** - * Gère la validation d'un coup réussi (mise à jour objectif, score, affichage). - * Centralise la logique pour être appelé par le bouton ET par le tactile. - */ - public void gererFinDeCoup() { - - // 1 clé tous les 5 coups - if (hardMode && etatJeu.obtenirNbCoups() % 5 == 0) { - gestionnaireObjectifs.ajouterCle(); - } - // --- Logique Hard Mode - if (hardMode && objectifActuel != null) { - // 1. Décrémenter les coups de l'objectif - objectifActuel.decrementerCoups(); - - // 2. Compter les séries de la couleur cible - int[] series = etatJeu.getSeriesParCouleurDernierCoup(); - objectifActuel.ajouterSeries(series[objectifActuel.getCouleur()]); - - // 3. Vérifier réussite ou échec - if (objectifActuel.estReussi()) { - - gestionnaireObjectifs.incrementerReussites(); - objectifActuel = gestionnaireObjectifs.genererObjectif(); - } else if (objectifActuel.estEchoue()) { - // Plus de coups disponibles et objectif non réussi -> fin de partie immédiate - Toast.makeText(activite, "Objectif échoué !", - Toast.LENGTH_SHORT - ).show(); - - etatJeu.forcerFinDePartie(); - - } - } - - rafraichirAffichage(); - verifierFinDePartie(); - } - - /** - * Tente de réinitialiser l'objectif en cours en consommant 3 clés. - * Affiche un Toast si le joueur n'a pas assez de clés. - */ - public void reinitialiserObjectif() { - if (!hardMode || gestionnaireObjectifs == null) return; - - if (gestionnaireObjectifs.consommerCles()) { - objectifActuel = gestionnaireObjectifs.genererObjectif(); - rafraichirAffichage(); - } else { - Toast.makeText(activite, "Pas assez de clés !", Toast.LENGTH_SHORT).show(); - } - } - - - /** - * Lancer l'écran de fin. - */ - public void verifierFinDePartie() { - int nbARetenir; - if (hardMode) { - nbARetenir = gestionnaireObjectifs.getNbObjectifsRealises(); - } else { - nbARetenir = 0; - } - - String description; - if (hardMode == true && objectifActuel != null) { - description = objectifActuel.getDescription(); - } else { - description = null; - } - - if (etatJeu.estTerminee()) { - FinPartieActivity.demarrer( - activite, - etatJeu.obtenirScore(), - etatJeu.obtenirNbCoups(), - graine, - nbARetenir, - description, - etatJeu.obtenirGrille(), - etatJeu.obtenirVerrous() - ); - } - } - - public void rafraichirAffichage() { - tvScore.setText("Score : " + etatJeu.obtenirScore()); - tvCoups.setText("Coups : " + etatJeu.obtenirNbCoups()); - vueGrille.definirGrille(etatJeu.obtenirGrille()); - vueGrille.definirVerrous(etatJeu.obtenirVerrous()); - - if (hardMode && objectifActuel != null) { - if (tvObjectif != null){ - tvObjectif.setText(objectifActuel.getDescription()); - } - if (tvNbObjectifs != null){ - tvNbObjectifs.setText("Objectifs réussis : " + gestionnaireObjectifs.getNbObjectifsRealises()); - } - - int nbCles = gestionnaireObjectifs.getNbCles(); - if (tvCles != null) { - tvCles.setText("🗝️ Clés : " + nbCles + " (Max 1)"); - } - if (btnReinitialisationObjectif != null) { - // Grisé si 0 clé - float alpha; - if (nbCles >= 1) { - alpha = 1f; // visible - } else { - alpha = 0.4f; // grisé - } - btnReinitialisationObjectif.setAlpha(alpha); - } - } - } - - public void sauvegarderEtat(Bundle out) { - if (hardMode) { - gestionnaireObjectifs.sauvegarder(out); - if (objectifActuel != null) { - objectifActuel.sauvegarder(out); - } - } - } +package sae.chuzzle; + +import android.app.Activity; +import android.os.Bundle; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; +import android.widget.Toast; + +public class Controleur { + + private final Activity activite; + private final EtatJeu etatJeu; + private final VueGrille vueGrille; + private final long graine; + + private final TextView tvScore; + private final TextView tvCoups; + + // Hard Mode logic + private final boolean hardMode; + private GestionnaireObjectifs gestionnaireObjectifs; + private Objectif objectifActuel; + private TextView tvObjectif; + private TextView tvNbObjectifs; + private TextView tvCles; + private Button btnReinitialisationObjectif; + private View layoutCles; + + public Controleur(Activity activite, EtatJeu etatJeu, VueGrille vueGrille, + long graine, TextView tvScore, TextView tvCoups, + boolean hardMode) { + + + + this.activite = activite; + this.etatJeu = etatJeu; + this.vueGrille = vueGrille; + this.graine = graine; + this.tvScore = tvScore; + this.tvCoups = tvCoups; + this.hardMode = hardMode; + + if (hardMode) { + this.gestionnaireObjectifs = new GestionnaireObjectifs(graine); + this.tvObjectif = activite.findViewById(R.id.tvObjectif); + this.tvNbObjectifs = activite.findViewById(R.id.tvNbObjectifs); + this.tvCles = activite.findViewById(R.id.tvCles); + this.layoutCles = activite.findViewById(R.id.layoutCles); + this.btnReinitialisationObjectif = activite.findViewById(R.id.btnReinitialisationObjectif); + + if (tvObjectif != null) tvObjectif.setVisibility(View.VISIBLE); + if (tvNbObjectifs != null) tvNbObjectifs.setVisibility(View.VISIBLE); + if (layoutCles != null) layoutCles.setVisibility(View.VISIBLE); + + + if (btnReinitialisationObjectif != null) { + btnReinitialisationObjectif.setOnClickListener(v -> reinitialiserObjectif()); + } + } + + + rafraichirAffichage(); + } + + + + /** + * Initialise l'objectif au début de la partie ou lors de la restauration. + */ + public void initialiserObjectif(Bundle savedState) { + if (!hardMode) return; + + gestionnaireObjectifs.restaurer(savedState); + objectifActuel = Objectif.restaurer(savedState); + + if (objectifActuel == null) { + objectifActuel = gestionnaireObjectifs.genererObjectif(); + } + rafraichirAffichage(); + } + + /** + * Gère la validation d'un coup réussi (mise à jour objectif, score, affichage). + * Centralise la logique pour être appelé par le bouton ET par le tactile. + */ + public void gererFinDeCoup() { + + // 1 clé tous les 5 coups + if (hardMode && etatJeu.obtenirNbCoups() % 5 == 0) { + gestionnaireObjectifs.ajouterCle(); + } + // --- Logique Hard Mode + if (hardMode && objectifActuel != null) { + // 1. Décrémenter les coups de l'objectif + objectifActuel.decrementerCoups(); + + // 2. Compter les séries de la couleur cible + int[] series = etatJeu.getSeriesParCouleurDernierCoup(); + objectifActuel.ajouterSeries(series[objectifActuel.getCouleur()]); + + // 3. Vérifier réussite ou échec + if (objectifActuel.estReussi()) { + + gestionnaireObjectifs.incrementerReussites(); + objectifActuel = gestionnaireObjectifs.genererObjectif(); + } else if (objectifActuel.estEchoue()) { + // Plus de coups disponibles et objectif non réussi -> fin de partie immédiate + Toast.makeText(activite, "Objectif échoué !", + Toast.LENGTH_SHORT + ).show(); + + etatJeu.forcerFinDePartie(); + + } + } + + rafraichirAffichage(); + verifierFinDePartie(); + } + + /** + * Tente de réinitialiser l'objectif en cours en consommant 3 clés. + * Affiche un Toast si le joueur n'a pas assez de clés. + */ + public void reinitialiserObjectif() { + if (!hardMode || gestionnaireObjectifs == null) return; + + if (gestionnaireObjectifs.consommerCles()) { + objectifActuel = gestionnaireObjectifs.genererObjectif(); + rafraichirAffichage(); + } else { + Toast.makeText(activite, "Pas assez de clés !", Toast.LENGTH_SHORT).show(); + } + } + + + /** + * Lancer l'écran de fin. + */ + public void verifierFinDePartie() { + int nbARetenir; + if (hardMode) { + nbARetenir = gestionnaireObjectifs.getNbObjectifsRealises(); + } else { + nbARetenir = 0; + } + + String description; + if (hardMode == true && objectifActuel != null) { + description = objectifActuel.getDescription(); + } else { + description = null; + } + + if (etatJeu.estTerminee()) { + FinPartieActivity.demarrer( + activite, + etatJeu.obtenirScore(), + etatJeu.obtenirNbCoups(), + graine, + nbARetenir, + description, + etatJeu.obtenirGrille(), + etatJeu.obtenirVerrous() + ); + } + } + + public void rafraichirAffichage() { + tvScore.setText("Score : " + etatJeu.obtenirScore()); + tvCoups.setText("Coups : " + etatJeu.obtenirNbCoups()); + vueGrille.definirGrille(etatJeu.obtenirGrille()); + vueGrille.definirVerrous(etatJeu.obtenirVerrous()); + + if (hardMode && objectifActuel != null) { + if (tvObjectif != null){ + tvObjectif.setText(objectifActuel.getDescription()); + } + if (tvNbObjectifs != null){ + tvNbObjectifs.setText("Objectifs réussis : " + gestionnaireObjectifs.getNbObjectifsRealises()); + } + + int nbCles = gestionnaireObjectifs.getNbCles(); + if (tvCles != null) { + tvCles.setText("🗝️ Clés : " + nbCles + " (Max 1)"); + } + if (btnReinitialisationObjectif != null) { + // Grisé si 0 clé + float alpha; + if (nbCles >= 1) { + alpha = 1f; // visible + } else { + alpha = 0.4f; // grisé + } + btnReinitialisationObjectif.setAlpha(alpha); + } + } + } + + public void sauvegarderEtat(Bundle out) { + if (hardMode) { + gestionnaireObjectifs.sauvegarder(out); + if (objectifActuel != null) { + objectifActuel.sauvegarder(out); + } + } + } } \ No newline at end of file diff --git a/src/main/java/sae/chuzzle/EtatJeu.java b/app/src/main/java/sae/chuzzle/EtatJeu.java similarity index 96% rename from src/main/java/sae/chuzzle/EtatJeu.java rename to app/src/main/java/sae/chuzzle/EtatJeu.java index 2f52c75..619a6a5 100644 --- a/src/main/java/sae/chuzzle/EtatJeu.java +++ b/app/src/main/java/sae/chuzzle/EtatJeu.java @@ -1,279 +1,279 @@ -package sae.chuzzle; - -import android.os.Bundle; -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 { - - 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 final int[] seriesParCouleurDernierCoup = new int[Plateau.NB_TYPES]; - - public EtatJeu(long graine, boolean hardMode) { - this.aleatoire = new Random(graine); - this.hardMode = hardMode; - this.plateau = new Plateau(this.aleatoire); - } - - // --- Getters --- - - public int obtenirScore() { - return score; - } - - public int obtenirNbCoups() { - return nbCoups; - } - - public boolean estTerminee() { - return partieTerminee; - } - - public int[] getSeriesParCouleurDernierCoup() { - return seriesParCouleurDernierCoup; - } - - public int[][] obtenirGrille() { - return plateau.copierGrille(); - } - - public boolean[][] obtenirVerrous() { - // 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; - } - - // --- Actions --- - - public boolean appliquerCoup(boolean estLigne, int index, int sens) { - if (partieTerminee || plateau.estBloque(estLigne, index)) { - return false; - } - - int[][] sauvegarde = plateau.copierGrille(); - if (estLigne) { - plateau.decalerLigne(index, sens); - } else { - plateau.decalerColonne(index, sens); - } - - if (plateau.trouverSeries().isEmpty()) { - plateau.restaurerGrille(sauvegarde); - return false; - } - - nbCoups++; - resetSeriesDernierCoup(); - score += resoudreCascades(); - - plateau.ajouterVerrou(nbCoups); - if (hardMode) { - plateau.ajouterVerrou(nbCoups); - } - - if (!aUnCoupValide()) { - partieTerminee = true; - } - return true; - } - - private int resoudreCascades() { - int baseTotal = 0; - int nbSeriesTotal = 0; - List series = plateau.trouverSeries(); - - while (!series.isEmpty()) { - int[] result = traiterSeries(series); - baseTotal += result[0]; - nbSeriesTotal += result[1]; - - boolean[][] masque = creerMasque(series); - plateau.libererVerrous(masque); - plateau.faireTomber(masque); - - series = plateau.trouverSeries(); - } - - if (nbSeriesTotal == 0) { - return 0; - } - return (int) (baseTotal * (1.0 + (nbSeriesTotal - 1) * 0.5)); - } - - // --- Aide à la résolution - - /** - * Parcourt les séries détectées, calcule les points de base et compte le nombre - * de séries. - * Vérifie la couleur des cellules pour délimiter correctement les séries. - * - * int[2] : [0] = points de base, [1] = nombre de séries - */ - private int[] traiterSeries(List series) { - boolean[][] masque = creerMasque(series); - int[][] g = plateau.getGrille(); - int pts = 0; - int count = 0; - - // Horizontal - for (int l = 0; l < Plateau.NB_LIGNES; l++) { - int c = 0; - while (c < Plateau.NB_COLONNES) { - if (masque[l][c]) { - int type = g[l][c]; - int fin = c + 1; - while (fin < Plateau.NB_COLONNES && masque[l][fin] && g[l][fin] == type) { - fin++; - } - if (fin - c >= 3) { - pts += pointsPourLongueur(fin - c); - seriesParCouleurDernierCoup[type]++; - count++; - } - c = fin; - } else { - c++; - } - } - } - // Vertical - for (int c = 0; c < Plateau.NB_COLONNES; c++) { - int l = 0; - while (l < Plateau.NB_LIGNES) { - if (masque[l][c]) { - int type = g[l][c]; - int fin = l + 1; - while (fin < Plateau.NB_LIGNES && masque[fin][c] && g[fin][c] == type) { - fin++; - } - if (fin - l >= 3) { - pts += pointsPourLongueur(fin - l); - seriesParCouleurDernierCoup[type]++; - count++; - } - l = fin; - } else { - l++; - } - } - } - return new int[] { pts, count }; - } - - private int pointsPourLongueur(int n) { - if (n == 3) - return 8; - if (n == 4) - return 16; - if (n == 5) - return 32; - return 64; - } - - 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() { - 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; - } - } - } - 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() { - partieTerminee = true; - } - - 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 < Plateau.NB_LIGNES; i++) { - for (int j = 0; j < Plateau.NB_COLONNES; j++) { - g[i * Plateau.NB_LIGNES + j] = grid[i][j]; - v[i * Plateau.NB_LIGNES + j] = lk[i][j]; - } - } - b.putIntArray("grille", g); - b.putBooleanArray("verrous", v); - b.putInt("score", score); - b.putInt("nbCoups", nbCoups); - b.putBoolean("partieTerminee", partieTerminee); - } - - public void restaurerEtat(Bundle b) { - if (!b.containsKey("grille")) { - return; - } - int[] g = b.getIntArray("grille"); - boolean[] v = b.getBooleanArray("verrous"); - int[][] grid = plateau.getGrille(); - boolean[][] lk = plateau.getVerrous(); - for (int i = 0; i < Plateau.NB_LIGNES; i++) { - for (int j = 0; j < Plateau.NB_COLONNES; j++) { - grid[i][j] = g[i * Plateau.NB_LIGNES + j]; - lk[i][j] = v[i * Plateau.NB_LIGNES + j]; - } - } - score = b.getInt("score"); - nbCoups = b.getInt("nbCoups"); - partieTerminee = b.getBoolean("partieTerminee"); - } -} +package sae.chuzzle; + +import android.os.Bundle; +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 { + + 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 final int[] seriesParCouleurDernierCoup = new int[Plateau.NB_TYPES]; + + public EtatJeu(long graine, boolean hardMode) { + this.aleatoire = new Random(graine); + this.hardMode = hardMode; + this.plateau = new Plateau(this.aleatoire); + } + + // --- Getters --- + + public int obtenirScore() { + return score; + } + + public int obtenirNbCoups() { + return nbCoups; + } + + public boolean estTerminee() { + return partieTerminee; + } + + public int[] getSeriesParCouleurDernierCoup() { + return seriesParCouleurDernierCoup; + } + + public int[][] obtenirGrille() { + return plateau.copierGrille(); + } + + public boolean[][] obtenirVerrous() { + // 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; + } + + // --- Actions --- + + public boolean appliquerCoup(boolean estLigne, int index, int sens) { + if (partieTerminee || plateau.estBloque(estLigne, index)) { + return false; + } + + int[][] sauvegarde = plateau.copierGrille(); + if (estLigne) { + plateau.decalerLigne(index, sens); + } else { + plateau.decalerColonne(index, sens); + } + + if (plateau.trouverSeries().isEmpty()) { + plateau.restaurerGrille(sauvegarde); + return false; + } + + nbCoups++; + resetSeriesDernierCoup(); + score += resoudreCascades(); + + plateau.ajouterVerrou(nbCoups); + if (hardMode) { + plateau.ajouterVerrou(nbCoups); + } + + if (!aUnCoupValide()) { + partieTerminee = true; + } + return true; + } + + private int resoudreCascades() { + int baseTotal = 0; + int nbSeriesTotal = 0; + List series = plateau.trouverSeries(); + + while (!series.isEmpty()) { + int[] result = traiterSeries(series); + baseTotal += result[0]; + nbSeriesTotal += result[1]; + + boolean[][] masque = creerMasque(series); + plateau.libererVerrous(masque); + plateau.faireTomber(masque); + + series = plateau.trouverSeries(); + } + + if (nbSeriesTotal == 0) { + return 0; + } + return (int) (baseTotal * (1.0 + (nbSeriesTotal - 1) * 0.5)); + } + + // --- Aide à la résolution + + /** + * Parcourt les séries détectées, calcule les points de base et compte le nombre + * de séries. + * Vérifie la couleur des cellules pour délimiter correctement les séries. + * + * int[2] : [0] = points de base, [1] = nombre de séries + */ + private int[] traiterSeries(List series) { + boolean[][] masque = creerMasque(series); + int[][] g = plateau.getGrille(); + int pts = 0; + int count = 0; + + // Horizontal + for (int l = 0; l < Plateau.NB_LIGNES; l++) { + int c = 0; + while (c < Plateau.NB_COLONNES) { + if (masque[l][c]) { + int type = g[l][c]; + int fin = c + 1; + while (fin < Plateau.NB_COLONNES && masque[l][fin] && g[l][fin] == type) { + fin++; + } + if (fin - c >= 3) { + pts += pointsPourLongueur(fin - c); + seriesParCouleurDernierCoup[type]++; + count++; + } + c = fin; + } else { + c++; + } + } + } + // Vertical + for (int c = 0; c < Plateau.NB_COLONNES; c++) { + int l = 0; + while (l < Plateau.NB_LIGNES) { + if (masque[l][c]) { + int type = g[l][c]; + int fin = l + 1; + while (fin < Plateau.NB_LIGNES && masque[fin][c] && g[fin][c] == type) { + fin++; + } + if (fin - l >= 3) { + pts += pointsPourLongueur(fin - l); + seriesParCouleurDernierCoup[type]++; + count++; + } + l = fin; + } else { + l++; + } + } + } + return new int[] { pts, count }; + } + + private int pointsPourLongueur(int n) { + if (n == 3) + return 8; + if (n == 4) + return 16; + if (n == 5) + return 32; + return 64; + } + + 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() { + 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; + } + } + } + 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() { + partieTerminee = true; + } + + 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 < Plateau.NB_LIGNES; i++) { + for (int j = 0; j < Plateau.NB_COLONNES; j++) { + g[i * Plateau.NB_LIGNES + j] = grid[i][j]; + v[i * Plateau.NB_LIGNES + j] = lk[i][j]; + } + } + b.putIntArray("grille", g); + b.putBooleanArray("verrous", v); + b.putInt("score", score); + b.putInt("nbCoups", nbCoups); + b.putBoolean("partieTerminee", partieTerminee); + } + + public void restaurerEtat(Bundle b) { + if (!b.containsKey("grille")) { + return; + } + int[] g = b.getIntArray("grille"); + boolean[] v = b.getBooleanArray("verrous"); + int[][] grid = plateau.getGrille(); + boolean[][] lk = plateau.getVerrous(); + for (int i = 0; i < Plateau.NB_LIGNES; i++) { + for (int j = 0; j < Plateau.NB_COLONNES; j++) { + grid[i][j] = g[i * Plateau.NB_LIGNES + j]; + lk[i][j] = v[i * Plateau.NB_LIGNES + j]; + } + } + score = b.getInt("score"); + nbCoups = b.getInt("nbCoups"); + partieTerminee = b.getBoolean("partieTerminee"); + } +} diff --git a/src/main/java/sae/chuzzle/FinPartieActivity.java b/app/src/main/java/sae/chuzzle/FinPartieActivity.java similarity index 100% rename from src/main/java/sae/chuzzle/FinPartieActivity.java rename to app/src/main/java/sae/chuzzle/FinPartieActivity.java diff --git a/src/main/java/sae/chuzzle/FinPartieControleur.java b/app/src/main/java/sae/chuzzle/FinPartieControleur.java similarity index 100% rename from src/main/java/sae/chuzzle/FinPartieControleur.java rename to app/src/main/java/sae/chuzzle/FinPartieControleur.java diff --git a/src/main/java/sae/chuzzle/GestionnaireObjectifs.java b/app/src/main/java/sae/chuzzle/GestionnaireObjectifs.java similarity index 96% rename from src/main/java/sae/chuzzle/GestionnaireObjectifs.java rename to app/src/main/java/sae/chuzzle/GestionnaireObjectifs.java index 9f24c52..f304a84 100644 --- a/src/main/java/sae/chuzzle/GestionnaireObjectifs.java +++ b/app/src/main/java/sae/chuzzle/GestionnaireObjectifs.java @@ -1,102 +1,102 @@ -package sae.chuzzle; - -import android.os.Bundle; -import java.util.ArrayList; -import java.util.List; -import java.util.Random; - -/** - * Gère la génération aléatoire et le comptage des objectifs. - */ -public class GestionnaireObjectifs { - private final Random random; - private int nbObjectifsRealises = 0; - private int nbCles = 0; - - public GestionnaireObjectifs(long graine) { - - this.random = new Random(graine); - } - - /** - * Génère un nouvel objectif en respectant les probabilités de difficulté. - */ - public Objectif genererObjectif() { - List pool = new ArrayList<>(); - int totalPoids = 0; - - // M (nbCoupsMax) entre 2 et 5. - // N (nbSeriesCible) tel que M - N >= 1 et N <= 3. - for (int m = 2; m <= 5; m++) { - for (int n = 1; n <= m - 1 && n <= 3; n++) { - // Probabilité inversement proportionnelle à la facilité (M-N). - // Plus (M-N) est petit, plus c'est dur. - int diff = m - n; - int poids = diff * diff; // On utilise le carré pour accentuer la différence de probabilité - - for (int color = 0; color < 7; color++) { - pool.add(new Objectif(color, n, m, poids)); - totalPoids += poids; - } - } - } - - if (totalPoids == 0) return null; - - int tirage = random.nextInt(totalPoids); - int cumul = 0; - for (Objectif obj : pool) { - cumul += obj.getPoids(); - if (tirage < cumul) { - return new Objectif(obj.getCouleur(), obj.getNbSeriesCible(), obj.getNbCoupsMax(), obj.getPoids()); - } - } - return pool.get(0); - } - - public void incrementerReussites() { - nbObjectifsRealises++; - // 1 clé gagnée tous les 2 objectifs réussis, maximum 1 clés en stock - if (nbObjectifsRealises % 2 == 0) { - ajouterCle(); - } - } - - public int getNbCles() { - return nbCles; - } - - public void ajouterCle() { - // Ajoute une clé maximum 1 en stock - nbCles = Math.min(nbCles + 1, 1); - } - - /** - * Consomme 1 clé pour réinitialiser l'objectif. - */ - public boolean consommerCles() { - if (nbCles >= 1) { - nbCles -= 1; - return true; - } - return false; - } - - public int getNbObjectifsRealises() { - - return nbObjectifsRealises; - } - - public void sauvegarder(Bundle out) { - out.putInt("nb_objectifs_total", nbObjectifsRealises); - out.putInt("nb_cles", nbCles); - } - - public void restaurer(Bundle in) { - if (in != null) { - nbObjectifsRealises = in.getInt("nb_objectifs_total", 0); - nbCles = in.getInt("nb_cles", 0); - } - } -} - +package sae.chuzzle; + +import android.os.Bundle; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +/** + * Gère la génération aléatoire et le comptage des objectifs. + */ +public class GestionnaireObjectifs { + private final Random random; + private int nbObjectifsRealises = 0; + private int nbCles = 0; + + public GestionnaireObjectifs(long graine) { + + this.random = new Random(graine); + } + + /** + * Génère un nouvel objectif en respectant les probabilités de difficulté. + */ + public Objectif genererObjectif() { + List pool = new ArrayList<>(); + int totalPoids = 0; + + // M (nbCoupsMax) entre 2 et 5. + // N (nbSeriesCible) tel que M - N >= 1 et N <= 3. + for (int m = 2; m <= 5; m++) { + for (int n = 1; n <= m - 1 && n <= 3; n++) { + // Probabilité inversement proportionnelle à la facilité (M-N). + // Plus (M-N) est petit, plus c'est dur. + int diff = m - n; + int poids = diff * diff; // On utilise le carré pour accentuer la différence de probabilité + + for (int color = 0; color < 7; color++) { + pool.add(new Objectif(color, n, m, poids)); + totalPoids += poids; + } + } + } + + if (totalPoids == 0) return null; + + int tirage = random.nextInt(totalPoids); + int cumul = 0; + for (Objectif obj : pool) { + cumul += obj.getPoids(); + if (tirage < cumul) { + return new Objectif(obj.getCouleur(), obj.getNbSeriesCible(), obj.getNbCoupsMax(), obj.getPoids()); + } + } + return pool.get(0); + } + + public void incrementerReussites() { + nbObjectifsRealises++; + // 1 clé gagnée tous les 2 objectifs réussis, maximum 1 clés en stock + if (nbObjectifsRealises % 2 == 0) { + ajouterCle(); + } + } + + public int getNbCles() { + return nbCles; + } + + public void ajouterCle() { + // Ajoute une clé maximum 1 en stock + nbCles = Math.min(nbCles + 1, 1); + } + + /** + * Consomme 1 clé pour réinitialiser l'objectif. + */ + public boolean consommerCles() { + if (nbCles >= 1) { + nbCles -= 1; + return true; + } + return false; + } + + public int getNbObjectifsRealises() { + + return nbObjectifsRealises; + } + + public void sauvegarder(Bundle out) { + out.putInt("nb_objectifs_total", nbObjectifsRealises); + out.putInt("nb_cles", nbCles); + } + + public void restaurer(Bundle in) { + if (in != null) { + nbObjectifsRealises = in.getInt("nb_objectifs_total", 0); + nbCles = in.getInt("nb_cles", 0); + } + } +} + diff --git a/src/main/java/sae/chuzzle/GestionnaireTactile.java b/app/src/main/java/sae/chuzzle/GestionnaireTactile.java similarity index 100% rename from src/main/java/sae/chuzzle/GestionnaireTactile.java rename to app/src/main/java/sae/chuzzle/GestionnaireTactile.java diff --git a/src/main/java/sae/chuzzle/MainActivity.java b/app/src/main/java/sae/chuzzle/MainActivity.java similarity index 100% rename from src/main/java/sae/chuzzle/MainActivity.java rename to app/src/main/java/sae/chuzzle/MainActivity.java diff --git a/src/main/java/sae/chuzzle/MainController.java b/app/src/main/java/sae/chuzzle/MainController.java similarity index 100% rename from src/main/java/sae/chuzzle/MainController.java rename to app/src/main/java/sae/chuzzle/MainController.java diff --git a/src/main/java/sae/chuzzle/MenuActivity.java b/app/src/main/java/sae/chuzzle/MenuActivity.java similarity index 100% rename from src/main/java/sae/chuzzle/MenuActivity.java rename to app/src/main/java/sae/chuzzle/MenuActivity.java diff --git a/src/main/java/sae/chuzzle/MenuController.java b/app/src/main/java/sae/chuzzle/MenuController.java similarity index 100% rename from src/main/java/sae/chuzzle/MenuController.java rename to app/src/main/java/sae/chuzzle/MenuController.java diff --git a/src/main/java/sae/chuzzle/Objectif.java b/app/src/main/java/sae/chuzzle/Objectif.java similarity index 96% rename from src/main/java/sae/chuzzle/Objectif.java rename to app/src/main/java/sae/chuzzle/Objectif.java index 5de6d1c..9e50e08 100644 --- a/src/main/java/sae/chuzzle/Objectif.java +++ b/app/src/main/java/sae/chuzzle/Objectif.java @@ -1,108 +1,108 @@ -package sae.chuzzle; - -import android.os.Bundle; - -/** - * Représente un objectif dynamique pour le mode Hard. - */ -public class Objectif { - private final int couleur; // Index de la couleur cible (0-6) - private final int nbSeriesCible; // Nombre de séries à réaliser - private final int nbCoupsMax; // Limite de coups à faire - private final int poids; // Probabilité d'apparition (poids pour le tirage) - - private int seriesRealisees = 0; - private int coupsRestants; - - public Objectif(int couleur, int nbSeries, int nbCoupsMax, int poids) { - this.couleur = couleur; - this.nbSeriesCible = nbSeries; - this.nbCoupsMax = nbCoupsMax; - this.coupsRestants = nbCoupsMax; - this.poids = poids; - } - - // Getters - public int getCouleur() { - return couleur; - } - public int getNbSeriesCible() { - - return nbSeriesCible; - } - public int getNbCoupsMax() { - return nbCoupsMax; - } - - public int getCoupsRestants() { - return coupsRestants; - - } - public int getPoids() { - return poids; - - } - - public void decrementerCoups() { - - if (coupsRestants > 0) coupsRestants--; - } - - public void ajouterSeries(int n) { - - this.seriesRealisees += n; - } - - public boolean estReussi() { - - return seriesRealisees >= nbSeriesCible; - } - - public boolean estEchoue() { - - return coupsRestants <= 0 && !estReussi(); - } - - public String getDescription() { - String nomCouleur = obtenirNomCouleur(couleur); - return "Éclatez " + nbSeriesCible + " fois des Chuzzle " + nomCouleur + - " en moins de " + nbCoupsMax + " coups (" + seriesRealisees + "/" + nbSeriesCible + - ").\nCoups restants : " + coupsRestants; - } - - private String obtenirNomCouleur(int c) { - switch (c) { - case 0: return "Gris"; - case 1: return "Rose"; - case 2: return "Vert"; - case 3: return "Bleu"; - case 4: return "Jaune"; - case 5: return "Orange"; - case 6: return "Rouge"; - default: return "Inconnue"; - } - } - - // Persistance pour la rotation d'écran - public void sauvegarder(Bundle out) { - out.putInt("obj_couleur", couleur); - out.putInt("obj_cible", nbSeriesCible); - out.putInt("obj_max", nbCoupsMax); - out.putInt("obj_restants", coupsRestants); - out.putInt("obj_realise", seriesRealisees); - out.putInt("obj_poids", poids); - } - - public static Objectif restaurer(Bundle in) { - if (in == null || !in.containsKey("obj_couleur")) return null; - Objectif obj = new Objectif( - in.getInt("obj_couleur"), - in.getInt("obj_cible"), - in.getInt("obj_max"), - in.getInt("obj_poids") - ); - obj.coupsRestants = in.getInt("obj_restants"); - obj.seriesRealisees = in.getInt("obj_realise"); - return obj; - } -} +package sae.chuzzle; + +import android.os.Bundle; + +/** + * Représente un objectif dynamique pour le mode Hard. + */ +public class Objectif { + private final int couleur; // Index de la couleur cible (0-6) + private final int nbSeriesCible; // Nombre de séries à réaliser + private final int nbCoupsMax; // Limite de coups à faire + private final int poids; // Probabilité d'apparition (poids pour le tirage) + + private int seriesRealisees = 0; + private int coupsRestants; + + public Objectif(int couleur, int nbSeries, int nbCoupsMax, int poids) { + this.couleur = couleur; + this.nbSeriesCible = nbSeries; + this.nbCoupsMax = nbCoupsMax; + this.coupsRestants = nbCoupsMax; + this.poids = poids; + } + + // Getters + public int getCouleur() { + return couleur; + } + public int getNbSeriesCible() { + + return nbSeriesCible; + } + public int getNbCoupsMax() { + return nbCoupsMax; + } + + public int getCoupsRestants() { + return coupsRestants; + + } + public int getPoids() { + return poids; + + } + + public void decrementerCoups() { + + if (coupsRestants > 0) coupsRestants--; + } + + public void ajouterSeries(int n) { + + this.seriesRealisees += n; + } + + public boolean estReussi() { + + return seriesRealisees >= nbSeriesCible; + } + + public boolean estEchoue() { + + return coupsRestants <= 0 && !estReussi(); + } + + public String getDescription() { + String nomCouleur = obtenirNomCouleur(couleur); + return "Éclatez " + nbSeriesCible + " fois des Chuzzle " + nomCouleur + + " en moins de " + nbCoupsMax + " coups (" + seriesRealisees + "/" + nbSeriesCible + + ").\nCoups restants : " + coupsRestants; + } + + private String obtenirNomCouleur(int c) { + switch (c) { + case 0: return "Gris"; + case 1: return "Rose"; + case 2: return "Vert"; + case 3: return "Bleu"; + case 4: return "Jaune"; + case 5: return "Orange"; + case 6: return "Rouge"; + default: return "Inconnue"; + } + } + + // Persistance pour la rotation d'écran + public void sauvegarder(Bundle out) { + out.putInt("obj_couleur", couleur); + out.putInt("obj_cible", nbSeriesCible); + out.putInt("obj_max", nbCoupsMax); + out.putInt("obj_restants", coupsRestants); + out.putInt("obj_realise", seriesRealisees); + out.putInt("obj_poids", poids); + } + + public static Objectif restaurer(Bundle in) { + if (in == null || !in.containsKey("obj_couleur")) return null; + Objectif obj = new Objectif( + in.getInt("obj_couleur"), + in.getInt("obj_cible"), + in.getInt("obj_max"), + in.getInt("obj_poids") + ); + obj.coupsRestants = in.getInt("obj_restants"); + obj.seriesRealisees = in.getInt("obj_realise"); + return obj; + } +} diff --git a/src/main/java/sae/chuzzle/OptionsActivity.java b/app/src/main/java/sae/chuzzle/OptionsActivity.java similarity index 96% rename from src/main/java/sae/chuzzle/OptionsActivity.java rename to app/src/main/java/sae/chuzzle/OptionsActivity.java index 82783fa..e68419e 100644 --- a/src/main/java/sae/chuzzle/OptionsActivity.java +++ b/app/src/main/java/sae/chuzzle/OptionsActivity.java @@ -1,31 +1,31 @@ -package sae.chuzzle; - -import android.app.Activity; -import android.content.SharedPreferences; -import android.os.Bundle; -import android.widget.Button; -import android.widget.CheckBox; - -public class OptionsActivity extends Activity { - - private SharedPreferences prefs; - private CheckBox checkHard; - private Button btnRetour; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_options); - - prefs = getSharedPreferences("chuzzle_prefs", MODE_PRIVATE); - - checkHard = findViewById(R.id.checkHard); - btnRetour = findViewById(R.id.btnBack); - - checkHard.setChecked(prefs.getBoolean("hard_mode", false)); - - OptionsController controller = new OptionsController(this, prefs); - checkHard.setOnCheckedChangeListener(controller); - btnRetour.setOnClickListener(controller); - } -} +package sae.chuzzle; + +import android.app.Activity; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.widget.Button; +import android.widget.CheckBox; + +public class OptionsActivity extends Activity { + + private SharedPreferences prefs; + private CheckBox checkHard; + private Button btnRetour; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_options); + + prefs = getSharedPreferences("chuzzle_prefs", MODE_PRIVATE); + + checkHard = findViewById(R.id.checkHard); + btnRetour = findViewById(R.id.btnBack); + + checkHard.setChecked(prefs.getBoolean("hard_mode", false)); + + OptionsController controller = new OptionsController(this, prefs); + checkHard.setOnCheckedChangeListener(controller); + btnRetour.setOnClickListener(controller); + } +} diff --git a/src/main/java/sae/chuzzle/OptionsController.java b/app/src/main/java/sae/chuzzle/OptionsController.java similarity index 100% rename from src/main/java/sae/chuzzle/OptionsController.java rename to app/src/main/java/sae/chuzzle/OptionsController.java diff --git a/src/main/java/sae/chuzzle/Plateau.java b/app/src/main/java/sae/chuzzle/Plateau.java similarity index 100% rename from src/main/java/sae/chuzzle/Plateau.java rename to app/src/main/java/sae/chuzzle/Plateau.java diff --git a/src/main/java/sae/chuzzle/SeedActivity.java b/app/src/main/java/sae/chuzzle/SeedActivity.java similarity index 96% rename from src/main/java/sae/chuzzle/SeedActivity.java rename to app/src/main/java/sae/chuzzle/SeedActivity.java index fd82310..3146351 100644 --- a/src/main/java/sae/chuzzle/SeedActivity.java +++ b/app/src/main/java/sae/chuzzle/SeedActivity.java @@ -1,65 +1,65 @@ -package sae.chuzzle; - -import android.app.Activity; -import android.content.Intent; -import android.os.Bundle; -import android.view.View; -import android.widget.Button; -import android.widget.EditText; -import android.widget.Toast; - -public class SeedActivity extends Activity implements View.OnClickListener { - - private EditText etGraine; - private Button btnJouer; - - private Button btnRetour; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_seed); - - etGraine = findViewById(R.id.etGraine); - btnJouer = findViewById(R.id.btnJouer); - btnRetour = findViewById(R.id.btnBack); - - btnRetour.setOnClickListener(this); - - btnJouer.setOnClickListener(this); - } - - @Override - public void onClick(View v) { - if (v == btnJouer) { - lancerPartieAvecGraine(); - } - if (v == btnRetour) { - Intent intent = new Intent(this, MenuActivity.class); - startActivity(intent); - } - } - - private void lancerPartieAvecGraine() { - String texte = etGraine.getText().toString().trim(); - - if (texte.isEmpty()) { - Toast.makeText(this, "Veuillez entrer une graine.", - Toast.LENGTH_SHORT - ).show(); - return; - } - - long graine; - - try { - graine = Long.parseLong(texte); - } catch (NumberFormatException e) { - graine = texte.hashCode(); - } - - Intent intent = new Intent(this, MainActivity.class); - intent.putExtra("graine", graine); - startActivity(intent); - } +package sae.chuzzle; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.Toast; + +public class SeedActivity extends Activity implements View.OnClickListener { + + private EditText etGraine; + private Button btnJouer; + + private Button btnRetour; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_seed); + + etGraine = findViewById(R.id.etGraine); + btnJouer = findViewById(R.id.btnJouer); + btnRetour = findViewById(R.id.btnBack); + + btnRetour.setOnClickListener(this); + + btnJouer.setOnClickListener(this); + } + + @Override + public void onClick(View v) { + if (v == btnJouer) { + lancerPartieAvecGraine(); + } + if (v == btnRetour) { + Intent intent = new Intent(this, MenuActivity.class); + startActivity(intent); + } + } + + private void lancerPartieAvecGraine() { + String texte = etGraine.getText().toString().trim(); + + if (texte.isEmpty()) { + Toast.makeText(this, "Veuillez entrer une graine.", + Toast.LENGTH_SHORT + ).show(); + return; + } + + long graine; + + try { + graine = Long.parseLong(texte); + } catch (NumberFormatException e) { + graine = texte.hashCode(); + } + + Intent intent = new Intent(this, MainActivity.class); + intent.putExtra("graine", graine); + startActivity(intent); + } } \ No newline at end of file diff --git a/src/main/java/sae/chuzzle/VueGrille.java b/app/src/main/java/sae/chuzzle/VueGrille.java similarity index 100% rename from src/main/java/sae/chuzzle/VueGrille.java rename to app/src/main/java/sae/chuzzle/VueGrille.java diff --git a/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml similarity index 100% rename from src/main/res/drawable-v24/ic_launcher_foreground.xml rename to app/src/main/res/drawable-v24/ic_launcher_foreground.xml diff --git a/src/main/res/drawable/chaine.png b/app/src/main/res/drawable/chaine.png similarity index 100% rename from src/main/res/drawable/chaine.png rename to app/src/main/res/drawable/chaine.png diff --git a/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml similarity index 100% rename from src/main/res/drawable/ic_launcher_background.xml rename to app/src/main/res/drawable/ic_launcher_background.xml diff --git a/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml similarity index 100% rename from src/main/res/drawable/ic_launcher_foreground.xml rename to app/src/main/res/drawable/ic_launcher_foreground.xml diff --git a/src/main/res/layout/activity_fin_partie.xml b/app/src/main/res/layout/activity_fin_partie.xml similarity index 100% rename from src/main/res/layout/activity_fin_partie.xml rename to app/src/main/res/layout/activity_fin_partie.xml diff --git a/src/main/res/layout/activity_menu.xml b/app/src/main/res/layout/activity_menu.xml similarity index 100% rename from src/main/res/layout/activity_menu.xml rename to app/src/main/res/layout/activity_menu.xml diff --git a/src/main/res/layout/activity_seed.xml b/app/src/main/res/layout/activity_seed.xml similarity index 100% rename from src/main/res/layout/activity_seed.xml rename to app/src/main/res/layout/activity_seed.xml diff --git a/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml similarity index 100% rename from src/main/res/mipmap-anydpi-v26/ic_launcher.xml rename to app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml diff --git a/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml similarity index 100% rename from src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml rename to app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml diff --git a/src/main/res/mipmap-hdpi/ic_launcher.webp b/app/src/main/res/mipmap-hdpi/ic_launcher.webp similarity index 100% rename from src/main/res/mipmap-hdpi/ic_launcher.webp rename to app/src/main/res/mipmap-hdpi/ic_launcher.webp diff --git a/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp similarity index 100% rename from src/main/res/mipmap-hdpi/ic_launcher_round.webp rename to app/src/main/res/mipmap-hdpi/ic_launcher_round.webp diff --git a/src/main/res/mipmap-mdpi/ic_launcher.webp b/app/src/main/res/mipmap-mdpi/ic_launcher.webp similarity index 100% rename from src/main/res/mipmap-mdpi/ic_launcher.webp rename to app/src/main/res/mipmap-mdpi/ic_launcher.webp diff --git a/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp similarity index 100% rename from src/main/res/mipmap-mdpi/ic_launcher_round.webp rename to app/src/main/res/mipmap-mdpi/ic_launcher_round.webp diff --git a/src/main/res/mipmap-xhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp similarity index 100% rename from src/main/res/mipmap-xhdpi/ic_launcher.webp rename to app/src/main/res/mipmap-xhdpi/ic_launcher.webp diff --git a/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp similarity index 100% rename from src/main/res/mipmap-xhdpi/ic_launcher_round.webp rename to app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp diff --git a/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp similarity index 100% rename from src/main/res/mipmap-xxhdpi/ic_launcher.webp rename to app/src/main/res/mipmap-xxhdpi/ic_launcher.webp diff --git a/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp similarity index 100% rename from src/main/res/mipmap-xxhdpi/ic_launcher_round.webp rename to app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp diff --git a/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp similarity index 100% rename from src/main/res/mipmap-xxxhdpi/ic_launcher.webp rename to app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp diff --git a/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp similarity index 100% rename from src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp rename to app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp diff --git a/src/main/res/values-night/themes.xml b/app/src/main/res/values-night/themes.xml similarity index 100% rename from src/main/res/values-night/themes.xml rename to app/src/main/res/values-night/themes.xml diff --git a/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml similarity index 100% rename from src/main/res/values/colors.xml rename to app/src/main/res/values/colors.xml diff --git a/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml similarity index 100% rename from src/main/res/values/strings.xml rename to app/src/main/res/values/strings.xml diff --git a/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml similarity index 100% rename from src/main/res/values/themes.xml rename to app/src/main/res/values/themes.xml diff --git a/src/main/res/xml/backup_rules.xml b/app/src/main/res/xml/backup_rules.xml similarity index 100% rename from src/main/res/xml/backup_rules.xml rename to app/src/main/res/xml/backup_rules.xml diff --git a/src/main/res/xml/data_extraction_rules.xml b/app/src/main/res/xml/data_extraction_rules.xml similarity index 100% rename from src/main/res/xml/data_extraction_rules.xml rename to app/src/main/res/xml/data_extraction_rules.xml diff --git a/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml similarity index 100% rename from src/main/res/xml/preferences.xml rename to app/src/main/res/xml/preferences.xml diff --git a/src/test/java/sae/chuzzle/ExampleUnitTest.java b/app/src/test/java/sae/chuzzle/ExampleUnitTest.java similarity index 100% rename from src/test/java/sae/chuzzle/ExampleUnitTest.java rename to app/src/test/java/sae/chuzzle/ExampleUnitTest.java diff --git a/build.gradle.kts b/build.gradle.kts index 882d8c5..3756278 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,42 +1,4 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { - alias(libs.plugins.android.application) -} - -android { - namespace = "sae.chuzzle" - compileSdk { - version = release(36) - } - - defaultConfig { - applicationId = "sae.chuzzle" - minSdk = 24 - targetSdk = 36 - versionCode = 1 - versionName = "1.0" - - testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" - } - - buildTypes { - release { - isMinifyEnabled = false - proguardFiles( - getDefaultProguardFile("proguard-android-optimize.txt"), - "proguard-rules.pro" - ) - } - } - compileOptions { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 - } -} - -dependencies { - - implementation(libs.activity) - testImplementation(libs.junit) - androidTestImplementation(libs.ext.junit) - androidTestImplementation(libs.espresso.core) + alias(libs.plugins.android.application) apply false } \ No newline at end of file diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..4387edc --- /dev/null +++ b/gradle.properties @@ -0,0 +1,21 @@ +# Project-wide Gradle settings. +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. For more details, visit +# https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects +# org.gradle.parallel=true +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app's APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Enables namespacing of each library's R class so that its R class includes only the +# resources declared in the library itself and none from the library's dependencies, +# thereby reducing the size of the R class for that library +android.nonTransitiveRClass=true \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 0000000..9f3ec5d --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,22 @@ +[versions] +agp = "9.0.1" +junit = "4.13.2" +junitVersion = "1.3.0" +espressoCore = "3.7.0" +appcompat = "1.7.1" +material = "1.13.0" +activity = "1.12.4" +constraintlayout = "2.2.1" + +[libraries] +junit = { group = "junit", name = "junit", version.ref = "junit" } +ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" } +espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" } +appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" } +material = { group = "com.google.android.material", name = "material", version.ref = "material" } +activity = { group = "androidx.activity", name = "activity", version.ref = "activity" } +constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" } + +[plugins] +android-application = { id = "com.android.application", version.ref = "agp" } + diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..8bdaf60c75ab801e22807dde59e12a8735a34077 GIT binary patch literal 45457 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
E3O!uy!x-n^Xipuqmga7Z(85N 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®G46aK?r|^ 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 M0bT}%>?I%`0L*Dn)Bpeg literal 0 HcmV?d00001 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..a96301f --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,9 @@ +#Tue Mar 24 19:40:20 CET 2026 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionSha256Sum=a17ddd85a26b6a7f5ddb71ff8b05fc5104c0202c6e64782429790c933686c806 +distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100644 index 0000000..ef07e01 --- /dev/null +++ b/gradlew @@ -0,0 +1,251 @@ +#!/bin/sh + +# +# Copyright © 2015 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH="\\\"\\\"" + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..db3a6ac --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,94 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH= + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 0000000..95e681f --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,24 @@ +pluginManagement { + repositories { + google { + content { + includeGroupByRegex("com\\.android.*") + includeGroupByRegex("com\\.google.*") + includeGroupByRegex("androidx.*") + } + } + mavenCentral() + gradlePluginPortal() + } +} +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + } +} + +rootProject.name = "Real Chuzzle" +include(":app") + \ No newline at end of file diff --git a/src/main/res/layout/activity_main.xml b/src/main/res/layout/activity_main.xml deleted file mode 100644 index efcd1e2..0000000 --- a/src/main/res/layout/activity_main.xml +++ /dev/null @@ -1,93 +0,0 @@ - - - - - - - - - - - - - - - - - - - -