379 lines
16 KiB
Java
379 lines
16 KiB
Java
package sudoku;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.HashSet;
|
|
import java.util.List;
|
|
import java.util.Scanner;
|
|
import java.util.Set;
|
|
|
|
import sudoku.core.Console;
|
|
|
|
public class Sudoku {
|
|
private final Grille grille;
|
|
private final List<Contrainte> contraintes;
|
|
private String nom;
|
|
|
|
public Sudoku(int taille) {
|
|
this.grille = new Grille(taille, this);
|
|
this.contraintes = new ArrayList<>();
|
|
}
|
|
|
|
public void setNom(String nom) {
|
|
this.nom = nom;
|
|
}
|
|
|
|
public String getNom() {
|
|
return this.nom;
|
|
}
|
|
|
|
public void ajouterContrainte(Contrainte contrainte) {
|
|
contraintes.add(contrainte);
|
|
}
|
|
|
|
public boolean estValide(Case c) {
|
|
for (Contrainte contrainte : contraintes) {
|
|
if (!contrainte.estRespectee(grille, c)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public boolean estValide() {
|
|
for (int i = 0; i < this.getGrille().getTaille(); i++) {
|
|
for (int j = 0; j < this.getGrille().getTaille(); j++) {
|
|
Case c = this.getGrille().getCase(i, j);
|
|
if (c.getSymbole() != null && !this.estValide(c)) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public boolean verifierToutesContraintes() {
|
|
return grille.verifierToutesContraintes(contraintes);
|
|
}
|
|
|
|
public Grille getGrille() {
|
|
return grille;
|
|
}
|
|
|
|
public static void menuGrille() {
|
|
Scanner scanner = new Scanner(System.in);
|
|
// ETAPE 1 : TAILLE GRILLE
|
|
System.out.println("ETAPE 1 : Choisir la taille de la grille");
|
|
int tailleGrille = setTailleGrille(scanner); // récpère la taille de la grille
|
|
Sudoku sudoku = new Sudoku(tailleGrille);
|
|
// ETAPE 2 : SYMBOLE POSSIBLE
|
|
System.out.println("ETAPE 2 : Choisir les symboles possibles");
|
|
int typeSymbole = Grille.choisirTypeSymbole(scanner);
|
|
sudoku.getGrille().askSetSymbolesPossibles(typeSymbole, scanner); // demande à l'utilisateur de saisir ses
|
|
// symboles
|
|
// ETAPE 3 : REMPLIR LA GRILLE
|
|
System.out.println("ETAPE 3 : Remplir la grille");
|
|
setValeursGrille(sudoku, scanner, tailleGrille, typeSymbole);
|
|
System.out.println("Voici votre sudoku rempli :");
|
|
System.out.println(sudoku.getGrille().toString());
|
|
// ETAPE 4 : CHOIX DES CONTRAINTES
|
|
choixContraintes(sudoku, scanner);
|
|
// ETAPE 5 : RESOLUTION
|
|
System.out.println("ETAPE 5 : Résolution du sudoku");
|
|
choixResolution(sudoku, scanner);
|
|
}
|
|
|
|
private static void choixContraintes(Sudoku sudoku, Scanner scanner) {
|
|
System.out.println("Choisissez une combinaison entre 0 et 3 contraintes parmi les suivantes :");
|
|
System.out.println("1: Contrainte Bloc, 2: Contrainte Ligne, 3: Contrainte Colonne");
|
|
System.out.println(
|
|
"Entrez les numéros des contraintes séparés par des virgules (par exemple, 1,2,3) ou appuyez sur Entrée pour aucune contrainte :");
|
|
|
|
String input = scanner.nextLine();
|
|
if (input.trim().isEmpty()) {
|
|
System.out.println("Aucune contrainte sélectionnée.");
|
|
return;
|
|
}
|
|
|
|
String[] choix = input.split(",");
|
|
Set<Integer> contraintesChoisies = new HashSet<>();
|
|
for (String choixStr : choix) {
|
|
try {
|
|
int choixInt = Integer.parseInt(choixStr.trim());
|
|
if (choixInt >= 1 && choixInt <= 3) {
|
|
contraintesChoisies.add(choixInt);
|
|
} else {
|
|
System.out.println("Choix invalide : " + choixInt);
|
|
}
|
|
} catch (NumberFormatException e) {
|
|
System.out.println("Entrée invalide : " + choixStr);
|
|
}
|
|
}
|
|
|
|
for (int choixContrainte : contraintesChoisies) {
|
|
switch (choixContrainte) {
|
|
case 1:
|
|
sudoku.ajouterContrainte(new ContrainteBloc());
|
|
System.out.println("Contrainte Bloc ajoutée.");
|
|
break;
|
|
case 2:
|
|
sudoku.ajouterContrainte(new ContrainteLigne());
|
|
System.out.println("Contrainte Ligne ajoutée.");
|
|
break;
|
|
case 3:
|
|
sudoku.ajouterContrainte(new ContrainteColonne());
|
|
System.out.println("Contrainte Colonne ajoutée.");
|
|
break;
|
|
default:
|
|
System.out.println("Choix invalide : " + choixContrainte);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void resolutionSudoku(Sudoku sudoku, boolean afficherEtape) {
|
|
ResolveurBacktraceSimple resolveur = new ResolveurBacktraceSimple();
|
|
resolveur.resoudre(sudoku, afficherEtape);
|
|
System.out.println("Sudoku résolu :");
|
|
System.out.println(sudoku.getGrille().toString());
|
|
}
|
|
|
|
private static void choixResolution(Sudoku sudoku, Scanner scanner) {
|
|
System.out.println("Voulez-vous résoudre le sudoku ? (O/N)");
|
|
String choix = scanner.nextLine();
|
|
if (choix.equalsIgnoreCase("O")) {
|
|
System.out.println("Résolution du sudoku.");
|
|
// resolutionSudoku(sudoku);
|
|
System.out.println("Voulez-vous afficher les étapes de la résolution ? (O/N)");
|
|
String choixAffichageEtapes = scanner.nextLine();
|
|
|
|
if (choixAffichageEtapes.equalsIgnoreCase("O")) {
|
|
sudoku.resolutionSudoku(sudoku, true);
|
|
} else if (choixAffichageEtapes.equalsIgnoreCase("N")) {
|
|
sudoku.resolutionSudoku(sudoku, false);
|
|
} else {
|
|
System.err.println("Choix invalide.");
|
|
}
|
|
} else if (choix.equalsIgnoreCase("N")) {
|
|
System.err.println("Fin du jeu.");
|
|
} else {
|
|
System.out.println("Choix invalide.");
|
|
choixResolution(sudoku, scanner);
|
|
}
|
|
}
|
|
|
|
private static int setTailleGrille(Scanner scanner) {
|
|
int tailleGrille = -1;
|
|
while (tailleGrille <= 0) {
|
|
try {
|
|
tailleGrille = Integer.parseInt(scanner.nextLine());
|
|
if (tailleGrille <= 0) {
|
|
System.out.println("Erreur : Veuillez entrer un entier positif.");
|
|
}
|
|
} catch (NumberFormatException e) {
|
|
System.out.println("Erreur : Entrée invalide. Veuillez entrer un nombre.");
|
|
}
|
|
}
|
|
return tailleGrille;
|
|
}
|
|
|
|
private static void setValeursGrille(Sudoku sudoku, Scanner scanner, int tailleGrille, int typeSymbole) {
|
|
// Etude de la taille de la grille pour choisir le type de génération
|
|
if (carreParfait(tailleGrille)) {
|
|
System.out.println(tailleGrille + " est un carré parfait.");
|
|
sudoku.getGrille().creerBlocCarre();
|
|
} else {
|
|
while (true) {
|
|
System.out.println("Veuillez faire votre choix");
|
|
System.out.println("1 : Entrer les blocs manuellement");
|
|
System.out.println("2 : Entrer les blocs à l'aide de la longueur et de la largeur");
|
|
|
|
int choixGenerationBloc = Integer.parseInt(scanner.nextLine());
|
|
|
|
switch (choixGenerationBloc) {
|
|
case 1:
|
|
// Entrer les blocs manuellement
|
|
System.out.println("Entrez les blocs manuellement.");
|
|
creationBlocManuel(sudoku, scanner, tailleGrille);
|
|
break;
|
|
case 2:
|
|
// Entrer les blocs à l'aide de la longueur et de la largeur
|
|
boolean validDimensions = false;
|
|
while (!validDimensions) {
|
|
try {
|
|
System.out.println("Entrez les blocs à l'aide de la longueur et de la largeur.");
|
|
System.out.println("Entrez la longueur du bloc : ");
|
|
int longueurBloc = Integer.parseInt(scanner.nextLine());
|
|
System.out.println("Entrez la largeur du bloc :");
|
|
int largeurBloc = Integer.parseInt(scanner.nextLine());
|
|
sudoku.getGrille().creerBlocRectangulaire(longueurBloc, largeurBloc);
|
|
validDimensions = true; // Sortir de la boucle si aucune exception n'est lancée
|
|
} catch (IllegalArgumentException e) {
|
|
Console.errorln("Erreur : " + e.getMessage());
|
|
Console.errorln("Veuillez entrer des dimensions valides.");
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
Console.errorln("Choix invalide.");
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
// DEBUT DU REMPLISSAGE DU SUDOKU
|
|
String input;
|
|
while (true) {
|
|
// Demander et vérifier la ligne
|
|
int ligne = -1;
|
|
while (true) {
|
|
System.out.println("Pour arrêter la saisie, tapez \"esc\".");
|
|
System.out.println(
|
|
"Entrez le numéro de ligne :");
|
|
input = scanner.nextLine(); // Lire la ligne
|
|
if (input.equalsIgnoreCase("ESC")) {
|
|
break; // Sortie de la boucle si l'utilisateur tape ESC
|
|
}
|
|
if (input.isEmpty()) {
|
|
System.out.println("Veuillez entrer un numéro de ligne valide.");
|
|
continue; // Recommencer la saisie de la ligne si l'entrée est vide
|
|
}
|
|
try {
|
|
ligne = Integer.parseInt(input); // Convertir la ligne en entier
|
|
break; // Sortir de la boucle si la ligne est valide
|
|
} catch (NumberFormatException e) {
|
|
System.out.println("Veuillez entrer un numéro de ligne valide (un nombre entier).");
|
|
}
|
|
}
|
|
// ARRET DE LA BOUCLE SI SAISIE DE "ESC"
|
|
if (input.equalsIgnoreCase("ESC")) {
|
|
break; // Sortie de la boucle principale si l'utilisateur tape ESC
|
|
}
|
|
|
|
// Demander et vérifier la colonne
|
|
int colonne;
|
|
while (true) {
|
|
System.out.println("Entrez le numéro de colonne :");
|
|
input = scanner.nextLine(); // Lire la colonne
|
|
if (input.isEmpty()) {
|
|
System.out.println("Veuillez entrer un numéro de colonne valide.");
|
|
continue; // Recommencer la saisie de la colonne si l'entrée est vide
|
|
}
|
|
try {
|
|
colonne = Integer.parseInt(input); // Convertir la colonne en entier
|
|
break; // Sortir de la boucle si la colonne est valide
|
|
} catch (NumberFormatException e) {
|
|
System.out.println("Veuillez entrer un numéro de colonne valide (un nombre entier).");
|
|
}
|
|
}
|
|
|
|
// Demander et vérifier le symbole
|
|
String symbole;
|
|
while (true) {
|
|
System.out.println("Entrez le symbole :");
|
|
symbole = scanner.nextLine(); // Lire le symbole
|
|
if (symbole.isEmpty()) {
|
|
System.out.println("Veuillez entrer un symbole valide.");
|
|
continue; // Recommencer la saisie du symbole si l'entrée est vide
|
|
}
|
|
try {
|
|
Symbole s;
|
|
switch (typeSymbole) {
|
|
case 1:
|
|
// Entiers
|
|
s = Symbole.of(Integer.parseInt(symbole));
|
|
break;
|
|
case 2:
|
|
// Lettres
|
|
if (symbole.length() == 1 && Character.isLetter(symbole.charAt(0))) {
|
|
s = Symbole.of(symbole.charAt(0));
|
|
} else {
|
|
throw new IllegalArgumentException("Veuillez entrer une seule lettre.");
|
|
}
|
|
break;
|
|
case 3:
|
|
// Chaînes de caractères
|
|
s = Symbole.of(symbole);
|
|
break;
|
|
default:
|
|
throw new IllegalArgumentException("Type de symbole invalide.");
|
|
}
|
|
sudoku.getGrille().setCase(ligne, colonne, s); // Ajouter le symbole à la grille
|
|
|
|
System.out.println(sudoku.getGrille().toString());
|
|
break; // Sortir de la boucle si le symbole est valide
|
|
} catch (IllegalArgumentException e) {
|
|
System.out.println("Symbole non valide. " + e.getMessage());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private static boolean carreParfait(int nombre) {
|
|
if (nombre < 0) {
|
|
return false;
|
|
}
|
|
int racine = (int) Math.sqrt(nombre);
|
|
return racine * racine == nombre;
|
|
}
|
|
|
|
private static void creationBlocManuel(Sudoku sudoku, Scanner scanner, int tailleGrille) {
|
|
int nombreBloc = tailleGrille; // Nombre de blocs dans la grille
|
|
|
|
Set<String> toutesLesCoordonnees = new HashSet<>(); // Stocke toutes les coordonnées utilisées
|
|
|
|
while (nombreBloc != 0) {
|
|
List<int[]> listeCases = new ArrayList<>(); // Liste des cases du bloc
|
|
System.out.println("Remplissage du bloc " + nombreBloc);
|
|
|
|
for (int i = 1; i <= tailleGrille; i++) {
|
|
int choixLigne, choixColonne;
|
|
boolean coordonneesValides;
|
|
|
|
do {
|
|
coordonneesValides = true; // Par défaut, on suppose que la coordonnée est valide
|
|
|
|
// Demande de saisie
|
|
System.out.println("Entrez la ligne de la case " + i + " dans le bloc " + nombreBloc + " (0 à "
|
|
+ (tailleGrille - 1) + "):");
|
|
choixLigne = scanner.nextInt();
|
|
System.out.println("Entrez la colonne de la case " + i + " dans le bloc " + nombreBloc + " (0 à "
|
|
+ (tailleGrille - 1) + "):");
|
|
choixColonne = scanner.nextInt();
|
|
|
|
// Vérification des limites
|
|
if (choixLigne < 0 || choixLigne >= tailleGrille || choixColonne < 0
|
|
|| choixColonne >= tailleGrille) {
|
|
System.out.println("Erreur : Coordonnées hors limites ! Veuillez réessayer.");
|
|
coordonneesValides = false;
|
|
continue;
|
|
}
|
|
|
|
// Vérification si la coordonnée existe déjà dans TOUTE la grille
|
|
String coordonneeStr = choixLigne + "-" + choixColonne;
|
|
if (toutesLesCoordonnees.contains(coordonneeStr)) {
|
|
System.out.println(
|
|
"Erreur : Ces coordonnées sont déjà utilisées dans un autre bloc ! Veuillez en entrer une nouvelle.");
|
|
coordonneesValides = false;
|
|
}
|
|
|
|
} while (!coordonneesValides); // Tant que la saisie est invalide, on redemande
|
|
|
|
// Ajout des coordonnées validées
|
|
listeCases.add(new int[] { choixLigne, choixColonne });
|
|
toutesLesCoordonnees.add(choixLigne + "-" + choixColonne); // Ajout dans l'ensemble global
|
|
}
|
|
|
|
// Création du bloc après la saisie complète
|
|
try {
|
|
sudoku.getGrille().creerBlocPersonnalise(listeCases);
|
|
System.out.println("Bloc " + nombreBloc + " enregistré avec succès !");
|
|
} catch (IllegalArgumentException e) {
|
|
System.out.println("Erreur lors de la création du bloc : " + e.getMessage());
|
|
System.out.println("Veuillez recommencer la saisie de ce bloc.");
|
|
continue; // Recommence le bloc en cours
|
|
}
|
|
|
|
nombreBloc--; // Passer au bloc suivant
|
|
}
|
|
}
|
|
} |