Ajout de GridSolver - Avant modification + jointure des classes
This commit is contained in:
parent
8d482356d3
commit
79010f68fd
2
Makefile
2
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)
|
||||
|
BIN
src/.DS_Store
vendored
BIN
src/.DS_Store
vendored
Binary file not shown.
@ -110,10 +110,8 @@ public class GridMakerGrid extends JPanel {
|
||||
for (int j = 0; j < 9; j++) {
|
||||
temp.append(gridCases[i][j].getCellValue());
|
||||
}
|
||||
|
||||
exportedGrid[i] = Integer.parseInt(temp.toString());
|
||||
}
|
||||
|
||||
return exportedGrid;
|
||||
}
|
||||
|
||||
|
61
src/GridSolver/Button.java
Normal file
61
src/GridSolver/Button.java
Normal file
@ -0,0 +1,61 @@
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* Class containing custom settings for JButtons.
|
||||
* @version 1.0
|
||||
* @author Moncef STITI
|
||||
* @author Marco ORFAO
|
||||
*/
|
||||
|
||||
public class Button extends JButton {
|
||||
/**
|
||||
* Constructor
|
||||
* @param text The text of the button
|
||||
*/
|
||||
public Button (String text) {
|
||||
super(text);
|
||||
setFont(new Font("Arial", Font.BOLD, 15));
|
||||
setBackground(new Color(96, 175, 255));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param text The text of the button
|
||||
* @param dimension The dimension of the button
|
||||
*/
|
||||
public Button(String text, Dimension dimension) {
|
||||
super(text);
|
||||
setPreferredSize(dimension);
|
||||
setFont(new Font("Arial", Font.BOLD, 20));
|
||||
setBackground(new Color(96, 175, 255));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param text The text of the button
|
||||
* @param dimension The dimension of the button
|
||||
* @param font The font of the text in the button
|
||||
*/
|
||||
public Button(String text, Dimension dimension, Font font) {
|
||||
super(text);
|
||||
setPreferredSize(dimension);
|
||||
setFont(font);
|
||||
setBackground(new Color(96, 175, 255));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param text The text of the button
|
||||
* @param dimension The dimension of the button
|
||||
* @param font The font of the text in the button
|
||||
* @param color The background color of the button
|
||||
*/
|
||||
public Button(String text, Dimension dimension, Font font, Color color) {
|
||||
super(text);
|
||||
setPreferredSize(dimension);
|
||||
setFont(font);
|
||||
setBackground(color);
|
||||
}
|
||||
|
||||
}
|
39
src/GridSolver/CongratulationsDialog.java
Normal file
39
src/GridSolver/CongratulationsDialog.java
Normal file
@ -0,0 +1,39 @@
|
||||
import javax.swing.JOptionPane;
|
||||
|
||||
/**
|
||||
* Cette classe permet de crée une boîte de dialogue de félicitations pour afficher le temps de résolution d'un Sudoku.
|
||||
* @version 1.0
|
||||
* @author Moncef STITI
|
||||
* @author Marco ORFAO
|
||||
*/
|
||||
public class CongratulationsDialog extends JOptionPane {
|
||||
|
||||
/**
|
||||
* Constructeur de la classe CongratulationsDialog.
|
||||
* @param solvingStartTime Le temps de démarrage de la résolution du Sudoku en nanosecondes.
|
||||
*/
|
||||
public CongratulationsDialog(long solvingStartTime) {
|
||||
super();
|
||||
|
||||
// Obtenir le temps actuel en nanosecondes
|
||||
long currentTime = System.nanoTime();
|
||||
|
||||
// Calculer le temps de résolution en secondes
|
||||
long solvingTime = (currentTime - solvingStartTime) / 1_000_000_000;
|
||||
|
||||
// Créer le message de félicitations en fonction du temps de résolution
|
||||
String message;
|
||||
long minutes = solvingTime / 60;
|
||||
long seconds = solvingTime % 60;
|
||||
|
||||
// Gérer le pluriel pour les minutes
|
||||
String minutesString = (minutes <= 1) ? " minute" : " minutes";
|
||||
|
||||
// Gérer le pluriel pour les secondes
|
||||
String secondsString = (seconds <= 1) ? " seconde" : " secondes";
|
||||
|
||||
message = "Félicitations ! Vous avez résolu le Sudoku en " + minutes + minutesString + " et " + seconds + secondsString + ".";
|
||||
|
||||
showMessageDialog(null, message, "Félicitations !", JOptionPane.PLAIN_MESSAGE);
|
||||
}
|
||||
}
|
10
src/GridSolver/DialogManager.java
Normal file
10
src/GridSolver/DialogManager.java
Normal file
@ -0,0 +1,10 @@
|
||||
|
||||
/**
|
||||
* Interface containing definition to showDialog box.
|
||||
* @version 1.0
|
||||
* @author Moncef STITI
|
||||
* @author Marco ORFAO
|
||||
*/
|
||||
public interface DialogManager {
|
||||
void showDialog();
|
||||
}
|
201
src/GridSolver/GSCase.java
Executable file
201
src/GridSolver/GSCase.java
Executable file
@ -0,0 +1,201 @@
|
||||
import java.awt.*;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JLabel;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.awt.event.MouseEvent;
|
||||
|
||||
/**
|
||||
* La classe GSCase représente une case individuelle dans une grille de Sudoku.
|
||||
*/
|
||||
public class GSCase extends JPanel implements MouseListener{
|
||||
|
||||
private int primaryValue; // Valeur principale de la case
|
||||
private int secondaryValue; // Deuxième valeur de la case (utilisée pour les cas spéciaux)
|
||||
private int tertiaryValue; // Troisième valeur de la case (utilisée pour les cas spéciaux)
|
||||
private int quaternaryValue; // Quatrième valeur de la case (utilisée pour les cas spéciaux)
|
||||
private String text = ""; // Texte affiché dans la case
|
||||
private Boolean isInitial = false; // Indique si la valeur de la case est initiale (fournie avec le puzzle)
|
||||
private Boolean isActive; // Indique si la case est active (sélectionnée par l'utilisateur)
|
||||
JLabel label = new JLabel(); // Composant pour afficher le texte dans la case
|
||||
private byte digitCount = 0; // Compte le nombre de valeurs insérées dans la case
|
||||
private int positionX; // Position X de la case dans la grille
|
||||
private int positionY; // Position Y de la case dans la grille
|
||||
private GSGrid parentGrid; // Référence à la grille parente
|
||||
|
||||
/**
|
||||
* Constructeur de la classe GSCase.
|
||||
* @param grid La grille parente à laquelle cette case appartient.
|
||||
* @param x Position X de la case dans la grille.
|
||||
* @param y Position Y de la case dans la grille.
|
||||
*/
|
||||
public GSCase(GSGrid grid, int x, int y) {
|
||||
this.positionX = x;
|
||||
this.positionY = y;
|
||||
|
||||
this.primaryValue = 0;
|
||||
this.secondaryValue = 0;
|
||||
this.tertiaryValue = 0;
|
||||
this.quaternaryValue = 0;
|
||||
|
||||
this.setBackground(Color.white);
|
||||
this.addMouseListener(this);
|
||||
this.parentGrid = grid;
|
||||
this.add(label);
|
||||
deactivateCell();
|
||||
layoutSetup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure l'apparence initiale de la case.
|
||||
*/
|
||||
public void layoutSetup() {
|
||||
this.label.setText(this.primaryValue != 0 ? this.text : "");
|
||||
this.label.setVisible(true);
|
||||
this.repaint();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise la case avec une valeur initiale.
|
||||
*/
|
||||
public void initializeCell() {
|
||||
label.setText(this.text);
|
||||
this.setBackground(this.isInitial ? Color.lightGray : Color.white);
|
||||
layoutSetup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Définit la valeur de la case.
|
||||
* @param value La valeur à définir pour la case.
|
||||
*/
|
||||
public void setValue(int value) {
|
||||
this.isInitial = (value != 0);
|
||||
this.text = (value != 0) ? String.valueOf(value) : "";
|
||||
this.primaryValue = value;
|
||||
initializeCell();
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtient la valeur de la case.
|
||||
* @return La valeur de la case.
|
||||
*/
|
||||
public int getValue(){
|
||||
return this.primaryValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gère les actions de clic de souris sur la case.
|
||||
*/
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
if (!this.isInitial) {
|
||||
this.isActive = true;
|
||||
this.setBackground(Color.GREEN);
|
||||
this.parentGrid.testActivity(this.positionX, this.positionY);
|
||||
}
|
||||
}
|
||||
|
||||
// D'autres méthodes de l'interface MouseListener
|
||||
public void mousePressed(MouseEvent e) {}
|
||||
public void mouseReleased(MouseEvent e) {}
|
||||
public void mouseEntered(MouseEvent e) {
|
||||
if (!isInitial) {
|
||||
if (!isActive) {
|
||||
this.setBackground(Color.yellow);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void mouseExited(MouseEvent e) {
|
||||
if (!isInitial) {
|
||||
if (!isActive) {
|
||||
this.setBackground(Color.white);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Désactive la case.
|
||||
*/
|
||||
public void deactivateCell(){
|
||||
this.isActive = false;
|
||||
this.setBackground(Color.white);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtient l'état d'activité de la case.
|
||||
* @return True si la case est active, sinon False.
|
||||
*/
|
||||
public Boolean getActivity(){
|
||||
return this.isActive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Met à jour la valeur de la case.
|
||||
* @param value La nouvelle valeur de la case.
|
||||
*/
|
||||
public void updateValue(int value){
|
||||
if (value == 0) {
|
||||
this.primaryValue = 0;
|
||||
this.digitCount = 0;
|
||||
layoutSetup();
|
||||
} else {
|
||||
if (!checkInputValue(value)) {
|
||||
if (this.primaryValue != value ) {
|
||||
if (this.digitCount == 0) {
|
||||
this.digitCount++;
|
||||
this.primaryValue = value;
|
||||
this.text = String.valueOf(this.primaryValue);
|
||||
} else if (this.digitCount == 1 && value != this.primaryValue) {
|
||||
this.secondaryValue = value;
|
||||
this.digitCount++;
|
||||
this.text = String.valueOf(this.primaryValue + ", " + this.secondaryValue);
|
||||
} else if (this.digitCount == 2 && value != this.primaryValue && value != this.secondaryValue) {
|
||||
this.tertiaryValue = value;
|
||||
this.digitCount++;
|
||||
this.text = String.valueOf(this.primaryValue + ", " + this.secondaryValue + ", " + this.tertiaryValue);
|
||||
} else if (this.digitCount == 3 && value != this.primaryValue && value != this.secondaryValue && value != this.tertiaryValue) {
|
||||
this.quaternaryValue = value;
|
||||
this.digitCount++;
|
||||
this.text = String.valueOf(this.primaryValue + ", " + this.secondaryValue + ", " + this.tertiaryValue + ", " + this.quaternaryValue);
|
||||
}
|
||||
}
|
||||
this.setBackground(Color.WHITE);
|
||||
layoutSetup();
|
||||
} else if (checkInputValue(value)){
|
||||
this.setBackground(Color.RED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si la valeur entrée est valide pour la case.
|
||||
* @param val La valeur à vérifier.
|
||||
* @return True si la valeur est valide, sinon False.
|
||||
*/
|
||||
public Boolean checkInputValue(int val){
|
||||
int temp = this.primaryValue;
|
||||
this.primaryValue = val;
|
||||
GSTest test = new GSTest(this.parentGrid);
|
||||
Boolean isValid = test.test();
|
||||
this.primaryValue = temp;
|
||||
return isValid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtient le nombre de valeurs insérées dans la case.
|
||||
* @return Le nombre de valeurs insérées.
|
||||
*/
|
||||
public int getDigitCount(){
|
||||
return this.digitCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Insère une valeur dans la case.
|
||||
* @param value La valeur à insérer.
|
||||
*/
|
||||
public void insertValue(int value){
|
||||
this.primaryValue = value;
|
||||
this.text = String.valueOf(this.primaryValue);
|
||||
layoutSetup();
|
||||
}
|
||||
|
||||
}
|
180
src/GridSolver/GSGrid.java
Executable file
180
src/GridSolver/GSGrid.java
Executable file
@ -0,0 +1,180 @@
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import javax.swing.border.Border;
|
||||
|
||||
/**
|
||||
* Cette classe représente la grille de jeu pour le Sudoku.
|
||||
* @version 1.0
|
||||
* @author Moncef STITI
|
||||
* @author Marco ORFAO
|
||||
*/
|
||||
public class GSGrid extends JLabel {
|
||||
|
||||
private static final int GRID_SIZE = 9;
|
||||
|
||||
private int[][] tableauGrille = new int[GRID_SIZE][GRID_SIZE];
|
||||
private GSCase[][] cases = new GSCase[GRID_SIZE][GRID_SIZE];
|
||||
private GSMenu menu;
|
||||
|
||||
private int activeX = 0;
|
||||
private int activeY = 0;
|
||||
private Boolean isPlaying;
|
||||
|
||||
/**
|
||||
* Constructeur de la classe GSGrid.
|
||||
* @param menu Le menu associé à la grille.
|
||||
*/
|
||||
public GSGrid(GSMenu menu) {
|
||||
this.menu = menu;
|
||||
initializeGrid();
|
||||
}
|
||||
|
||||
// Initialise la grille avec des cases vides
|
||||
private void initializeGrid() {
|
||||
FlowLayout gestionnaire = new FlowLayout();
|
||||
this.setLayout(gestionnaire);
|
||||
JPanel gridContainer = new JPanel();
|
||||
gridContainer.setLayout(new GridLayout(GRID_SIZE, GRID_SIZE));
|
||||
Dimension cellSize = new Dimension(91, 71);
|
||||
|
||||
for (int i = 0; i < GRID_SIZE; i++) {
|
||||
for (int j = 0; j < GRID_SIZE; j++) {
|
||||
cases[i][j] = new GSCase(this, i, j);
|
||||
setCellBorder(i, j);
|
||||
cases[i][j].setPreferredSize(cellSize);
|
||||
gridContainer.add(cases[i][j]);
|
||||
}
|
||||
}
|
||||
this.add(gridContainer);
|
||||
}
|
||||
|
||||
// Détermine les bordures des cellules de la grille
|
||||
private Border determineBorder(int i, int j) {
|
||||
int top = (i == 0) ? 5 : 1;
|
||||
int bottom = ((i + 1) % 3 == 0) ? 5 : 1;
|
||||
int left = (j == 0) ? 5 : 1;
|
||||
int right = ((j + 1) % 3 == 0) ? 5 : 1;
|
||||
return BorderFactory.createMatteBorder(top, left, bottom, right, Color.BLACK);
|
||||
}
|
||||
|
||||
// Applique les bordures aux cellules de la grille
|
||||
private void setCellBorder(int i, int j) {
|
||||
cases[i][j].setBorder(determineBorder(i, j));
|
||||
}
|
||||
|
||||
/**
|
||||
* Importe les données du Sudoku dans la grille.
|
||||
* @param go Tableau d'entiers représentant les données du Sudoku.
|
||||
*/
|
||||
public void importGrid(int[] go){
|
||||
int i,j;
|
||||
int longueur;
|
||||
for (i = 0; i < 9 ; i++) {
|
||||
longueur = String.valueOf(go[i]).length();
|
||||
|
||||
for ( j = 0; j < 9 - longueur; j++) {
|
||||
this.tableauGrille[i][j] = 0;
|
||||
this.cases[i][j].setValue(this.tableauGrille[i][j]);
|
||||
this.cases[i][j].repaint();
|
||||
}
|
||||
int[] transfert = new int[longueur];
|
||||
String str = Integer.toString(go[i]);
|
||||
for ( j = 0; j < longueur; j++) {
|
||||
transfert[j] = (int) Character.getNumericValue(str.charAt(j));
|
||||
}
|
||||
int k = 0;
|
||||
for ( j = 9 - longueur; j < 9; j++) {
|
||||
this.tableauGrille[i][j] = transfert[k];
|
||||
k++;
|
||||
this.cases[i][j].setValue(this.tableauGrille[i][j]);
|
||||
this.cases[i][j].repaint();
|
||||
}
|
||||
}
|
||||
this.menu.enablePlayOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Récupère la valeur d'une case à une position spécifique dans la grille.
|
||||
* @param i L'indice de ligne de la case.
|
||||
* @param j L'indice de colonne de la case.
|
||||
* @return La valeur de la case à la position spécifiée.
|
||||
*/
|
||||
public int getCellValue(int i, int j) {
|
||||
return cases[i][j].getValue();
|
||||
}
|
||||
|
||||
// Désactive les cases autres que celle indiquée
|
||||
public void testActivity(int x, int y){
|
||||
for (int i = 0 ; i < GRID_SIZE ; i++ ) {
|
||||
for (int j = 0 ; j < GRID_SIZE ; j++ ) {
|
||||
if (cases[i][j].getActivity() && (i != x || j != y)) {
|
||||
activeX = x;
|
||||
activeY = y;
|
||||
cases[i][j].deactivateCell();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Retourne l'index X de la case active
|
||||
public int whoIsActive_X() {
|
||||
return activeX;
|
||||
}
|
||||
|
||||
// Retourne l'index Y de la case active
|
||||
public int whoIsActive_Y() {
|
||||
return activeY;
|
||||
}
|
||||
|
||||
// Met à jour la valeur d'une case dans la grille
|
||||
public void setValuetoCase(int x, int y, int val) {
|
||||
if (cases[x][y].getActivity() && getMode()) {
|
||||
cases[x][y].updateValue(val);
|
||||
}
|
||||
}
|
||||
|
||||
// Vérifie si la grille est complète
|
||||
public Boolean isComplete(){
|
||||
for (int i = 0 ; i < 9 ; i++ ) {
|
||||
for (int j = 0 ; j < 9 ; j++ ) {
|
||||
if (this.cases[i][j].getDigitCount() != 1 && this.cases[i][j].getValue() == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Active ou désactive le mode de jeu
|
||||
public void isPlaying(Boolean _bool) {
|
||||
this.isPlaying = _bool;
|
||||
}
|
||||
|
||||
// Retourne le mode de jeu
|
||||
public Boolean getMode() {
|
||||
return this.isPlaying;
|
||||
}
|
||||
|
||||
// Résout le Sudoku
|
||||
public boolean solve() {
|
||||
for (int row = 0; row < 9; row++) {
|
||||
for (int column = 0; column < 9; column++) {
|
||||
if (this.tableauGrille[row][column] == 0) {
|
||||
for (int k = 1; k <= 9; k++) {
|
||||
this.tableauGrille[row][column] = k;
|
||||
this.cases[row][column].insertValue(k);
|
||||
GSTest _test = new GSTest(this);
|
||||
if (_test.isValid(row, column) && solve()) {
|
||||
return true;
|
||||
}
|
||||
this.tableauGrille[row][column] = 0;
|
||||
this.cases[row][column].insertValue(0);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
84
src/GridSolver/GSImport.java
Executable file
84
src/GridSolver/GSImport.java
Executable file
@ -0,0 +1,84 @@
|
||||
import javax.swing.*;
|
||||
import javax.swing.filechooser.FileNameExtensionFilter;
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* La classe GSImport est utilisée pour importer une grille à partir d'un fichier.
|
||||
* @version 1.0
|
||||
* @author Moncef STITI
|
||||
* @author Marco ORFAO
|
||||
*/
|
||||
public class GSImport {
|
||||
|
||||
private Window previousFrame;
|
||||
private boolean accessible;
|
||||
private File file;
|
||||
private int[] importedValues = new int[9];
|
||||
|
||||
/**
|
||||
* Constructeur pour créer une instance de GridMakerImport.
|
||||
* @param frame La fenêtre précédente
|
||||
* @param sudokuGrid La grille Sudoku
|
||||
*/
|
||||
public GSImport(Window frame) {
|
||||
this.previousFrame = frame;
|
||||
}
|
||||
|
||||
/**
|
||||
* Affiche une boîte de dialogue de sélection de fichier et importe la grille à partir du fichier sélectionné.
|
||||
*/
|
||||
public void importGrid() {
|
||||
JFileChooser fileChooser = new JFileChooser();
|
||||
FileNameExtensionFilter filter = new FileNameExtensionFilter("Grid files (*.gri)", "gri");
|
||||
fileChooser.setFileFilter(filter);
|
||||
int returnVal = fileChooser.showOpenDialog(previousFrame);
|
||||
if (returnVal == JFileChooser.APPROVE_OPTION) {
|
||||
file = fileChooser.getSelectedFile();
|
||||
if (readFile()) {
|
||||
accessible = true;
|
||||
} else {
|
||||
accessible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lit les données à partir du fichier sélectionné et les stocke dans un tableau.
|
||||
* @return true si la lecture est réussie, false sinon
|
||||
*/
|
||||
public boolean readFile() {
|
||||
try {
|
||||
FileInputStream fileInputStream = new FileInputStream(file);
|
||||
DataInputStream dataInputStream = new DataInputStream(fileInputStream);
|
||||
int incrementable = 0;
|
||||
while (dataInputStream.available() > 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;
|
||||
}
|
||||
}
|
88
src/GridSolver/GSMenu.java
Executable file
88
src/GridSolver/GSMenu.java
Executable file
@ -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;
|
||||
}
|
||||
}
|
60
src/GridSolver/GSMenuController.java
Normal file
60
src/GridSolver/GSMenuController.java
Normal file
@ -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
|
||||
}
|
||||
}
|
||||
}
|
108
src/GridSolver/GSPlay.java
Executable file
108
src/GridSolver/GSPlay.java
Executable file
@ -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;
|
||||
}
|
||||
}
|
69
src/GridSolver/GSPlayController.java
Normal file
69
src/GridSolver/GSPlayController.java
Normal file
@ -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é
|
||||
}
|
||||
}
|
56
src/GridSolver/GSSolver.java
Executable file
56
src/GridSolver/GSSolver.java
Executable file
@ -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
|
||||
}
|
||||
}
|
137
src/GridSolver/GSTest.java
Executable file
137
src/GridSolver/GSTest.java
Executable file
@ -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));
|
||||
}
|
||||
}
|
27
src/GridSolver/GSWin.java
Executable file
27
src/GridSolver/GSWin.java
Executable file
@ -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);
|
||||
}
|
||||
}
|
48
src/GridSolver/HomeButtonClickListener.java
Normal file
48
src/GridSolver/HomeButtonClickListener.java
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
103
src/GridSolver/HomeView.java
Normal file
103
src/GridSolver/HomeView.java
Normal file
@ -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
|
||||
}
|
||||
}
|
6
src/GridSolver/Main.java
Normal file
6
src/GridSolver/Main.java
Normal file
@ -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
|
||||
}
|
||||
}
|
47
src/GridSolver/MusicButton.java
Normal file
47
src/GridSolver/MusicButton.java
Normal file
@ -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;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
57
src/GridSolver/MusicPlayer.java
Normal file
57
src/GridSolver/MusicPlayer.java
Normal file
@ -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;
|
||||
}
|
||||
}
|
20
src/GridSolver/RulesDialogManager.java
Normal file
20
src/GridSolver/RulesDialogManager.java
Normal file
@ -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
|
||||
}
|
||||
}
|
||||
|
49
src/GridSolver/RulesSudoku.java
Normal file
49
src/GridSolver/RulesSudoku.java
Normal file
@ -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
|
||||
}
|
||||
}
|
||||
|
26
src/GridSolver/Title.java
Normal file
26
src/GridSolver/Title.java
Normal file
@ -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
|
||||
}
|
||||
}
|
||||
|
71
src/GridSolver/Window.java
Normal file
71
src/GridSolver/Window.java
Normal file
@ -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
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user