IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

 C Discussion :

Résoudre un sudoku par backtracking


Sujet :

C

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    104
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2007
    Messages : 104
    Points : 84
    Points
    84
    Par défaut Résoudre un sudoku par backtracking
    Bonsoir,

    Je sais que ce problème a été traité de nombreuses fois, mais je n'ai pas trouvé de code simple. Celui qui était dans les sources C du site a disparu.
    Donc pour me remettre un petit peu à la programmation (rentrée tout ça...), j'ai essayé de faire un solveur de sudoku.

    L'algorithme par backtracking est pourtant simple (à comprendre du moins ^^), mais je ne comprends pas pourquoi mon programme ne fonctionne pas (il remplit mal la grille).

    Je vous poste mon code, si vous pouviez m'aiguiller, ce serait sympa ;-)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
    #define N_POSSIBILITES 9
    #define T_GRILLE 9
     
    void
    initialiser_grille(int grille[][T_GRILLE], int taille) {
     
        int i;
        int j;
     
        for (i = 0; i < taille; i++) {
    	for (j = 0; j < taille; j++) {
    	    grille[i][j] = 0;
    	}
        }
    }
     
    void
    lire_grille(FILE* fichier, int grille[][T_GRILLE], int taille) {
     
        int i;
        int j;
        int c;
     
        for (i = 0; i < taille; i++) {
    	for (j = 0; j < taille; j++) {
    	    c = fgetc(fichier);
    	    if (c != 0) {
    		grille[i][j] = c - '0';
    	    }
    	}
    	fseek(fichier, 1, SEEK_CUR);
        }
    }
     
    int
    est_valide_ligne(int grille[][T_GRILLE], int taille, int ligne) {
     
        int i;
        int tableau[T_GRILLE] = {1, 1, 1, 1, 1, 1, 1, 1, 1};
     
        for (i = 0; i < taille; i++) {
    	if (grille[ligne][i] != 0) {	
    	    if (tableau[grille[ligne][i] - 1] == 0) {
    		return 0;
    	    }
    	    else {
    		tableau[grille[ligne][i] - 1] = 0;
    	    }
    	}
        }
     
        return 1;
    }
     
    int
    est_valide_colonne(int grille[][T_GRILLE], int taille, int colonne) {
     
        int i;
        int tableau[T_GRILLE] = {1, 1, 1, 1, 1, 1, 1, 1, 1};
     
        for (i = 0; i < taille; i++) {
    	if (grille[i][colonne] != 0) {
    	    if (tableau[grille[i][colonne] - 1] == 0) {
    		return 0;
    	    }
    	    else {
    		tableau[grille[i][colonne] - 1] = 0;
    	    }
    	}
        }
     
        return 1;
    }
     
     
    int
    est_valide_bloc(int grille[][T_GRILLE], int taille, int x, int y) {
     
        int i;
        int j;
        int tableau[T_GRILLE] = {1, 1, 1, 1, 1, 1, 1, 1, 1};
     
        for (i = x; i < x + 3; i++) {
    	for (j = y; j < y + 3; j++) {
    	    if (grille[i][j] != 0) {
    		if (tableau[grille[i][j] - 1] == 0) {
    		    return 0;
    		}
    		else {
    		    tableau[grille[i][j] - 1] = 0;
    		}		
    	    }
    	}
        }
     
        return 1;
    }
     
    int
    sont_valides_blocs(int grille[][T_GRILLE], int taille) {
     
        int i;
        int j;
     
        for (i = 0; i < taille; i += 3) {
    	for (j = 0; j < taille; j += 3) {
    	    if (! est_valide_bloc(grille, taille, i, j)) {
    		return 0;
    	    }
    	}
        }
     
        return 1;
    }
     
    int 
    est_valide(int grille[][T_GRILLE], int taille) {
     
        int i;
     
        for (i = 0; i < taille; i++) {
    	if (! est_valide_ligne(grille, taille, i) ||
    	    ! est_valide_colonne(grille, taille, i)) {
    	    return 0;
    	}
        }
        if (! sont_valides_blocs(grille, taille)) {
    	return 0;
        }
     
        return 1;
    }
     
    int
    trouver_case_vide(int grille[][T_GRILLE], int taille, int* x, int *y) {
     
        int i;
        int j;
     
        for (i = 0; i < taille; i++) {
    	for (j = 0; j < taille; j++) {
    	    if (grille[i][j] == 0) {
    		*x = i;
    		*y = j;
     
    		return 1;
    	    }
    	}
        }
     
        return 0;
    }
     
    void
    solver_sudoku(int grille[][T_GRILLE], int taille) {
     
        int i;
        int j;
        int k;
     
        if (! trouver_case_vide(grille, taille, &i, &j)) {
    	return;
        }
        for (k = 1; k <= N_POSSIBILITES; k++) {
    	grille[i][j] = k;
    	if (est_valide(grille, taille)) {
    	    solver_sudoku(grille, taille);
    	}
        }
    }
     
    int
    main(int argc, char* argv[]) {
     
        int grille[T_GRILLE][T_GRILLE];
        FILE* fichier;
     
        if ((fichier = fopen(argv[1], "r")) == NULL) {
    	return -1;
        }
     
        initialiser_grille(grille, T_GRILLE);
        lire_grille(fichier, grille, T_GRILLE);
        solver_sudoku(grille, T_GRILLE);
     
        {
    	int i;
    	int j;
     
    	for (i = 0; i < T_GRILLE; i++) {
    	    for (j = 0; j < T_GRILLE; j++) {
    		printf("%d ", grille[i][j]);
    	    }
    	    printf("\n");
    	}
        }
     
        fclose(fichier);
     
        return 0;
    }
    Le format du fichier est simple, sur chaque ligne 9 chiffre suivit d'un retour à la ligne. Les cases vides sont matérialisées par un 0.

    exemple :

    081004905
    005000310
    070050480
    000000001
    000000293
    050007060
    003089000
    029000600
    500060109
    Merci à vous.

    Bye

  2. #2
    Expert éminent sénior
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Points : 13 926
    Points
    13 926
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    lire_grille(FILE* fichier, int grille[][T_GRILLE], int taille) {
    ...
        int c;
    ...
    	    c = fgetc(fichier);
    	    if (c != 0) {
    		grille[i][j] = (int) strtol((char*) &c, NULL, 10);
    strtol demande comme argument une chaine de caractères, pas l'adresse d'un char ou d'un int.
    Si il s'agit de convertir un caractère numérique en le chiffre correspondant, on peut utiliser c-'0'

  3. #3
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    104
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2007
    Messages : 104
    Points : 84
    Points
    84
    Par défaut
    Oui c'est vrai... Merci à toi.

    Malheureusement ça ne devait pas être le seul problème car ça ne fonctionne pas plus.

  4. #4
    Membre émérite Avatar de SofEvans
    Homme Profil pro
    Développeur C
    Inscrit en
    Mars 2009
    Messages
    1 078
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France

    Informations professionnelles :
    Activité : Développeur C

    Informations forums :
    Inscription : Mars 2009
    Messages : 1 078
    Points : 2 339
    Points
    2 339
    Par défaut
    Bonjour,

    Juste une chose qui me tracasse.

    Dans le code que tu as poster au debut, tu definie un bloc de la maniere suivante (il est situer apres l'appel a solver_sudoku)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
        {
    	int i;
    	int j;
     
    	for (i = 0; i < T_GRILLE; i++) {
    	    for (j = 0; j < T_GRILLE; j++) {
    		printf("%d ", grille[i][j]);
    	    }
    	    printf("\n");
    	}
        }
    C'est valide ca ?
    Je n'avais jamais vu une pareille syntaxe, si c'est valide, que cela veut-il dire ??


    EDIT :

    *Tu as mis int main(void) et tu utilise argv a la ligne 182.... Ce code compile chez toi ?

    *Apparemment, c'est la fonction de lecture du fichier qui ne donne pas ce que l'on veut. Il suffit de commenter l'appel a resolve_sudoku pour voir ce que le initialiser_grille et lire_grille font.

    *La grille de sudoku que tu as mise ne sera pas lu entierement car c'est une grille 9*10, alors que tu veut 9*9. De plus, il faut que tu change fseek. En effet, tu lui dit de se deplacer de 1 caractere, mais il lit le caractere retour chariot et met -38 dans la grille. Il suffit de remplacer 1 par 2.
    Cependant, ce n'etait pas ca qui bloquer ton algo.

  5. #5
    Rédacteur

    Avatar de ram-0000
    Homme Profil pro
    Consultant en sécurité
    Inscrit en
    Mai 2007
    Messages
    11 517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Consultant en sécurité
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2007
    Messages : 11 517
    Points : 50 367
    Points
    50 367
    Par défaut
    Citation Envoyé par SofEvans Voir le message
    C'est valide ca ?
    Je n'avais jamais vu une pareille syntaxe, si c'est valide, que cela veut-il dire ??
    Oui, c'est tout à fait valide.

    Cela permet de déclarer un bloc avec une portée plus limitée sur la variables locales.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    void main(void)
    {
       int i = 12;
       // ici i vaut 12
     
       {
          int i = 15;
          // ici i vaut 15 et le compilateur ne crie pas en disant double déclaration de variable
       }
     
       // ici i vaut à nouveau 12
    }

    Je l'utilise plutôt dans les cases d'un switch pour masquer supprimer le warning des variable locales au case non utilisée
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    switch(variable)
    {
       case 1:
       {
          int i = 15;
       }
       break;
     
       case 2:
       // si dans le case 1, je ne mets pas d'acoolades de bloc
       // j'ai un warning ici "error C2360: l'initialisation de 'a' est ignorée par l'étiquette 'case'"
       break;
    }

  6. #6
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    104
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2007
    Messages : 104
    Points : 84
    Points
    84
    Par défaut
    Pour les paramètres de la fonction main(), j'ai dû copier coller une ancienne version... C'est corrigé.

    Pour les fonctions d'initialisation et de lecture du fichier tout va bien, fin la grille est bien remplie (j'avais ajouté une ligne de trop à l'exemple).

    Donc voilà, la grille ne se remplit pas cependant.

    Merci à vous.

    EDIT : tu as édité ton message en même temps que moi, l'appel à fseek est juste, si je mets 2 ça me met -38 dans la case.

  7. #7
    Expert éminent sénior
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Points : 13 926
    Points
    13 926
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    void
    solver_sudoku(int grille[][T_GRILLE], int taille) {
    ...
        for (k = 1; k <= N_POSSIBILITES; k++) {
    	grille[i][j] = k;
    	if (est_valide(grille, taille)) {
    	    solver_sudoku(grille, taille);
    	}
        }
    }
    - Et si k donne une grille invalide ? Maintenant on a mis l'invalide k dans grille[i][j] et il y reste !
    - Si k donne une grille valide, on entre dans la récursivité. Lorsqu'on sort de cet appel, on continue la boucle for et on écrase la valeur (valide) k dans grille[i][j]

  8. #8
    Membre émérite Avatar de SofEvans
    Homme Profil pro
    Développeur C
    Inscrit en
    Mars 2009
    Messages
    1 078
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France

    Informations professionnelles :
    Activité : Développeur C

    Informations forums :
    Inscription : Mars 2009
    Messages : 1 078
    Points : 2 339
    Points
    2 339
    Par défaut
    D'accord.

    Je ne connaissait vraiment pas.
    C'est bon a savoir car quand j'essayer de declarer une variable dans un switch, cela m'afficher une erreur. Je sais d'ou ca vient maintenant.

  9. #9
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    104
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2007
    Messages : 104
    Points : 84
    Points
    84
    Par défaut
    Alors pour le cas de la grille invalide ok, je remets la valeur à 0 au cas où mais je pensais surtout à résoudre des grilles valides ^^.

    Pour la boucle for qui reprend lorsqu'on sort de l'appel résursif, oui je suis d'accord. Donc en fait lorsqu'on sort de cet appel si la grille est finie (plus aucune case à 0) on quitte la fonction tout de suite. Sinon on laisse dérouler la boucle for car la solution n'était pas la bonne à une certaine profondeur.

    Ce qui me donne le code suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
    #define N_POSSIBILITES 9
    #define T_GRILLE 9
     
    void
    initialiser_grille(int grille[][T_GRILLE], int taille) {
     
        int i;
        int j;
     
        for (i = 0; i < taille; i++) {
    	for (j = 0; j < taille; j++) {
    	    grille[i][j] = 0;
    	}
        }
    }
     
    void
    lire_grille(FILE* fichier, int grille[][T_GRILLE], int taille) {
     
        int i;
        int j;
        int c;
     
        for (i = 0; i < taille; i++) {
    	for (j = 0; j < taille; j++) {
    	    c = fgetc(fichier);
    	    if (c != 0) {
    		grille[i][j] = c - '0';
    	    }
    	}
    	fseek(fichier, 1, SEEK_CUR);
        }
    }
     
    int
    est_complete(int grille[][T_GRILLE], int taille) {
     
        int i;
        int j;
     
        for (i = 0; i < taille; i++) {
    	for (j = 0; j < taille; j++) {
    	    if (grille[i][j] == 0) {
    		return 0;
    	    }
    	}
        }
     
        return 1;
    }
     
    int
    est_valide_ligne(int grille[][T_GRILLE], int taille, int ligne) {
     
        int i;
        int tableau[T_GRILLE] = {1, 1, 1, 1, 1, 1, 1, 1, 1};
     
        for (i = 0; i < taille; i++) {
    	if (grille[ligne][i] != 0) {	
    	    if (tableau[grille[ligne][i] - 1] == 0) {
    		return 0;
    	    }
    	    else {
    		tableau[grille[ligne][i] - 1] = 0;
    	    }
    	}
        }
     
        return 1;
    }
     
    int
    est_valide_colonne(int grille[][T_GRILLE], int taille, int colonne) {
     
        int i;
        int tableau[T_GRILLE] = {1, 1, 1, 1, 1, 1, 1, 1, 1};
     
        for (i = 0; i < taille; i++) {
    	if (grille[i][colonne] != 0) {
    	    if (tableau[grille[i][colonne] - 1] == 0) {
    		return 0;
    	    }
    	    else {
    		tableau[grille[i][colonne] - 1] = 0;
    	    }
    	}
        }
     
        return 1;
    }
     
     
    int
    est_valide_bloc(int grille[][T_GRILLE], int taille, int x, int y) {
     
        int i;
        int j;
        int tableau[T_GRILLE] = {1, 1, 1, 1, 1, 1, 1, 1, 1};
     
        for (i = x; i < x + 3; i++) {
    	for (j = y; j < y + 3; j++) {
    	    if (grille[i][j] != 0) {
    		if (tableau[grille[i][j] - 1] == 0) {
    		    return 0;
    		}
    		else {
    		    tableau[grille[i][j] - 1] = 0;
    		}		
    	    }
    	}
        }
     
        return 1;
    }
     
    int
    sont_valides_blocs(int grille[][T_GRILLE], int taille) {
     
        int i;
        int j;
     
        for (i = 0; i < taille; i += 3) {
    	for (j = 0; j < taille; j += 3) {
    	    if (! est_valide_bloc(grille, taille, i, j)) {
    		return 0;
    	    }
    	}
        }
     
        return 1;
    }
     
    int 
    est_valide(int grille[][T_GRILLE], int taille) {
     
        int i;
     
        for (i = 0; i < taille; i++) {
    	if (! est_valide_ligne(grille, taille, i) ||
    	    ! est_valide_colonne(grille, taille, i)) {
    	    return 0;
    	}
        }
        if (! sont_valides_blocs(grille, taille)) {
    	return 0;
        }
     
        return 1;
    }
     
    int
    trouver_case_vide(int grille[][T_GRILLE], int taille, int* x, int *y) {
     
        int i;
        int j;
     
        for (i = 0; i < taille; i++) {
    	for (j = 0; j < taille; j++) {
    	    if (grille[i][j] == 0) {
    		*x = i;
    		*y = j;
     
    		return 1;
    	    }
    	}
        }
     
        return 0;
    }
     
    void
    solver_sudoku(int grille[][T_GRILLE], int taille) {
     
        int i;
        int j;
        int k;
        int continuer = 1;
     
        if (! trouver_case_vide(grille, taille, &i, &j)) {
    	return;
        }
        for (k = 1; continuer && k <= N_POSSIBILITES; k++) {
    	grille[i][j] = k;
    	if (est_valide(grille, taille)) {
    	    solver_sudoku(grille, taille);
    	    if (est_complete(grille, taille)) {
    		return;
    	    }
    	}
    	else {
    	    grille[i][j] = 0;
    	}
        }
    }
     
    int
    main(int argc, char* argv[]) {
     
        int grille[T_GRILLE][T_GRILLE];
        FILE* fichier;
     
        if ((fichier = fopen(argv[1], "r")) == NULL) {
    	return -1;
        }
     
        initialiser_grille(grille, T_GRILLE);
        lire_grille(fichier, grille, T_GRILLE);
        solver_sudoku(grille, T_GRILLE);
     
        {
    	int i;
    	int j;
     
    	for (i = 0; i < T_GRILLE; i++) {
    	    for (j = 0; j < T_GRILLE; j++) {
    		printf("%d ", grille[i][j]);
    	    }
    	    printf("\n");
    	}
        }
     
        fclose(fichier);
     
        return 0;
    }
    Mais par contre ça ne fonctionne pas totalement (voire quasi pas du tout).

    Dans ma tête pour l'instant je raisonne comme ça :

    Je cherche une case valide je test si une des 9 valeurs est possible (logiquement y en a au moins une de possible sinon y a un problème plus grave). À partir de là dès que j'en ai une bonne récursion, je cherche une autre case et ainsi de suite.
    Si l'on sort de la fonction solver_sudoku avec une grille complète alors c'est fini on sort. Sinon c'est que la valeur n'était pas bonne et on laisse la boucle for continuée.

    Pourtant en théorie ça fonctionne (du moins dans ma tête ^^) mais alors en pratique...

    Merci.

  10. #10
    Expert éminent sénior
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Points : 13 926
    Points
    13 926
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    solver_sudoku(int grille[][T_GRILLE], int taille) {
    ...
        int continuer = 1;
    ...
        for (k = 1; continuer && k <= N_POSSIBILITES; k++) {...
    Visiblement continuer ne sert à rien, il est toujours à 1.

  11. #11
    Membre éprouvé Avatar de orfix
    Homme Profil pro
    Inscrit en
    Avril 2007
    Messages
    707
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Maroc

    Informations professionnelles :
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Avril 2007
    Messages : 707
    Points : 1 132
    Points
    1 132
    Par défaut
    J'ai regardé ton premier code, bien qu'il contienne quelques erreurs, tu es quand même sur le bon chemin.
    dans un premier temps essaies de corriger la lecture du fichier :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    void
    lire_grille(FILE* fichier, int grille[][T_GRILLE], int taille) {
     
        int i;
        int j;
        int c;
     
        for (i = 0; i < taille; i++) {
    	for (j = 0; j < taille; j++) {
    	    c = fgetc(fichier);
    	    if (c != 0) {
    		grille[i][j] = c - '0';
    	    }
    	}
    	fseek(fichier, 1, SEEK_CUR);
        }
    }
    je ne vois pas pourquoi tu utilises fseek, l'indicateur de positions avance automatiquement à chaque appel de fgetc, de plus tu devrais tester le retour de fgetc par rapport à EOF (fin de fichier ou erreur de lecture) et vérifier que c>='0' && c<='9' et par la même occasion sauter les '\n'.
    à présent tu peux te pencher sur solver_sudoku() :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    void
    solver_sudoku(int grille[][T_GRILLE], int taille) {
     
        int i;
        int j;
        int k;
     
        if (! trouver_case_vide(grille, taille, &i, &j)) {
    	return;
        }
        for (k = 1; k <= N_POSSIBILITES; k++) {
    	grille[i][j] = k;
    	if (est_valide(grille, taille)) {
    	    solver_sudoku(grille, taille);
    	}
        }
    }
    la fin de la boucle for indique que toutes les valeurs entre 0 et taille ne sont pas valides à cette position (grille[i][j]) tu devrais donc remettre les choses à leur place avec grille[i][j] = 0;
    et ta solution tu l'as quand il ne reste plus aucune case vide
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    void
    solver_sudoku(int grille[][T_GRILLE], int taille) {
     
    	int i;
    	int j;
    	int k;
     
    	if (! trouver_case_vide(grille, taille, &i, &j)) {
    		/* A cet endroit la grille est résolus ! */
    		return;
    	}
    	for (k = 1; k <= N_POSSIBILITES; k++) {
    		grille[i][j] = k;
    		if (est_valide(grille, taille)) {
    			solver_sudoku(grille, taille);
    		}
    	}
    	grille[i][j] = 0;
    }
    tu devrais donc mettre une valeur de retour pour solver_sudoku afin d'indiquer quand la solution a été trouvée (si solution il y a) et réagir en conséquence, car avec ton algo même quand la solution a été trouvée le backtrack continue.

    Bonne continuation.

  12. #12
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    104
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2007
    Messages : 104
    Points : 84
    Points
    84
    Par défaut
    Oui pardon à force de tester, j'avais oublié de remettre mon affectation...

    En fait je ne parviens pas à arrêter la boucle for au bon moment. Tel que je le vois, le seul moment où je peux l'arrêter c'est lorsque la grille est complète. Donc ce qui fait que la variable continuer est modifier dans la condition d'arrêt. Mais bon sans résultat...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
    #define N_POSSIBILITES 9
    #define T_GRILLE 9
     
    void
    initialiser_grille(int grille[][T_GRILLE], int taille) {
     
        int i;
        int j;
     
        for (i = 0; i < taille; i++) {
    	for (j = 0; j < taille; j++) {
    	    grille[i][j] = 0;
    	}
        }
    }
     
    void
    lire_grille(FILE* fichier, int grille[][T_GRILLE], int taille) {
     
        int i;
        int j;
        int c;
     
        for (i = 0; i < taille; i++) {
    	for (j = 0; j < taille; j++) {
    	    c = fgetc(fichier);
    	    if (c != 0) {
    		grille[i][j] = c - '0';
    	    }
    	}
    	fseek(fichier, 1, SEEK_CUR);
        }
    }
     
    int
    est_complete(int grille[][T_GRILLE], int taille) {
     
        int i;
        int j;
     
        for (i = 0; i < taille; i++) {
    	for (j = 0; j < taille; j++) {
    	    if (grille[i][j] == 0) {
    		return 0;
    	    }
    	}
        }
     
        return 1;
    }
     
    int
    est_valide_ligne(int grille[][T_GRILLE], int taille, int ligne) {
     
        int i;
        int tableau[T_GRILLE] = {1, 1, 1, 1, 1, 1, 1, 1, 1};
     
        for (i = 0; i < taille; i++) {
    	if (grille[ligne][i] != 0) {	
    	    if (tableau[grille[ligne][i] - 1] == 0) {
    		return 0;
    	    }
    	    else {
    		tableau[grille[ligne][i] - 1] = 0;
    	    }
    	}
        }
     
        return 1;
    }
     
    int
    est_valide_colonne(int grille[][T_GRILLE], int taille, int colonne) {
     
        int i;
        int tableau[T_GRILLE] = {1, 1, 1, 1, 1, 1, 1, 1, 1};
     
        for (i = 0; i < taille; i++) {
    	if (grille[i][colonne] != 0) {
    	    if (tableau[grille[i][colonne] - 1] == 0) {
    		return 0;
    	    }
    	    else {
    		tableau[grille[i][colonne] - 1] = 0;
    	    }
    	}
        }
     
        return 1;
    }
     
     
    int
    est_valide_bloc(int grille[][T_GRILLE], int taille, int x, int y) {
     
        int i;
        int j;
        int tableau[T_GRILLE] = {1, 1, 1, 1, 1, 1, 1, 1, 1};
     
        for (i = x; i < x + 3; i++) {
    	for (j = y; j < y + 3; j++) {
    	    if (grille[i][j] != 0) {
    		if (tableau[grille[i][j] - 1] == 0) {
    		    return 0;
    		}
    		else {
    		    tableau[grille[i][j] - 1] = 0;
    		}		
    	    }
    	}
        }
     
        return 1;
    }
     
    int
    sont_valides_blocs(int grille[][T_GRILLE], int taille) {
     
        int i;
        int j;
     
        for (i = 0; i < taille; i += 3) {
    	for (j = 0; j < taille; j += 3) {
    	    if (! est_valide_bloc(grille, taille, i, j)) {
    		return 0;
    	    }
    	}
        }
     
        return 1;
    }
     
    int 
    est_valide(int grille[][T_GRILLE], int taille) {
     
        int i;
     
        for (i = 0; i < taille; i++) {
    	if (! est_valide_ligne(grille, taille, i) ||
    	    ! est_valide_colonne(grille, taille, i)) {
    	    return 0;
    	}
        }
        if (! sont_valides_blocs(grille, taille)) {
    	return 0;
        }
     
        return 1;
    }
     
    int
    trouver_case_vide(int grille[][T_GRILLE], int taille, int* x, int *y) {
     
        int i;
        int j;
     
        for (i = 0; i < taille; i++) {
    	for (j = 0; j < taille; j++) {
    	    if (grille[i][j] == 0) {
    		*x = i;
    		*y = j;
     
    		return 1;
    	    }
    	}
        }
     
        return 0;
    }
     
    int continuer = 1;
     
    void
    solver_sudoku(int grille[][T_GRILLE], int taille) {
     
        int i;
        int j;
        int k;
     
        if (! trouver_case_vide(grille, taille, &i, &j)) {
    	continuer = 0;
        }
     
        for (k = 1; continuer && k <= N_POSSIBILITES; k++) {
    	grille[i][j] = k;
    	if (est_valide(grille, taille)) {
    	    solver_sudoku(grille, taille);
    	}
    	else {
    	    grille[i][j] = 0;
    	}
        }
    }
     
    int
    main(int argc, char* argv[]) {
     
        int grille[T_GRILLE][T_GRILLE];
        FILE* fichier;
     
        if ((fichier = fopen(argv[1], "r")) == NULL) {
    	return -1;
        }
     
        initialiser_grille(grille, T_GRILLE);
        lire_grille(fichier, grille, T_GRILLE);
        solver_sudoku(grille, T_GRILLE);
     
        {
    	int i;
    	int j;
     
    	for (i = 0; i < T_GRILLE; i++) {
    	    for (j = 0; j < T_GRILLE; j++) {
    		printf("%d ", grille[i][j]);
    	    }
    	    printf("\n");
    	}
        }
     
        fclose(fichier);
     
        return 0;
    }
    Merci à vous.

  13. #13
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    104
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2007
    Messages : 104
    Points : 84
    Points
    84
    Par défaut
    Bon c'est sûr ça fonctionne mieux quand on est réveillé... Donc en fait il fallait que j'utilise une fonction de type int pour savoir quand est-ce que je remonte ou quand est-ce que c'est bon (mise à 0 de la case ou pas).

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    int
    solver_sudoku(int grille[][T_GRILLE], int taille) {
     
        int i;
        int j;
        int k;
     
        if (! trouver_case_vide(grille, taille, &i, &j)) {
    	return 1;
        }
     
        for (k = 1; k <= N_POSSIBILITES; k++) {
    	grille[i][j] = k;
    	if (est_valide(grille, taille)) {
    	    if (solver_sudoku(grille, taille)) {
    		return 1;
    	    }
    	}
        }
        grille[i][j] = 0;
     
        return 0;
    }
    Voilà ça fonctionne...

    Merci à vous ;-)

    Bye.

    PS: la récursivité ça se travaille dis donc...

    PS2: je n'avais pas vu le message de ssmario2... C'est exactement ça ^^. Merci !

  14. #14
    Membre émérite Avatar de SofEvans
    Homme Profil pro
    Développeur C
    Inscrit en
    Mars 2009
    Messages
    1 078
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France

    Informations professionnelles :
    Activité : Développeur C

    Informations forums :
    Inscription : Mars 2009
    Messages : 1 078
    Points : 2 339
    Points
    2 339
    Par défaut
    Juste une remarque pour ameliorer ton code :
    La taille de ton sudoku est definie par

    #define T_GRILLE 9

    Tu n'as donc pas besoins de te trimballer une variable taille a travers tes fonction car tu as directment T_GRILLE.

    Aussi, tu as besoins d'ouvrir ton fichier dans l'initialisation, il n'est pas necessaire de le faire dans le main. Le mieux serait de deplacer toutes ta gestion du fichier dans la fonction 'lire_grille'.
    De plus, 'initialiser_grille' ne sert a rien, son role etant masquer par 'lire_grille'.

  15. #15
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    104
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2007
    Messages : 104
    Points : 84
    Points
    84
    Par défaut
    Pour la variable taille à trimballer justement, je me suis toujours posé la question. Donc toi du moment que la taille est une constante préprocesseur pas besoin de la remettre dans les paramètres de la fonction. Je le simplement si un jour j'ai besoin de réutiliser les fonctions en fait.

    Pour le lire grille et la gestion du fichier, je suis d'accord ;-)

    Merci à toi.

  16. #16
    Membre émérite Avatar de SofEvans
    Homme Profil pro
    Développeur C
    Inscrit en
    Mars 2009
    Messages
    1 078
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France

    Informations professionnelles :
    Activité : Développeur C

    Informations forums :
    Inscription : Mars 2009
    Messages : 1 078
    Points : 2 339
    Points
    2 339
    Par défaut
    La taille de la grille de sudoku est une constante, elle vaudra toujours 9. c'est un fait que tu ne peux changer (a moins que tu fasse un soduko qui va de 1 à 16).

    Par consequent, on a pas besoins de se trimballer une variable (qui est en realité une constante) à travers les fonction. On peut ecrire directement 9.

    Cependant, le jour ou tu voudra faire un sudoku de 12x12, tu va devoir retrouver toutes les valeurs 9, et c'est pas forcement gagner. Donc tu definie une constante preprocesseur. Comme ca, le jour ou tu voudra changer la taille, tout s'adaptera (si tu as bien coder) et tu n'aura rien a toucher (mis a part la valeur de cette constante preprocesseur).

  17. #17
    Expert éminent sénior
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Points : 13 926
    Points
    13 926
    Par défaut
    Si tu veux améliorer ton code, c'est peut-être la fonction est_valide() qu'il faut réformer : elle teste inutilement l'intégralité du tableau à chaque essai d'insertion de la valeur k en position (i,j) alors que seuls la ligne i, la colonne j et le bloc(i,j) sont concernés.
    On pourrait avoir :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    int
    est_valide(int grille[][T_GRILLE], int taille, int i, int j) {
      if(!est_valide_ligne(grille,taille,i))   return 0;
      if(!est_valide_colonne(grille,taille,j)) return 0;
       return est_valide_bloc(grille,taille,i,j);
    }
    .....
        for (k = 1; k <= N_POSSIBILITES; k++) {
    	grille[i][j] = k;
    	if (est_valide(grille, taille,i,j)) {
    .....

  18. #18
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    104
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2007
    Messages : 104
    Points : 84
    Points
    84
    Par défaut
    Oui effectivement la fonction qui va valide la grille est affreuse ^^.

    C'est surtout au niveau de la vérification du bloc que c'est moche. Donc je pensais à l'avenir utiliser une structure spéciale, dans laquelle je mémorise à quel bloc appartient la case correspondante.

    Je voulais surtout savoir ce qu'était le backtracking en faisant ça (c'est en découvrant le défi C et la seule solution qui me vient à l'esprit est dans le même style).

    Enfin pour le sudoku j'ai d'autres idées que je présenterai une fois réalisées.

    Merci et à bientôt ;-)

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Résolution de Sudoku par backtracking
    Par pottiez dans le forum Télécharger
    Réponses: 2
    Dernier message: 16/04/2014, 03h01
  2. Réponses: 0
    Dernier message: 30/11/2010, 15h46
  3. [Java] Résolution de Sudoku par backtracking
    Par pseudocode dans le forum Contribuez
    Réponses: 1
    Dernier message: 04/01/2009, 12h58
  4. probleme : resolveur de sudoku par backtracking
    Par gnouz dans le forum Algorithmes et structures de données
    Réponses: 8
    Dernier message: 14/09/2008, 14h18
  5. Résolution SuDoKu récursif BackTrack
    Par kawasaki dans le forum Langage
    Réponses: 0
    Dernier message: 20/12/2007, 16h33

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo