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 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 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 toutesLesCoordonnees = new HashSet<>(); // Stocke toutes les coordonnées utilisées while (nombreBloc != 0) { List 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 } } }