From 79010f68fdeff37e02b704f2d9d408678e618323 Mon Sep 17 00:00:00 2001 From: orfao Date: Fri, 26 Apr 2024 11:29:30 +0200 Subject: [PATCH] Ajout de GridSolver - Avant modification + jointure des classes --- Makefile | 2 +- src/.DS_Store | Bin 6148 -> 6148 bytes src/GridMaker/GridMakerGrid.java | 2 - src/GridSolver/Button.java | 61 ++++++ src/GridSolver/CongratulationsDialog.java | 39 ++++ src/GridSolver/DialogManager.java | 10 + src/GridSolver/GSCase.java | 201 ++++++++++++++++++++ src/GridSolver/GSGrid.java | 180 ++++++++++++++++++ src/GridSolver/GSImport.java | 84 ++++++++ src/GridSolver/GSMenu.java | 88 +++++++++ src/GridSolver/GSMenuController.java | 60 ++++++ src/GridSolver/GSPlay.java | 108 +++++++++++ src/GridSolver/GSPlayController.java | 69 +++++++ src/GridSolver/GSSolver.java | 56 ++++++ src/GridSolver/GSTest.java | 137 +++++++++++++ src/GridSolver/GSWin.java | 27 +++ src/GridSolver/HomeButtonClickListener.java | 48 +++++ src/GridSolver/HomeView.java | 103 ++++++++++ src/GridSolver/Main.java | 6 + src/GridSolver/MusicButton.java | 47 +++++ src/GridSolver/MusicPlayer.java | 57 ++++++ src/GridSolver/RulesDialogManager.java | 20 ++ src/GridSolver/RulesSudoku.java | 49 +++++ src/GridSolver/Title.java | 26 +++ src/GridSolver/Window.java | 71 +++++++ 25 files changed, 1548 insertions(+), 3 deletions(-) create mode 100644 src/GridSolver/Button.java create mode 100644 src/GridSolver/CongratulationsDialog.java create mode 100644 src/GridSolver/DialogManager.java create mode 100755 src/GridSolver/GSCase.java create mode 100755 src/GridSolver/GSGrid.java create mode 100755 src/GridSolver/GSImport.java create mode 100755 src/GridSolver/GSMenu.java create mode 100644 src/GridSolver/GSMenuController.java create mode 100755 src/GridSolver/GSPlay.java create mode 100644 src/GridSolver/GSPlayController.java create mode 100755 src/GridSolver/GSSolver.java create mode 100755 src/GridSolver/GSTest.java create mode 100755 src/GridSolver/GSWin.java create mode 100644 src/GridSolver/HomeButtonClickListener.java create mode 100644 src/GridSolver/HomeView.java create mode 100644 src/GridSolver/Main.java create mode 100644 src/GridSolver/MusicButton.java create mode 100644 src/GridSolver/MusicPlayer.java create mode 100644 src/GridSolver/RulesDialogManager.java create mode 100644 src/GridSolver/RulesSudoku.java create mode 100644 src/GridSolver/Title.java create mode 100644 src/GridSolver/Window.java diff --git a/Makefile b/Makefile index 9d20c79..285704a 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ JCFLAGS := -encoding UTF-8 -implicit:none JVM := java JVMFLAGS := -SRCDIR := ./src/GridMaker +SRCDIR := ./src/GridSolver OUTDIR := ./out DOCDIR := ./doc SRC := $(wildcard $(SRCDIR)/*.java) diff --git a/src/.DS_Store b/src/.DS_Store index 0d19af3a42908e61885443e46b731c9655cbecfd..6f0c01fcacb8159efbc15d433b0ea8b12e0946d4 100644 GIT binary patch delta 113 zcmZoMXfc=|#>CJzu~2NHo}wrt0|NsP3otPFG9)r&Go&&UdFD(kR2K(Ha5A_v6ftBn zq#z_GtFg#$7UK|P+1OypyqTSYp95&tWpx_^jwSt0zSkbM0QEJB)Y^%7D+50j6nZKatCb6bd zM-f3p?k&m5WO8n9&U9`j08DM#*#Rm5iY$VK5~~kP?n_y)CErsf8tY?(A*#4S6SoVa zwL=w91^$`>^6r*V!xR(#!uPj%n2g%3WYppaNe{a$)fa1Q0qdxv&o@0GtA}H@hAcgF zaWl&SSszasA6qye`e%A2_Va;@R~8#v|s2|45MKar*0 zLNxE*8uZ)Y^BEBHRwHUW2WpgXMkOXTo;;2y5OT`6AZKXj%70Swj6;_F6KeGX1-NI6 z6(t9#sRF8iDiA6l`5|Hvj6J3fZR%iUj{w91yRES;9}B{XJjNbVhrB~Gj!JY?~NUaq1LK^Dlo6Wvb(Iv{=c7p{+}o5l`5bL z{3``aq28$1xFo-~E-X&=+KA 0 && incrementable < 9) { + importedValues[incrementable] = dataInputStream.readInt(); + incrementable++; + } + dataInputStream.close(); + return true; + } catch (FileNotFoundException e) { + System.err.println("File not found."); + return false; + } catch (IOException e) { + System.err.println("IOException."); + return false; + } catch (NumberFormatException e) { + System.err.println("NumberFormatException."); + return false; + } + } + + + public boolean isAccessible() { + return accessible; + } + + /** + * Gets the array of imported values. + * @return the array of imported values + */ + public int[] getImportedValues() { + return importedValues; + } +} diff --git a/src/GridSolver/GSMenu.java b/src/GridSolver/GSMenu.java new file mode 100755 index 0000000..6216c63 --- /dev/null +++ b/src/GridSolver/GSMenu.java @@ -0,0 +1,88 @@ +import javax.swing.*; +import java.awt.*; + +/** + * La classe GSMenu représente le menu jouer du jeu Sudoku. + * @version 1.0 + * @author Moncef STITI + * @author Marco ORFAO + */ +public class GSMenu { + + private Window window; // Fenêtre dans laquelle le menu est affiché + private JPanel titlePanel; // Panneau pour le titre + private JPanel buttonPanel; // Panneau pour les boutons + private Title titleLabel; // Étiquette pour le titre + private Button importerButton; // Bouton pour importer une grille + private Button jouerButton; // Bouton pour commencer à jouer + private Button autoSolveButton; // Bouton pour résoudre automatiquement la grille + + /** + * Constructeur de la classe GSMenu. + * @param window La fenêtre dans laquelle afficher le menu. + */ + public GSMenu(Window window) { + this.window = window; + this.window.setLayout(new BorderLayout()); + + // Initialisation du panneau de titre + this.titlePanel = new JPanel(); + this.titlePanel.setBackground(new Color(54, 91, 109)); + this.titlePanel.setLayout(new GridLayout(2, 1)); + + // Création des étiquettes de titre et sous-titre + this.titleLabel = new Title("Jouer", new Font("Copperplate", Font.BOLD, 45), Color.WHITE); + + // Ajout des étiquettes au panneau de titre + this.titlePanel.add(this.titleLabel); + + // Initialisation du panneau de boutons + this.buttonPanel = new JPanel(); + this.buttonPanel.setLayout(new GridLayout(1, 3, 10, 0)); + this.buttonPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); + this.buttonPanel.setBackground(new Color(54, 91, 109)); + + // Création des boutons + this.importerButton = new Button("Charger une grille"); + this.jouerButton = new Button("Jouer"); + this.jouerButton.setEnabled(false); // Le bouton "Jouer" est désactivé par défaut + this.autoSolveButton = new Button("Résolution automatique"); + this.autoSolveButton.setEnabled(false); // Le bouton "Résolution automatique" est désactivé par défaut + + // Ajout des boutons au panneau de boutons + this.buttonPanel.add(this.importerButton); + this.buttonPanel.add(this.jouerButton); + this.buttonPanel.add(this.autoSolveButton); + + // Ajout des panneaux à la fenêtre + this.window.add(this.titlePanel, BorderLayout.NORTH); + this.window.add(this.buttonPanel, BorderLayout.CENTER); + + // Définition du titre de la page + this.window.setPageTitle("Menu jouer"); + + // Ajustement de la taille de la fenêtre en fonction de son contenu + this.window.pack(); + } + + /** + * Active les options de jeu dans le menu. + */ + public void enablePlayOptions() { + this.jouerButton.setEnabled(true); // Active le bouton "Jouer" + this.autoSolveButton.setEnabled(true); // Active le bouton "Résolution automatique" + } + + // Méthodes getters pour les composants + public Button getImporterButton() { + return this.importerButton; + } + + public Button getJouerButton() { + return this.jouerButton; + } + + public Button getAutoSolveButton() { + return this.autoSolveButton; + } +} diff --git a/src/GridSolver/GSMenuController.java b/src/GridSolver/GSMenuController.java new file mode 100644 index 0000000..79c69ab --- /dev/null +++ b/src/GridSolver/GSMenuController.java @@ -0,0 +1,60 @@ +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/** + * La classe GSMenuController gère les actions déclenchées par les boutons du menu. + * @version 1.0 + * @author Moncef STITI + * @author Marco ORFAO + */ +public class GSMenuController implements ActionListener { + private GSMenu gsMenu; // Menu Sudoku + private Window mainWindow; // Fenêtre principale + private GSGrid sudokuGrid; // Grille de Sudoku + + /** + * Constructeur de la classe GSMenuController. + * @param gsMenu Le menu Sudoku à contrôler. + * @param mainWindow La fenêtre principale. + */ + public GSMenuController(GSMenu gsMenu, Window mainWindow) { + this.gsMenu = gsMenu; + this.mainWindow = mainWindow; + this.sudokuGrid = new GSGrid(gsMenu); // Initialise la grille de Sudoku + + // Ajout de l'action listener pour les boutons du menu + gsMenu.getImporterButton().addActionListener(this); + gsMenu.getJouerButton().addActionListener(this); + gsMenu.getAutoSolveButton().addActionListener(this); + } + + /** + * Méthode appelée lorsqu'une action est effectuée (clic sur un bouton). + * @param e L'événement associé à l'action. + */ + @Override + public void actionPerformed(ActionEvent e) { + // Si le bouton "Importer" est cliqué + if (e.getSource() == gsMenu.getImporterButton()) { + GSImport importer = new GSImport(mainWindow); // Crée un gestionnaire d'importation de grille + importer.importGrid(); // Importe une grille + if (importer.isAccessible()) { + sudokuGrid.importGrid(importer.getImportedValues()); // Met à jour la grille avec les valeurs importées + // Réactive les options de jeu dans le menu + gsMenu.enablePlayOptions(); + sudokuGrid.isPlaying(true); // Indique que le jeu est en cours + } + } + // Si le bouton "Jouer" est cliqué + else if (e.getSource() == gsMenu.getJouerButton()) { + GSPlay jeu = new GSPlay(this.mainWindow,this.sudokuGrid); // Crée un jeu Sudoku + GSPlayController jeuController = new GSPlayController(jeu); // Crée un contrôleur pour le jeu + gsMenu.getJouerButton().addKeyListener(jeuController); // Ajoute un écouteur de touches pour le jeu + jeu.showGame(); // Affiche le jeu + } + // Si le bouton "Résoudre automatiquement" est cliqué + else if (e.getSource() == gsMenu.getAutoSolveButton()) { + GSSolver resolveurDeGrille = new GSSolver(this.sudokuGrid,this.mainWindow); // Crée un résolveur de grille + } + } +} diff --git a/src/GridSolver/GSPlay.java b/src/GridSolver/GSPlay.java new file mode 100755 index 0000000..bb4d60d --- /dev/null +++ b/src/GridSolver/GSPlay.java @@ -0,0 +1,108 @@ +import java.awt.*; +import java.awt.event.*; + +/** + * Classe GSPlay pour jouer au Sudoku. + * @version 1.0 + * @author Moncef STITI + * @author Marco ORFAO + */ +public class GSPlay { + + // Valeur représentant une case vide + private static final int EMPTY_VALUE = 0; + + // Codes des touches numériques du pavé numérique + private static final int[] NUM_KEYS = {KeyEvent.VK_NUMPAD1, KeyEvent.VK_NUMPAD2, KeyEvent.VK_NUMPAD3, KeyEvent.VK_NUMPAD4, KeyEvent.VK_NUMPAD5, + KeyEvent.VK_NUMPAD6, KeyEvent.VK_NUMPAD7, KeyEvent.VK_NUMPAD8, KeyEvent.VK_NUMPAD9}; + + // Codes des touches numériques du clavier + private static final int[] KEY_NUMBERS = {KeyEvent.VK_1, KeyEvent.VK_2, KeyEvent.VK_3, KeyEvent.VK_4, KeyEvent.VK_5, + KeyEvent.VK_6, KeyEvent.VK_7, KeyEvent.VK_8, KeyEvent.VK_9}; + + // Code de la touche de suppression + private static final int DELETE_KEY = KeyEvent.VK_BACK_SPACE; + + private Container content; + private GSGrid ma_Grille; + private Button boutonValider = new Button("Valider"); + private long startTime; + private long vraiTime; + private Window gameplay; + private GSPlayController gsPlayController; + + /** + * Constructeur de la classe GSPlay. + * @param grille La grille de Sudoku. + * @param frame La fenêtre principale. + */ + public GSPlay(Window window, GSGrid grille) { + this.ma_Grille = grille; + this.gameplay = window; + this.gsPlayController = new GSPlayController(this); + } + + + /** + * Méthode pour afficher la fenêtre de jeu. + */ + public void showGame() { + Window.removeAllComponents(this.gameplay); + this.gameplay.setPageTitle("Jouer"); + this.startTime = System.nanoTime(); + content = this.gameplay.getContentPane(); + BorderLayout gestionnaireGameplay = new BorderLayout(); + this.gameplay.setLayout(gestionnaireGameplay); + this.gameplay.setSize(650, 730); + this.gameplay.setFocusable(true); + this.gameplay.requestFocusInWindow(); + this.gameplay.addKeyListener(gsPlayController); + this.boutonValider.setEnabled(false); + this.vraiTime = System.nanoTime() - this.startTime; + boutonValider.addActionListener(gsPlayController); + this.gameplay.add(boutonValider, BorderLayout.SOUTH); + content.add(this.ma_Grille, BorderLayout.CENTER); + } + + /** + * Méthode pour obtenir la valeur associée à une touche. + * @param e L'événement KeyEvent associé à la touche. + * @return La valeur correspondante à la touche ou -1 si aucune correspondance. + */ + public int getKeyValue(KeyEvent e) { + int keyCode = e.getKeyCode(); + if (keyCode == DELETE_KEY) { + return EMPTY_VALUE; + } + for (int i = 0; i < NUM_KEYS.length; i++) { + if (keyCode == NUM_KEYS[i] || keyCode == KEY_NUMBERS[i]) { + return i + 1; + } + } + return -1; + } + + /** + * Méthode pour vérifier si le jeu est terminé. + * @return true si le jeu est terminé, sinon false. + */ + public Boolean isGameOver() { + return !this.ma_Grille.isComplete(); + } + + public Button getBoutonValider() { + return boutonValider; + } + + public GSGrid getMaGrille() { + return ma_Grille; + } + + /** + * Méthode pour obtenir le temps de démarrage du jeu. + * @return Le temps de démarrage du jeu. + */ + public long getStartTime() { + return this.startTime; + } +} diff --git a/src/GridSolver/GSPlayController.java b/src/GridSolver/GSPlayController.java new file mode 100644 index 0000000..de44857 --- /dev/null +++ b/src/GridSolver/GSPlayController.java @@ -0,0 +1,69 @@ +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; + +/** + * Le contrôleur pour le jeu de la grille. + * @version 1.0 + * @author Moncef STITI + * @author Marco ORFAO + */ +public class GSPlayController implements KeyListener, ActionListener { + private GSPlay gsPlay; + + /** + * Constructeur du contrôleur du jeu de la grille. + * @param gsPlay Le jeu de la grille associé à ce contrôleur. + */ + public GSPlayController(GSPlay gsPlay) { + this.gsPlay = gsPlay; + } + + /** + * Gère les actions lorsqu'un événement se produit. + * @param e L'événement déclenché. + */ + @Override + public void actionPerformed(ActionEvent e) { + if (e.getSource() == gsPlay.getBoutonValider()) { + // Crée une fenêtre de dialogue pour afficher le temps écoulé depuis le début du jeu. + GSWin gestionVictoire = new GSWin(gsPlay.getStartTime()); + gestionVictoire.showDialog(); + } + } + + /** + * Gère les événements lorsque la touche est enfoncée. + * @param e L'événement de la touche enfoncée. + */ + @Override + public void keyPressed(KeyEvent e) { + int keyValue = gsPlay.getKeyValue(e); + if (keyValue != -1) { + // Met à jour la valeur dans la case active de la grille avec la touche appuyée. + gsPlay.getMaGrille().setValuetoCase(gsPlay.getMaGrille().whoIsActive_X(), gsPlay.getMaGrille().whoIsActive_Y(), keyValue); + // Active le bouton de validation si le jeu est terminé. + if (gsPlay.isGameOver()) { + gsPlay.getBoutonValider().setEnabled(true); + } + } + } + + /** + * Gère les événements lorsque la touche est relâchée. + * @param e L'événement de la touche relâchée. + */ + @Override + public void keyReleased(KeyEvent e) { + } + + /** + * Gère les événements lorsque la touche est tapée. + * @param e L'événement de la touche tapée. + */ + @Override + public void keyTyped(KeyEvent e) { + // Non utilisé + } +} diff --git a/src/GridSolver/GSSolver.java b/src/GridSolver/GSSolver.java new file mode 100755 index 0000000..e74be62 --- /dev/null +++ b/src/GridSolver/GSSolver.java @@ -0,0 +1,56 @@ +import javax.swing.*; +import java.awt.*; + +/** + * La classe GSSolver résout une grille de Sudoku et affiche le résultat dans une fenêtre. + * @version 1.O + * @author Moncef STITI + * @author Marco ORFAO + */ +public class GSSolver { + + private GSGrid grid; // Grille de Sudoku à résoudre + private Window window; // Fenêtre dans laquelle afficher la résolution + private JLabel label = new JLabel("Resolution en cours..."); // Étiquette pour afficher le statut de la résolution + private long startTime; // Temps de début de la résolution + + /** + * Constructeur de la classe GSSolver. + * @param grid La grille de Sudoku à résoudre. + * @param window La fenêtre dans laquelle afficher la résolution. + */ + public GSSolver(GSGrid grid, Window window) { + this.grid = grid; + this.window = window; + Window.removeAllComponents(this.window); // Efface tous les composants de la fenêtre + this.window.setPageTitle("Résolution automatique"); + this.startSolving(); // Démarre la résolution + } + + /** + * Démarre le processus de résolution de la grille de Sudoku. + */ + private void startSolving() { + startTime = System.nanoTime(); // Enregistre le temps de début de la résolution + BorderLayout layout = new BorderLayout(); // Gestionnaire de mise en page pour la fenêtre + window.setLayout(layout); // Définit le gestionnaire de mise en page pour la fenêtre + window.getContentPane().add(label, BorderLayout.SOUTH); // Ajoute l'étiquette au bas de la fenêtre + window.getContentPane().add(grid, BorderLayout.CENTER); // Ajoute la grille au centre de la fenêtre + grid.solve(); // Résout la grille de Sudoku + + // Vérifie si le jeu est terminé + if (isGameOver()) { + double time = (double) (System.nanoTime() - startTime) / 1_000_000_000; // Calcule le temps écoulé en secondes + label.setText("Résolu en " + time + " secondes."); // Met à jour le texte de l'étiquette avec le temps écoulé + label.setForeground(Color.WHITE); // Définit la couleur du texte sur blanc + } + } + + /** + * Vérifie si le jeu est terminé. + * @return true si le jeu est terminé, false sinon. + */ + private boolean isGameOver() { + return !grid.isComplete(); // Vérifie si la grille est complète + } +} diff --git a/src/GridSolver/GSTest.java b/src/GridSolver/GSTest.java new file mode 100755 index 0000000..d506064 --- /dev/null +++ b/src/GridSolver/GSTest.java @@ -0,0 +1,137 @@ +/** + * La classe GSTest contient les méthodes pour tester la validité d'une grille de Sudoku. + * @version 1.0 + * @author Moncef STITI + * @author Marco ORFAO + */ +public class GSTest { + + private GSGrid ma_Grille; + + /** + * Constructeur de la classe GSTest. + * @param Grid La grille de Sudoku à tester. + */ + public GSTest(GSGrid Grid) { + this.ma_Grille = Grid; + } + + /** + * Vérifie s'il y a des doublons dans la grille de Sudoku. + * @return true s'il y a des doublons, false sinon. + */ + public boolean test() { + // Vérification colonne + for (int i = 0; i < 9; i++) { + for (int j = 0; j < 9; j++) { + for (int i_prime = i + 1; i_prime < 9; i_prime++) { + if (this.ma_Grille.getCellValue(i, j) == this.ma_Grille.getCellValue(i_prime, j) && this.ma_Grille.getCellValue(i, j) != 0) { + return true; + } + } + } + } + + // Vérification ligne + for (int j = 0; j < 9; j++) { + for (int i = 0; i < 9; i++) { + for (int j_prime = j + 1; j_prime < 9; j_prime++) { + if (this.ma_Grille.getCellValue(i, j) == this.ma_Grille.getCellValue(i, j_prime) && this.ma_Grille.getCellValue(i, j) != 0) { + return true; + } + } + } + } + + // Vérification région + for (int i = 0; i < 9; i += 3) { + for (int j = 0; j < 9; j += 3) { + if (verificationRegion(i, j)) { + return true; + } + } + } + return false; // Aucun doublon trouvé dans la grille + } + + /** + * Vérifie s'il y a des doublons dans une région spécifique de la grille. + * @param x L'indice x du coin supérieur gauche de la région. + * @param y L'indice y du coin supérieur gauche de la région. + * @return true s'il y a des doublons, false sinon. + */ + public boolean verificationRegion(int x, int y) { + final int REGION_SIZE = 3; // Taille de chaque région (3x3) + + // Calcul des coordonnées du coin supérieur gauche de la région spécifiée + int regionX = (x / REGION_SIZE) * REGION_SIZE; + int regionY = (y / REGION_SIZE) * REGION_SIZE; + + // Tableau pour suivre les valeurs déjà vues dans la région (de 1 à 9) + boolean[] seen = new boolean[10]; + + // Parcours de chaque cellule de la région spécifiée + for (int i = 0; i < REGION_SIZE; i++) { + for (int j = 0; j < REGION_SIZE; j++) { + // Obtention de la valeur de la cellule + int value = this.ma_Grille.getCellValue(regionX + i, regionY + j); + // Vérification si la valeur est différente de zéro (cellule remplie) + if (value != 0) { + // Si la valeur a déjà été vue dans la région, il y a un doublon + if (seen[value]) { + return true; // Valeur en double trouvée + } + seen[value] = true; // Marquage de la valeur comme vue + } + } + } + return false; // Aucune valeur en double trouvée dans la région + } + + /** + * Vérifie s'il y a des doublons dans une ligne spécifique de la grille. + * @param x L'indice de la ligne à vérifier. + * @return true s'il y a des doublons, false sinon. + */ + public boolean verificationLigne(int x) { + int i = x; + + for (int j = 0; j < 8; j++) { // Parcours des colonnes jusqu'à l'avant-dernière colonne + for (int j_prime = j + 1; j_prime < 9; j_prime++) { // Parcours des colonnes suivantes + // Comparaison des valeurs des cellules + if (ma_Grille.getCellValue(i, j) == ma_Grille.getCellValue(i, j_prime) && ma_Grille.getCellValue(i, j) != 0) { + return true; // Doublon trouvé, on peut retourner true directement + } + } + } + return false; // Aucun doublon trouvé dans la ligne + } + + /** + * Vérifie s'il y a des doublons dans une colonne spécifique de la grille. + * @param y L'indice de la colonne à vérifier. + * @return true s'il y a des doublons, false sinon. + */ + public boolean verificationColonne(int y) { + int j = y; + for (int i = 0; i < 8; i++) { // Parcours des lignes jusqu'à l'avant-dernière ligne + for (int i_prime = i + 1; i_prime < 9; i_prime++) { // Parcours des lignes suivantes + // Comparaison des valeurs des cellules + if (ma_Grille.getCellValue(i, j) == ma_Grille.getCellValue(i_prime, j) && ma_Grille.getCellValue(i, j) != 0) { + return true; // Doublon trouvé, on peut retourner true directement + } + } + } + return false; // Aucun doublon trouvé dans la colonne + } + + /** + * Vérifie si une cellule spécifique de la grille est valide. + * @param row L'indice de la ligne de la cellule. + * @param column L'indice de la colonne de la cellule. + * @return true si la cellule est valide, false sinon. + */ + public Boolean isValid(int row, int column){ + return (!verificationLigne(row) && !verificationColonne(column) && !verificationRegion(row, column)); + } +} diff --git a/src/GridSolver/GSWin.java b/src/GridSolver/GSWin.java new file mode 100755 index 0000000..d1b207b --- /dev/null +++ b/src/GridSolver/GSWin.java @@ -0,0 +1,27 @@ +/** + * La classe GSWin gère l'affichage d'une fenêtre de félicitations pour avoir résolu le Sudoku. + * @version 1.0 + * @author Moncef STITI + * @author Marco ORFAO + */ +public class GSWin implements DialogManager { + + private long solvingTime; // Temps de résolution du Sudoku + + /** + * Constructeur de la classe GSWin. + * @param solvingTime Le temps de résolution du Sudoku. + */ + public GSWin(long solvingTime) { + this.solvingTime = solvingTime; + } + + /** + * Affiche la fenêtre de félicitations pour avoir résolu le Sudoku. + */ + @Override + public void showDialog() { + // Créer et afficher une nouvelle fenêtre de félicitations + CongratulationsDialog congratsWindow = new CongratulationsDialog(solvingTime); + } +} diff --git a/src/GridSolver/HomeButtonClickListener.java b/src/GridSolver/HomeButtonClickListener.java new file mode 100644 index 0000000..2706b76 --- /dev/null +++ b/src/GridSolver/HomeButtonClickListener.java @@ -0,0 +1,48 @@ +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/** + * Listener for button clicks in the menu. + * It performs different actions based on the button clicked. + * @version 1.0 + * @author Moncef STITI + * @author Marco ORFAO + */ +class HomeButtonClickListener implements ActionListener { + private Window window; + private DialogManager rulesDialogManager; + private GSMenu menuJeu; + + /** + * Constructs a ButtonClickListener with the specified window. + * @param window The window where the actions will be performed. + */ + public HomeButtonClickListener(Window window) { + this.window = window; + this.rulesDialogManager = new RulesDialogManager(); + } + + /** + * Performs an action based on the button clicked. + * @param e The ActionEvent representing the button click. + */ + @Override + public void actionPerformed(ActionEvent e) { + String buttonText = ((Button) e.getSource()).getText(); + switch (buttonText) { + case "Jouer": + Window.removeAllComponents(this.window); + this.menuJeu = new GSMenu(this.window); + GSMenuController menuController = new GSMenuController(this.menuJeu, this.window); + break; + case "Règles": + rulesDialogManager.showDialog(); // Afficher les règles + break; + case "Quitter": + System.exit(0); // Quitter le programme + break; + default: + break; + } + } +} diff --git a/src/GridSolver/HomeView.java b/src/GridSolver/HomeView.java new file mode 100644 index 0000000..eab4167 --- /dev/null +++ b/src/GridSolver/HomeView.java @@ -0,0 +1,103 @@ +import javax.swing.*; +import java.awt.*; + +/** + * HomeView représente la vue de la page d'accueil de l'application Sudoku. + * Cette classe étend JPanel et affiche les éléments de la page d'accueil, y compris le titre, les boutons et les contrôles audio. + * Elle utilise également les classes Title, Button, et MusicButton. + * + * @version 1.0 + * @author Moncef STITI + * @author Marco ORFAO + */ +public class HomeView extends JPanel { + + // Constantes pour les chemins des icônes et des fichiers audio, ainsi que pour les dimensions et les couleurs + private final String AUDIO_ON = "img/iconeAudio.png"; + private final String AUDIO_OFF = "img/iconeAudioMuted.png"; + private final String MUSIC_FILE = "audio/musiqueDeFond.wav"; + private final Dimension BUTTON_SIZE = new Dimension(300, 60); + private final Color BACKGROUND_COLOR = new Color(54, 91, 109); + private final Color TITLE_TEXT_COLOR = Color.WHITE; + private final Font TITLE_FONT = new Font("Copperplate", Font.BOLD, 75); + private final Font SUBTITLE_FONT = new Font("Copperplate", Font.PLAIN, 24); + private final Font BUTTON_FONT = new Font("Copperplate", Font.BOLD, 24); + private final String[] BUTTON_TEXTS = {"Jouer", "Règles", "Quitter"}; + + // Tableau de titres pour le titre principal et le sous-titre + private final Title[] labels = { + new Title("Sudoku Game", TITLE_FONT, TITLE_TEXT_COLOR), + new Title("Par Moncef & Marco", SUBTITLE_FONT, TITLE_TEXT_COLOR) + }; + + private MusicButton musicButton; // Bouton pour contrôler la musique + private final Window window; // Fenêtre parente + private JPanel titlePanel; // Panneau pour le titre + private JPanel buttonPanel; // Panneau pour les boutons + private JLabel imageLabel; // Étiquette pour l'image + + /** + * Constructeur de la classe HomeView. + * Initialise la fenêtre parente et crée les composants de la page d'accueil. + * @param window La fenêtre parente. + */ + public HomeView(Window window) { + this.window = window; + createComponents(); + addComponentsToWindow(); + } + + /** + * Crée les composants de la page d'accueil, y compris les panneaux de titre et de boutons. + */ + private void createComponents() { + titlePanel = new JPanel(); + buttonPanel = new JPanel(); + ImageIcon iconeSudoku = new ImageIcon("img/sudoku.png"); + imageLabel = new JLabel(iconeSudoku); + + // Configuration du panneau de titre + GridLayout titleLayout = new GridLayout(2, 1); + titlePanel.setLayout(titleLayout); + titlePanel.setBackground(BACKGROUND_COLOR); + // Utilisation de la classe Title pour le titre et le sous-titre + for (Title label : labels) { + titlePanel.add(label); + } + + // Configuration du panneau de boutons + GridLayout buttonLayout = new GridLayout(BUTTON_TEXTS.length, 1, 0, 10); + buttonPanel.setLayout(buttonLayout); + buttonPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); + buttonPanel.setBackground(BACKGROUND_COLOR); + HomeButtonClickListener listenerButton = new HomeButtonClickListener(window); + for (String text : BUTTON_TEXTS) { + Button button = new Button(text, BUTTON_SIZE, BUTTON_FONT, BACKGROUND_COLOR); + button.addActionListener(listenerButton); + buttonPanel.add(button); + } + + musicButton = new MusicButton(AUDIO_ON, AUDIO_OFF, MUSIC_FILE); // Bouton pour contrôler la musique + } + + /** + * Ajoute les composants créés à la fenêtre parente. + */ + public void addComponentsToWindow() { + BorderLayout layout = new BorderLayout(); + window.getContentPane().setLayout(layout); + window.add(titlePanel, BorderLayout.NORTH); + window.add(buttonPanel, BorderLayout.WEST); + window.add(imageLabel, BorderLayout.EAST); + window.setPageTitle("Menu principal"); // Définit le titre de la page dans la fenêtre + + FlowLayout controlPanelLayout = new FlowLayout(FlowLayout.RIGHT); + JPanel controlPanel = new JPanel(controlPanelLayout); // Panneau pour les contrôles audio + controlPanel.setBackground(BACKGROUND_COLOR); + controlPanel.add(musicButton); // Ajoute le bouton de contrôle audio + window.add(controlPanel, BorderLayout.SOUTH); // Ajoute le panneau de contrôles à la fenêtre + + window.pack(); // Ajuste la taille de la fenêtre pour s'adapter à son contenu + window.setVisible(true); // Rend la fenêtre visible + } +} diff --git a/src/GridSolver/Main.java b/src/GridSolver/Main.java new file mode 100644 index 0000000..cf5d61f --- /dev/null +++ b/src/GridSolver/Main.java @@ -0,0 +1,6 @@ +public class Main{ + public static void main(String[] args) { + Window fenetre = new Window(); // Création d'une fenêtre + HomeView menu = new HomeView(fenetre); // Création du menu sur la fenêtre + } +} \ No newline at end of file diff --git a/src/GridSolver/MusicButton.java b/src/GridSolver/MusicButton.java new file mode 100644 index 0000000..a383176 --- /dev/null +++ b/src/GridSolver/MusicButton.java @@ -0,0 +1,47 @@ +import javax.swing.*; + +/** + * It provides a button that toggles between playing and stopping music when clicked. + * @version 1.0 + * @author Moncef STITI + * @author Marco ORFAO + */ + public class MusicButton extends JButton { + private static MusicPlayer currentMusicPlayer; + private ImageIcon iconOn; + private ImageIcon iconOff; + private MusicPlayer musicPlayer; + + /** + * Constructs a MusicButton. + * @param onIconPath The file path for the icon when music is on. + * @param offIconPath The file path for the icon when music is off. + * @param musicFilePath The file path for the music file to be played. + */ + public MusicButton(String onIconPath, String offIconPath, String musicFilePath) { + + this.iconOn = new ImageIcon(onIconPath); + this.iconOff = new ImageIcon(offIconPath); + setIcon(this.iconOff); + + // Vérifie s'il y a déjà une musique en cours de lecture et l'arrête si nécessaire + if (currentMusicPlayer != null && currentMusicPlayer.isPlaying()) { + currentMusicPlayer.stop(); + currentMusicPlayer = null; + } + + this.musicPlayer = new MusicPlayer(musicFilePath); + + addActionListener(e -> { + if (currentMusicPlayer != null && currentMusicPlayer.isPlaying()) { + currentMusicPlayer.stop(); + currentMusicPlayer = null; + setIcon(this.iconOff); + } else { + this.musicPlayer.play(); + setIcon(this.iconOn); + currentMusicPlayer = this.musicPlayer; + } + }); + } +} diff --git a/src/GridSolver/MusicPlayer.java b/src/GridSolver/MusicPlayer.java new file mode 100644 index 0000000..0a451e8 --- /dev/null +++ b/src/GridSolver/MusicPlayer.java @@ -0,0 +1,57 @@ +import java.io.File; +import javax.sound.sampled.*; + +/** + * Class containign a simple music player that allows playing and stopping music. + * @version 1.0 + * @author Moncef STITI + * @author Marco ORFAO + */ + +public class MusicPlayer { + private Clip clip; + private boolean isPlaying; + + /** + * Constructs a MusicPlayer with the specified file path. + * @param filePath The path to the music file to be played. + */ + public MusicPlayer(String filePath) { + try { + File file = new File(filePath); + AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(file); + this.clip = AudioSystem.getClip(); + this.clip.open(audioInputStream); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * Starts playing the music. + */ + public void play() { + if (this.clip != null && !this.isPlaying) { + this.clip.start(); + this.isPlaying = true; + } + } + + /** + * Stops the music. + */ + public void stop() { + if (this.clip != null && this.isPlaying) { + this.clip.stop(); + this.isPlaying = false; + } + } + + /** + * Checks if the music is currently playing. + * @return true if the music is playing, false otherwise. + */ + public boolean isPlaying() { + return this.isPlaying; + } +} diff --git a/src/GridSolver/RulesDialogManager.java b/src/GridSolver/RulesDialogManager.java new file mode 100644 index 0000000..c903d04 --- /dev/null +++ b/src/GridSolver/RulesDialogManager.java @@ -0,0 +1,20 @@ +import javax.swing.JOptionPane; + +/** + * RulesDialogManager gère l'affichage de la boîte de dialogue des règles. + * Cette classe implémente DialogManager pour définir la méthode showDialog. + * @version 1.0 + * @author Moncef STITI + * @author Marco ORFAO + */ +public class RulesDialogManager implements DialogManager { + /** + * Affiche la boîte de dialogue des règles du Sudoku. + */ + @Override + public void showDialog() { + RulesSudoku rulesPanel = new RulesSudoku(); // Création du panneau contenant les règles + JOptionPane.showMessageDialog(null, rulesPanel, "Règles du Sudoku", JOptionPane.PLAIN_MESSAGE); // Affichage de la boîte de dialogue + } +} + diff --git a/src/GridSolver/RulesSudoku.java b/src/GridSolver/RulesSudoku.java new file mode 100644 index 0000000..606dc34 --- /dev/null +++ b/src/GridSolver/RulesSudoku.java @@ -0,0 +1,49 @@ +import javax.swing.*; +import java.awt.*; + +/** + * RulesSudoku représente le panneau affichant les règles du Sudoku. + * Cette classe étend JPanel et définit le contenu des règles. + * @version 1.0 + * @author Moncef STITI + * @author Marco ORFAO + */ +public class RulesSudoku extends JPanel { + private Dimension FRAME_SIZE = new Dimension(400, 500); // Taille de la fenêtre des règles + private Color BACKGROUND_COLOR = new Color(54, 91, 109); // Couleur d'arrière-plan du panneau + + /** + * Constructeur par défaut de RulesSudoku. + * Initialise le contenu des règles et configure l'apparence du panneau. + */ + public RulesSudoku() { + BorderLayout gestionnaireBorderLayout = new BorderLayout(); + this.setLayout(gestionnaireBorderLayout); + this.setBackground(this.BACKGROUND_COLOR); // Couleur d'arrière-plan du panneau + + JLabel titleLabel = new JLabel("Règles du Sudoku"); + titleLabel.setFont(new Font("Copperplate", Font.BOLD, 40)); // Police du titre + titleLabel.setForeground(Color.WHITE); // Couleur du titre + + JTextArea rulesTextArea = new JTextArea(); + rulesTextArea.setText("Les règles du Sudoku :\n\n" + + "1. Le but du jeu est de remplir la grille avec une série de chiffres de 1 à 9 de telle sorte que chaque ligne, chaque colonne et chaque région de 3x3 contienne tous les chiffres de 1 à 9 sans répétition.\n\n" + + "2. Certains chiffres sont déjà placés dans la grille au départ et ne peuvent pas être modifiés.\n\n" + + "3. Utilisez la logique et le raisonnement pour remplir la grille avec les chiffres manquants.\n\n" + + "4. Le jeu est terminé lorsqu'il n'y a plus de cases vides et que toutes les règles sont respectées."); + rulesTextArea.setEditable(false); + rulesTextArea.setLineWrap(true); + rulesTextArea.setWrapStyleWord(true); + rulesTextArea.setFont(new Font("Arial", Font.PLAIN, 20)); // Police du texte des règles + rulesTextArea.setForeground(Color.WHITE); // Couleur du texte des règles + rulesTextArea.setBackground(this.BACKGROUND_COLOR); // Couleur d'arrière-plan du texte des règles + + JScrollPane scrollPane = new JScrollPane(rulesTextArea); + + this.add(titleLabel, BorderLayout.NORTH); + this.add(scrollPane, BorderLayout.CENTER); + + this.setPreferredSize(this.FRAME_SIZE); // Taille de la fenêtre des règles + } +} + diff --git a/src/GridSolver/Title.java b/src/GridSolver/Title.java new file mode 100644 index 0000000..c953378 --- /dev/null +++ b/src/GridSolver/Title.java @@ -0,0 +1,26 @@ +import javax.swing.*; +import java.awt.*; + +/** + * Title est une étiquette Swing personnalisée utilisée pour afficher un titre centré avec une police et une couleur spécifiées. + * Cette classe étend JLabel. + * @version 1.0 + * @author Moncef STITI + * @author Marco ORFAO + */ +public class Title extends JLabel { + + /** + * Constructeur de Title. + * Crée une étiquette avec le texte, la police et la couleur spécifiés, et la centre horizontalement. + * @param text Le texte à afficher. + * @param font La police à utiliser pour le texte. + * @param color La couleur du texte. + */ + public Title(String text, Font font, Color color) { + super(text, SwingConstants.CENTER); // Centre le texte horizontalement + setFont(font); // Définit la police du texte + setForeground(color); // Définit la couleur du texte + } +} + diff --git a/src/GridSolver/Window.java b/src/GridSolver/Window.java new file mode 100644 index 0000000..0cdf564 --- /dev/null +++ b/src/GridSolver/Window.java @@ -0,0 +1,71 @@ +import javax.swing.*; +import java.awt.*; + +/** + * Window est une classe représentant la fenêtre principale de l'application Sudoku. + * Cette classe étend JFrame et gère l'affichage des différentes pages de l'application. + * @version 1.0 + * @author Moncef STITI + * @author Marco ORFAO + */ +public class Window extends JFrame { + /** + * La taille minimale de la fenêtre. + */ + private static final Dimension MIN_WINDOW_SIZE = new Dimension(850, 700); + /** + * Le titre du programme. + */ + private static final String PROGRAM_TITLE = "Sudoku"; + + /** + * La couleur d'arrière plan par défaut de la fenêtre + */ + private static final Color BACKGROUND_COLOR = new Color(54, 91, 109); + + /** + * Le titre de la page actuelle. + */ + private String PAGE_TITLE = ""; + + /** + * Constructeur de la classe Window. + * Initialise la fenêtre avec le titre du programme, la taille minimale et la couleur de fond. + */ + public Window() { + super(PROGRAM_TITLE); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + this.setMinimumSize(MIN_WINDOW_SIZE); + this.setLocationRelativeTo(null); + getContentPane().setBackground(BACKGROUND_COLOR); + } + + /** + * Obtient le titre de la page actuelle. + * @return Le titre de la page actuelle. + */ + public String getPageTitle() { + return this.PAGE_TITLE; + } + + /** + * Définit le titre de la page actuelle. + * Met à jour le titre de la fenêtre pour inclure le titre de la page et le titre du programme. + * @param title Le titre de la page actuelle. + */ + public void setPageTitle(String title) { + this.PAGE_TITLE = title; + this.setTitle(this.PAGE_TITLE + " - " + Window.PROGRAM_TITLE); + } + + /** + * Supprime tous les composants de la fenêtre. + * Utilisé pour effacer le contenu de la fenêtre. + * @param window La fenêtre à nettoyer. + */ + public static void removeAllComponents(Window window) { + window.getContentPane().removeAll(); // Supprime tous les composants de la fenêtre + window.revalidate(); // Revalide la disposition des composants + window.repaint(); // Redessine la fenêtre + } +}