Ledger Nano X - The secure hardware wallet
SHARE
TWEET

Projet

Swih Apr 10th, 2020 659 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // Projet   : Sudoku/Hexadoku partiel 2017/2020 pour le projet de programmation
  2. //          : en DEUST IOSI 1 - UPHF/INSA (c) 2015-2020
  3. // Auteur   : D. Duvivier
  4. // Version  : 1.2.2
  5. // Date     : 09/04/20
  6. // Licence  : Exclusivement utilisable dans le cadre du Projet de programmation
  7. //          : informatique en DEUST IOSI 1 - UPHF/ISTV (c) 2015-2019
  8. // Limites  : Cette version ne teste aucun code de retour (de scanf & ...).
  9. //          : Elle ne teste pas non plus la validité des paramètres...
  10. //          : TODO: A vous de le faire !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  11. //
  12. //////////////////////////////////////////////////////////////////////////////
  13. // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //
  14. // !VERSION COMPLETE, SANS TEST SUR LES PARAMETRES ET LES CODES DE RETOUR ! //
  15. // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //
  16. // !!!! VERSION PARTIELLE DEDIÉE AU PROJET DE PROGRAMMATION (HEXADOKU) !!!! //
  17. // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //
  18. //////////////////////////////////////////////////////////////////////////////
  19. //
  20. // Le format du fichier lu est celui qui a été étudié en TD.
  21. // Bien que seules des grilles de sudoku/hexadoku soient lues dans les fichiers
  22. // pour ce programme. Le format utilisé permet de considérer différents types
  23. // de jeux :
  24. // - jeu de "Dames", "Échecs" ou autre jeu avec grille régulière
  25. // - jeu de sudoku avec des régions (par exemple 3 lignes et 3 colonnes par
  26. //   région et 9 * 9 cases au total, ou 4 lignes et 4 colonnes par
  27. //   région et 16 * 16 cases au total)
  28. // - jeu de type "PacMan" ou "Labyrinthe" ou "Casse-Briques" où la grille de
  29. //   base est vide mais le "décor" est lu depuis le fichier en question
  30. //
  31. // Le format utilisé est donc le suivant pour les trois premières lignes de
  32. // chaque fichier :
  33. // nombre_de_lignes nombre_de_colonnes taille_region
  34. // <caractere_vide_dans_fichier>
  35. // caractere_vide_dans_grille s1 s2 s3 s4...
  36. //
  37. // ATTENTION : Le caractère "espace" (i.e. ' ') n'est pas autorisé dans les
  38. // fichiers en tant que "symbole" puisqu'il est utilisé comme séparateur par
  39. // scanf & cie (cf premiers TD de méthodologie).
  40. // Nous utilisons donc le caractère "_" pour remplacer l'espace dans le
  41. // fichier.
  42. //
  43. // Voici les explications détaillées :
  44. // 1) Sur la première ligne, il y a trois valeurs numériques positives ou nulles :
  45. //  - nombre_de_lignes   : nombre de lignes au total dans la grille
  46. //  - nombre_de_colonnes : nombre de colonnes au total dans la grille
  47. //  - taille_region      : taille de région
  48. //    0 si la grille initiale est vide ("PacMan" ou "Labyrinthe" ou "Casse-Briques")
  49. //    1 si la grille est régulière ("Dames", "Échecs")
  50. //    2, 3, 4 ou 5 pour une grille avec régions 2*2, 3*3, 4*4 ou 5*5 ("Sudoku")
  51. // 2) Sur la deuxième ligne, il y a 3 caractères :
  52. //   - le caractère '<'
  53. //   - le caractère caractere_vide_dans_fichier qui correspond à une case vide
  54. //     dans la grille stockée dans le fichier (par exemple le caractère '.')
  55. //   - le caractère '>'
  56. // 3) Sur la troisième ligne, il y a AU MAXIMUM une suite de MAXCOLONNES caractères et le premier
  57. //    caractère est le caractere_vide_dans_grille ou s0 (pour symbole N°0), le second caractère
  58. //    est appelé s1 (pour symbole N°1), le troisième caractère est appelé s2 et ainsi de suite...
  59. //    Le caractere_vide_dans_grille ou s0 correspond à une case vide affichée à l'écran dans la grille
  60. //    (par exemple le caractère '_').
  61. // Dans l'exemple ci-dessus, le symbole '.' lu dans le fichier est transformé en caractère '_',
  62. // qui est lui même remplacé par un espace ' '
  63. // dans la grille affichée pour éviter les problèmes avec les espaces, considérés comme des séparateurs
  64. // dans les fichiers texte (i.e. si nous utilisons scanf & cie)...
  65. //
  66. #include <stdio.h>
  67. #include <stdlib.h>
  68. #include <ctype.h>
  69. #include <string.h>
  70. #include <math.h>
  71. #include <unistd.h>
  72.  
  73. // Taille (maxi) de la grille de jeu
  74. #define MAXLIGNES   25
  75. #define MAXCOLONNES 25
  76.  
  77. // Nombre de grilles au menu
  78. #define NBGRILLES 26
  79.  
  80. const char *NomsGrilles[] = {
  81.     "grille04x04_00.dat",
  82.     "grille09x09_00.dat",
  83.     "grille09x09_01_facile0.dat",
  84.     "grille09x09_02_facile1.dat",
  85.     "grille09x09_03_moyenne.dat",
  86.     "grille09x09_04_moyenne.dat",
  87.     "grille09x09_05_difficile.dat",
  88.     "grille09x09_06_difficile.dat",
  89.     "grille09x09_07_difficile.dat",
  90.     "grille09x09_08_difficile.dat",
  91.     "grille09x09_09_difficile.dat",
  92.     "grille09x09_10_diabolique.dat",
  93.     "grille09x09_11_diabolique.dat",
  94.     "grille09x09_12_diabolique.dat",
  95.     "grille09x09_13_diabolique.dat",
  96.     "grille09x09_14_12cases.dat",
  97.     "grille09x09_15_17cases.dat",
  98.     "grille09x09_16_17cases0.dat",
  99.     "grille09x09_17_vide.dat",
  100.     "grille09x09_18_pleine.dat",
  101.     "grille09x09_19_unediagonale0.dat",
  102.     "grille09x09_20_unparregion0.dat",
  103.     "grille09x09_21_incorrecteligne.dat",
  104.     "grille09x09_22_incorrectecolonne.dat",
  105.     "grille09x09_23_incorrecteregion.dat",
  106.     "grille09x09_24_infaisable.dat",
  107.     "grille16x16_00.dat"
  108. };
  109.  
  110. //Quelque couleur pour avoir une vie en couleurs !
  111. #define ANSI_COLOR_RED     "\x1b[31m"
  112. #define ANSI_COLOR_GREEN   "\x1b[32m"
  113. #define ANSI_COLOR_YELLOW  "\x1b[33m"
  114. #define ANSI_COLOR_BLUE    "\x1b[34m"
  115. #define ANSI_COLOR_MAGENTA "\x1b[35m"
  116. #define ANSI_COLOR_CYAN    "\x1b[36m"
  117. #define ANSI_COLOR_RESET   "\x1b[0m"
  118.  
  119. // Nombre maxi de symboles (caractères) différents dans la grille + espace
  120. #define MAXSYMBOLES (MAXCOLONNES+1)
  121.  
  122. // Nombre de "symboles" par case. Pour des chiffres de 1 à 9 → MAXPLANS = 9
  123. // TODO : Question : Est-ce MAXSYMBOLES ou MAXCOLONNES qu'il faut utiliser ci-dessous ?
  124. #define MAXPLANS MAXSYMBOLES
  125.  
  126. // Caractère utilisé pour représenter un espace dans le fichier
  127. #define SYMBOLESPACE '_'
  128.  
  129. // Valeurs du paramètre 0 pour AfficheErreur
  130. #define STOPEXIT 1   // Mode "sauvage"
  131. #define STOPRETURN 0 // Mode "return" + gestion des codes de retour
  132.  
  133. // La taille des régions est obtenue directement depuis la lecture du fichier
  134. // contenant une grille
  135.  
  136. #define false 0
  137. #define true (!0)
  138.  
  139. #define CARGRILLEVIDE ((symboles[0] == SYMBOLESPACE) ? ' ' : symboles[0])
  140.  
  141. // Type "Tgrille2D".
  142. // Ci-dessous nous utilisons le type de base "caractère" pour faciliter
  143. // l'affichage
  144. typedef char TGrille2D[MAXLIGNES][MAXCOLONNES];
  145.  
  146. // Ci-dessous, la 3ème dimension est indépendante de la taille de grille.
  147. // Elle correspond à un plan faisant le cumul des possibilités par case
  148. // en guise de plan 0 (conformément à ce qui est précisé dans l'énoncé),
  149. // suivi des "plans" pour chaque chiffre/symbole en allant de 1 à MAXPLANS :
  150. typedef int TGrille3D[MAXLIGNES][MAXCOLONNES][MAXPLANS+1];
  151.  
  152. // Définition d'un type « pseudo-booléen » :
  153. typedef short int bool;
  154.  
  155. // Définition d'un tableau de booléen (pour tester l'unicité des symboles en ligne, en colonne ou en région...) :
  156. typedef bool TBool[MAXPLANS+1];
  157.  
  158. // Selon l'algorithme de résolution utilisé, il peut être intéressant pour éviter les boucles infinies, de
  159. // « marquer » (par un booléen placé à vrai) chaque case déjà visitée par l'algorithme, ce qui induit la
  160. // définition suivante :
  161. // Grille de marques (si votre algorithme a besoin de déterminer quelle(s) case(s) a/ont déjà été « explorée(s) ») :
  162. typedef bool TMarques[MAXLIGNES][MAXCOLONNES];
  163.  
  164. // Pour permettre un jeu « interactif » ou mémoriser une position et/ou un coup joué, il peut être très utile de
  165. // définir les deux types suivants :
  166. // Position sur la grille (cela peut être utile) :
  167. typedef struct {
  168.     int ligne, colonne;
  169. } TPosition;
  170.  
  171. // Un coup joué sur la grille :
  172. typedef struct {
  173.     int ligne, colonne;
  174.     int symbole; // Numéro du symbole (1 est le premier symbole, 2 le second...)
  175. } TCoupJoue;
  176.  
  177. // Pile des coups joués :
  178. typedef TCoupJoue TTabCoupJoue[MAXCOLONNES*MAXLIGNES]; // Nombre de coups au maxi
  179. typedef struct {
  180.     int sommet; // Sommet de pile
  181.     TTabCoupJoue tab; // Tableau contenant la pile
  182. } TPileCoupsJoues;
  183.  
  184. //-----------------------------------------------------------------------------
  185. // Calcule la racine entière du nombre passé en paramètre.
  186. //
  187. // Retourne 0 si le nombre passé en paramètre est inférieur à 4
  188. // ou s'il n'est pas un carré.
  189. // Retourne la racine carrée du nombre passé en paramètre sinon.
  190. int RacineEntiere(const int NombreAuCarre) {
  191.     int RacineEntiere = sqrt(NombreAuCarre);
  192.     if ((NombreAuCarre < 4) || (RacineEntiere * RacineEntiere != NombreAuCarre))
  193.         return 0;
  194.     else
  195.         return RacineEntiere;
  196. }
  197.  
  198. // Affiche une erreur sur le canal prévu à cet effet (stderr).
  199. // Le paramètre "stoppersauvagement" indique si cette procédure stoppe
  200. // "sauvagement" le programme en utilisant exit ou non :
  201. // - si stoppersauvagement est différent de 0, on utilise exit()
  202. // - si stoppersauvagement est égal à 0, on retourne -1
  203. //   et exit n'est pas utilisé
  204. int AfficheErreur(char *message, int stoppersauvagement) {
  205.     fprintf(stderr,"#\n# ERREUR: %s !\n#\n", message);
  206.     if (stoppersauvagement != 0)
  207.         exit(1);
  208.     return -1;
  209. }
  210.  
  211. // Vider buffer clavier quel que soit le nombre de caractères à lire/vider
  212. void viderbuffer(void) {
  213.     scanf("%*[^\n]");
  214. }
  215.  
  216. void yellow() {
  217.     printf("\033[1;33m");
  218. }
  219.  
  220. void red() {
  221.     printf("\033[1;31m");
  222. }
  223.  
  224. void reset() {
  225.      printf("\033[0m");
  226. }
  227. // Détecte le chemin courant pour accéder aux grille du Sudoku/Hexadoku
  228. //          : programmation en DEUST IOSI 1 - UPHF/INSA (c) 2015-2020
  229. //
  230. // Limites  :
  231. // - Cette version ne fait pas la différence entre Windows et MAC...
  232. // - Le chemin est limité à 256 caractères et ceci n'est pas testé --> TODO
  233. //
  234. char *CheminGrilles(void) {
  235.     static char chemin[256]; // chemin d'accès absolu du répertoire de travail courant
  236.    
  237.     if (!getcwd(chemin, 255))
  238.         AfficheErreur("Impossible d'accéder au chemin courant !", STOPEXIT);
  239.    
  240.     // Une fois que cela fonctionne, vous pouvez commenter la ligne suivante :
  241.     printf("Chemin courant : %s\n\n", chemin);
  242.    
  243.     // Ajouter "grilles_04_09_16_25" en fin de chemin courant
  244.     // en détectant l'OS (Linux ou... le reste) :
  245.     if (chemin[0] == '/') {
  246.         // Une fois que cela fonctionne, vous pouvez commenter la ligne suivante :
  247.         puts("C'est bien, vous êtes sous Linux...");
  248.         strcat(chemin, "/grilles_04_09_16_25/");
  249.     }
  250.     else {
  251.         // Une fois que cela fonctionne, vous pouvez commenter la ligne suivante :
  252.         puts("C'est mal, vous n'êtes pas sous Linux...");
  253.         strcat(chemin, "\\grilles_04_09_16_25\\");
  254.     }
  255.     printf("Chemin des grilles : %s\n\n", chemin);
  256.    
  257.     return chemin;
  258. }
  259.  
  260. // Retourne le nom de la grille sélectionnée
  261. // ou "" (chaîne vide) en cas d'erreur
  262. //
  263. // TODO : Durcir la saisie
  264. //
  265. char *ChoixGrille(void) {
  266.     int numgrille; // Numéro de la grille sélectionnée
  267.     int i; // Boucle de parcours des noms de grilles
  268.     int numbool = 0;
  269.     for (i=0; i < NBGRILLES + 1; i++)
  270.          printf("(%2d) - %s\n", i, NomsGrilles[i]);
  271.     puts("\nVeuillez entrer un numéro de la grille entre 0 et 26 (ou -1 pour quitter) :");
  272.     do {
  273.         scanf("%d", &numgrille);
  274.         if (numgrille > 0 && numgrille < 27)
  275.             numbool=1;
  276.         else {
  277.             viderbuffer();
  278.             puts("\nSaissiez un valeur valide si vous voulez jouer ! (entre -1 et 26 !) :");
  279.         }
  280.     } while (numbool != 1);
  281.    
  282.     if (numgrille < 0)
  283.         return "";
  284.     else
  285.         return NomsGrilles[numgrille];
  286. }
  287.  
  288. // Initialise/"vide" la pile des coups joués
  289. void initPileCoupsJoues(TPileCoupsJoues *pile) {
  290.     pile->sommet = -1; // Signale pile vide
  291. }
  292.  
  293. // Position du sommet de pile de la pile des coups joués
  294. int lireSommetPileCoupsJoues(TPileCoupsJoues pile) {
  295.     return (pile.sommet);
  296. }
  297.  
  298. // Nombre de coups joués mémorisés en pile
  299. int nombreCoupsJoues(TPileCoupsJoues pile) {
  300.     return (pile.sommet + 1);
  301. }
  302.  
  303. // Retourne vrai si la pile est vide
  304. // faux sinon
  305. bool pileVide(TPileCoupsJoues pile) {
  306.     return pile.sommet < 0;
  307. }
  308.  
  309. // Retourne vrai si la pile est pleine
  310. // faux sinon
  311. bool pilePleine(TPileCoupsJoues pile) {
  312.     return pile.sommet >= (MAXCOLONNES*MAXLIGNES) - 1;
  313. }
  314.  
  315. // Empile le (dernier) coup joué
  316. // Mode préincrémenté
  317. //
  318. // ATTENTION : AUCUN CONTROLE EFFECTUE
  319. //
  320. void empileCoupJoue(TPileCoupsJoues *pile, int ligne, int colonne, int symbole) {
  321.     // TODO: Vérifier si la pile n'est pas pleine
  322.     pile->sommet++;
  323.     pile->tab[pile->sommet] = (TCoupJoue){ligne, colonne, symbole};
  324. }
  325.  
  326. // Dépile le (dernier) coup joué
  327. // Mode postdécrémenté
  328. //
  329. // ATTENTION : AUCUN CONTROLE EFFECTUE
  330. //
  331. void depileCoupJoue(TPileCoupsJoues *pile, int *ligne, int *colonne, int *symbole) {
  332.     // TODO: Vérifier si la pile n'est pas vide
  333.     TCoupJoue coupjoue = pile->tab[pile->sommet];
  334.    
  335.     *ligne = coupjoue.ligne;
  336.     *colonne = coupjoue.colonne;
  337.     *symbole = coupjoue.symbole;
  338.     pile->sommet--;
  339. }
  340.  
  341. // Convertit un N° de plan (entre 1 et nbsymboles)
  342. // en un caractère utilisable dans la grille de jeu
  343. //
  344. // Retourne '\0' si le numéro de plan est incorrect
  345. //
  346. char plan2char(const char *symboles, const int nbsymboles, const int plan) {
  347.     if ((plan < 1) || (plan > nbsymboles))
  348.         return '\0';
  349.    
  350.     return symboles[plan];
  351. }
  352.  
  353. // Convertit un caractère (symbole situé dans la grille de jeu)
  354. // en un N° de plan (entre 1 et GTaille)
  355. // en un caractère utilisable dans la grille de jeu
  356. //
  357. // La suite des symboles n'est pas nécessairement triée, ce qui
  358. // fait que cette fonction utilise une recherche séquentielle dans
  359. // un tableau d'éléments non triés (non efficace).
  360. //
  361. // Retourne 0 si le caractère incorrect
  362. //
  363. // Remarque : Cette fonction peut être utilisée pour vérifier si le
  364. // symbole saisi par l'utilisateur, lors de la saisie d'un coup à jouer,
  365. // est correct (code de retour > 0) ou non (code de retour = 0)
  366. //
  367. int char2plan(const char *symboles, const int nbsymboles,
  368.               const char code)
  369. {
  370.     int plan;
  371.    
  372.     for (plan=1; plan<=nbsymboles; plan++)
  373.         if (symboles[plan] == code)
  374.             return plan;
  375.    
  376.     return 0; // Non trouvé !
  377. }
  378.  
  379. // Initialise la grille 2D en la remplissant de caractères passés via le paramètre s0.
  380. // TODO: Ajouter un code de retour (si nécessaire)
  381. void InitGrille2D(TGrille2D grille2D, char s0)
  382. {
  383.     int i, j;
  384.     for (i=0; i<MAXLIGNES; i++)
  385.         for (j=0; j<MAXCOLONNES; j++)
  386.             grille2D[i][j] = s0;
  387. }
  388.  
  389. // Initialise/vide la grille des compteurs passée en paramètre
  390. void InitGrille3D(TGrille3D grille3D)
  391. {
  392.     int i, j, k;
  393.     for (i=0; i<MAXLIGNES; i++)
  394.         for (j=0; j<MAXCOLONNES; j++)
  395.             for (k=0; k<=MAXPLANS; k++)
  396.                 grille3D[i][j][k] = 0;
  397. }
  398.  
  399. // Fonction interne (i.e. non visible dans l'API présentée à l'utilisateur).
  400. // AfficherGrilleRegionsSeparation affiche une ligne de séparation pour mettre
  401. // en forme le contenu de la grille comme un tableau
  402. // de "lignes" lignes de "colonnes" caractères chacune,
  403. // tailleregion est la taille de région (forcément > 1) :
  404. //    2, 3, 4 ou 5 pour une grille avec régions
  405. // TODO: Ajouter un code de retour (si nécessaire)
  406. int AfficherGrilleRegionsSeparation(int lignes, int colonnes,
  407.                                     int tailleregion, int numeroligne)
  408. {
  409.     int j;
  410.    
  411.     if (numeroligne < 0 || numeroligne >= lignes)
  412.         return AfficheErreur("AfficherGrilleRegionsSeparation: Numéro de ligne incorrect", STOPRETURN);
  413.    
  414.     printf("*"); // Bord gauche
  415.     // La ligne de séparation change en fonction de la taille des régions
  416.     // (en fonction du numéro de ligne)
  417.     if ((numeroligne % tailleregion) != 0)
  418.     {
  419.         for (j=0; j<colonnes; j++)
  420.         {
  421.             if ((j % tailleregion) != 0)
  422.                 printf("+---");
  423.             else
  424.                 printf("*---");
  425.         }
  426.         if ((colonnes % tailleregion) != 0)
  427.             puts("|*");
  428.         else
  429.             puts("**");
  430.     }
  431.     else
  432.     {
  433.         for (j=0; j<colonnes; j++)
  434.             printf("****");
  435.         puts("**");
  436.     }
  437.    
  438.     return 0;
  439. }
  440.  
  441. // Fonction interne (i.e. non visible dans l'API présentée à l'utilisateur).
  442. // AfficherGrilleRegionsDonnees affiche une ligne de donnees issues du
  443. // contenu de la grille stockée dans un tableau
  444. // de "lignes" lignes de "colonnes" caractères chacune,
  445. // tailleregion est la taille de région (forcément > 1) :
  446. //    2, 3, 4 ou 5 pour une grille avec régions
  447. // TODO: Ajouter un code de retour (si nécessaire)
  448. int AfficherGrilleRegionsDonnees(TGrille2D grille2D, int lignes, int colonnes,
  449.                                  int tailleregion, int numeroligne)
  450. {
  451.     int j;
  452.    
  453.     if (numeroligne < 0 || numeroligne >= lignes)
  454.         return AfficheErreur("AfficherGrilleRegionsDonnees: Numéro de ligne incorrect", STOPRETURN);
  455.    
  456.     printf("*"); // Bord gauche
  457.     for (j=0; j<colonnes; j++)
  458.     {
  459.         if ((j % tailleregion) != 0)
  460.             printf("| %c ", grille2D[numeroligne][j]);
  461.         else
  462.             printf("* %c ", grille2D[numeroligne][j]);
  463.     }
  464.     if ((colonnes % tailleregion) != 0)
  465.         puts("|*");
  466.     else
  467.         puts("**");
  468.    
  469.     return 0;
  470. }
  471.  
  472. // AfficherGrille affiche le contenu de la grille comme un tableau
  473. // de "lignes" lignes de "colonnes" caractères chacune,
  474. // tailleregion est la taille de région (forcément > 1).
  475. // TODO: Ajouter/gérer un code de retour (si nécessaire)
  476. int AfficherGrille2D(TGrille2D grille2D, int lignes, int colonnes, int tailleregion)
  477. {
  478.     int i, j;
  479.     puts("");
  480.     // Première ligne au dessus de la grille:
  481.     for (j=0; j<2+4*colonnes; j++)
  482.         printf("*");
  483.     puts("*");
  484.    
  485.     for (i=0; i<lignes; i++)
  486.     {
  487.         AfficherGrilleRegionsSeparation(lignes, colonnes, tailleregion, i);
  488.         AfficherGrilleRegionsDonnees(grille2D, lignes, colonnes, tailleregion, i);
  489.     } // for i
  490.    
  491.     // Dernières lignes en dessous de la grille:
  492.     for (j=0; j<2+4*colonnes; j++)
  493.         printf("*");
  494.     puts("*");
  495.     for (j=0; j<2+4*colonnes; j++)
  496.         printf("*");
  497.     puts("*");
  498.    
  499.     return 0;
  500. }
  501.  
  502. // Lecture de la taille de la grille stockée dans le fichier
  503. // dont le nom est passé en paramètre.
  504. //
  505. // Dans cette version, seules les grilles carrées sont autorisées
  506. //
  507. // Retourne 0 si :
  508. // - le fichier n'existe pas,
  509. // - la taille est < 4,
  510. // - le fichier ne commence pas par deux entiers positifs,
  511. // - ou si le nombre de colonnes est différent du nombre de lignes
  512. // Retourne le nombre de lignes (et de colonnes) dans les autres cas.
  513. //
  514. // ATTENTION : Cette fonction ouvre et ferme le fichier.
  515. //
  516. int lireTailleGrille2D(const char *Nom)
  517. {
  518.     FILE *fgrille; // Fichier contenant la grille
  519.     int l, c;
  520.    
  521.     if ((fgrille = fopen(Nom, "r")) == NULL)
  522.         return 0; // Fichier introuvable !
  523.    
  524.     if (fscanf(fgrille, "%d %d", &l, &c) != 2) {
  525.         fclose(fgrille);
  526.         return 0; // Impossible de lire deux entiers dans le fichier
  527.     }
  528.    
  529.     if ((l < 4) || (c < 4) || (l != c)) {
  530.         fclose(fgrille);
  531.         return 0; // Valeurs incorrectes ou grille non carrée
  532.     }
  533.    
  534.     fclose(fgrille); // On ferme... !!!
  535.    
  536.     return l; // Comme l == c il est possible de retourner l'un ou l'autre
  537. }
  538.  
  539.  
  540. // LireGrille permet de lire une grille de jeu depuis un fichier.
  541. // Le format du fichier lu doit permettre de considérer différents types de
  542. // jeux comme expliqué en tête de ce programme.
  543. // "Nom" est le nom du fichier contenant la grille ;
  544. // "grille2D" est le tableau 2D qui doit recevoir la grille ;
  545. // "lignes" et "colonnes" contiennent la taille de la grille lue ;
  546. // "tailleregion" contient la taille de région lue depuis le fichier ;
  547. // "carvide" est le caractère caractere_vide_dans_fichier qui correspond
  548. // à une case vide dans la grille stockée dans le fichier ;
  549. // "symboles" contient le tableau de caractères correspondant aux symboles
  550. // autorisés dans la grille de jeu, avec le premier symbole "s0"
  551. // qui correspond à une case vide affichée à l'écran dans la grille.
  552. //
  553. // TODO: Ajouter et gérer un code de retour (si nécessaire)
  554. // TODO: Dans cette version, la fonction LireGrille est stoppée "sauvagement"
  555. // via un "exit" dans la fonction AfficheErreur
  556. // --> Utilisez AfficheErreur avec la valeur "0" pour second paramètre
  557. // et récupérez proprement les codes de retour en informant au final
  558. // l'utilisateur (i.e. LireGrille retourne -1 en cas d'erreur).
  559. // N'oubliez pas de "fermer" le fichier si l'erreur se produit alors que
  560. // le fichier a pu être ouvert !
  561. int LireGrille2D(char *Nom, TGrille2D grille2D, int *lignes, int *colonnes,
  562.                  int *tailleregion, char *carvide, char *symboles)
  563. {
  564.     FILE *fgrille;
  565.     int l, c;
  566.     char chainecarvide[4]; // Prévu pour 3 caractères + \0 pour lire carvide
  567.    
  568.     if((fgrille = fopen(Nom, "r")) == NULL)
  569.         AfficheErreur("LireGrille: fichier introuvable", STOPEXIT);
  570.    
  571.     if(fscanf(fgrille, "%d %d %d", lignes, colonnes, tailleregion) != 3)
  572.         AfficheErreur("LireGrille: lignes et/ou colonnes et/ou tailleregion introuvable(s) dans le fichier", STOPEXIT);
  573.    
  574.     // Une grille inférieure à 4*4 est incorrecte
  575.     if (*lignes < 4 || *colonnes < 4 || *lignes > MAXLIGNES || *colonnes > MAXCOLONNES ||
  576.         *tailleregion < 0 || *tailleregion > *lignes || *tailleregion > *colonnes)
  577.         AfficheErreur("LireGrille: Valeur incorrecte de lignes et/ou colonnes et/ou taillerégion dans le fichier", STOPEXIT);
  578.    
  579.     if (*tailleregion > 1 && (((*lignes % *tailleregion) != 0) || ((*colonnes % *tailleregion) != 0)))
  580.         AfficheErreur("LireGrille: lignes et/ou colonnes doivent être multiples de la taille de la région", STOPEXIT);
  581.    
  582.     // Ci-dessous l'utilisation de "%c" complique le code
  583.     // --> Il est préférable de passer par "%s" et de récupérer le second caractère s'il existe.
  584.     // --> Si vous connaissez fgets, c'est préférable à scanf car plus rapide,
  585.     //     + permet de fixer la taille de chaine de caractères
  586.     //     + de savoir combien de CARACTERES ont été lus
  587.     if(fscanf(fgrille, "%3s", chainecarvide) != 1)
  588.         AfficheErreur("LireGrille2D: <carvide> introuvable dans le fichier", STOPEXIT);
  589.    
  590.     if (strlen(chainecarvide) != 3)
  591.         AfficheErreur("LireGrille2D: Format incorrect pour <carvide> dans le fichier", STOPEXIT);
  592.    
  593.     *carvide = chainecarvide[1]; // Récupère le second caractère dans <carvide>
  594.    
  595.     // --> Si vous connaissez fgets, c'est préférable à scanf car plus rapide,
  596.     //     + permet de fixer la taille de chaine de caractères
  597.     //     + de savoir combien de CARACTERES ont été lus
  598.     //     Ici cela donnerait qqchose du genre :
  599.     //     fgets(symboles, MAXSYMBOLES, fgrille);
  600.     //
  601.     // ATTENTION : Ci-dessous, il faudrait limiter la taille de chaine de caractères
  602.     // à MAXSYMBOLE pour éviter problèmes de type "débordement de buffer"
  603.     // --> Est-ce possible avec fscanf ?
  604.     if(fscanf(fgrille, "%s", symboles) != 1)
  605.         AfficheErreur("LireGrille2D: symboles introuvables dans le fichier", STOPEXIT);
  606.    
  607.     for (l=0; l<*lignes; l++)
  608.     {
  609.         for (c=0; c<*colonnes; c++)
  610.         {
  611.             if (feof(fgrille) || (fscanf(fgrille, " %c", &grille2D[l][c]) != 1))
  612.                 AfficheErreur("LireGrille: donnée manquante dans le fichier", STOPEXIT);
  613.             // Premier remplacement : Remplacer carvide par s0 ?
  614.             if (grille2D[l][c] == *carvide)
  615.                 grille2D[l][c] = symboles[0];
  616.             // Deuxième remplacement : Remplacer SYMBOLESPACE par espace (' ') ?
  617.             if (grille2D[l][c] == SYMBOLESPACE)
  618.                 grille2D[l][c] = ' ';
  619.         }  // for c
  620.     } // for l
  621.    
  622.     fclose(fgrille);
  623.     return 0;
  624. }
  625.  
  626. // EcrireGrille2D permet d'écrire une grille2D de jeu dans un fichier.
  627. // Le format du fichier écrit doit permettre de considérer différents types de
  628. // jeux comme expliqué en tête de ce programme.
  629. // "Nom" est le nom du fichier contenant la grille 2D ;
  630. // "grille2D" est le tableau 2D qui doit recevoir la grille ;
  631. // "lignes" et "colonnes" contiennent la taille de la grille lue ;
  632. // "tailleregion" contient la taille de région lue depuis le fichier ;
  633. // "carvide" est le caractère caractere_vide_dans_fichier qui correspond
  634. // à une case vide dans la grille stockée dans le fichier ;
  635. // "symboles" contient le tableau de caractères correspondant aux symboles
  636. // autorisés dans la grille de jeu, avec le premier symbole "s0"
  637. // qui correspond à une case vide affichée à l'écran dans la grille.
  638. //
  639. // TODO: Ajouter et gérer un code de retour (si nécessaire)
  640. // TODO: Dans cette version, la fonction EcrireGrille est stoppée "sauvagement"
  641. // via un "exit" dans la fonction AfficheErreur
  642. // --> Utilisez AfficheErreur avec la valeur "0" pour second paramètre
  643. // et récupérez proprement les codes de retour en informant au final
  644. // l'utilisateur (i.e. LireGrille retourne -1 en cas d'erreur).
  645. // N'oubliez pas de "fermer" le fichier si l'erreur se produit alors que
  646. // le fichier a pu être ouvert !
  647. int EcrireGrille2D(char *Nom, TGrille2D grille2D, int lignes, int colonnes,
  648.                    int tailleregion, char carvide, char *symboles)
  649. {
  650.     FILE *fgrille;
  651.     int l, c;
  652.     char element; // Element en position [l](c] de la grille
  653.    
  654.     if((fgrille = fopen(Nom, "w")) == NULL)
  655.         AfficheErreur("EcrireGrille2D: impossible de créer le fichier", STOPEXIT);
  656.    
  657.     if(fprintf(fgrille, "%d %d %d\n", lignes, colonnes, tailleregion) <= 0)
  658.         AfficheErreur("EcrireGrille2D: impossible d'écrire lignes et/ou colonnes et/ou tailleregion dans le fichier", STOPEXIT);
  659.    
  660.     // Une grille inférieure à 4*4 est incorrecte
  661.     if (lignes < 4 || colonnes < 4 || lignes > MAXLIGNES || colonnes > MAXCOLONNES ||
  662.         tailleregion < 0 || tailleregion > lignes || tailleregion > colonnes)
  663.         AfficheErreur("EcrireGrille2D: Valeur incorrecte de lignes et/ou colonnes et/ou taillerégion dans le fichier", STOPEXIT);
  664.    
  665.     if (tailleregion > 1 && (((lignes % tailleregion) != 0) || ((colonnes % tailleregion) != 0)))
  666.         AfficheErreur("EcrireGrille2D: lignes et/ou colonnes doivent être multiples de la taille de la région", STOPEXIT);
  667.    
  668.     if(fprintf(fgrille, "<%c>\n", carvide) != 4)
  669.         AfficheErreur("EcrireGrille2D: Impossible d'écrire <carvide> dans le fichier", STOPEXIT);
  670.    
  671.     // ATTENTION : Ci-dessous, il faudrait limiter la taille de chaine de caractères
  672.     // à MAXSYMBOLE pour éviter problèmes de type "débordement de buffer"
  673.     // --> Est-ce possible avec fprintf ?
  674.     if(fprintf(fgrille, "%s\n", symboles) <= 0)
  675.         AfficheErreur("EcrireGrille2D: Impossible d'écrire symboles dans le fichier", STOPEXIT);
  676.    
  677.     for (l=0; l<lignes; l++)
  678.     {
  679.         for (c=0; c<colonnes; c++)
  680.         {
  681.             // Comme pour la lecture du fichier où il a fallut faire des conversions
  682.             // pour les caractères vides, il faut procéder à l'envers pour l'écriture
  683.             // des fichiers contenant les grilles de jeu :
  684.             element =  grille2D[l][c];
  685.             // Premier remplacement : Remplacer espace (' ') par SYMBOLESPACE ?
  686.             if (element == ' ')
  687.                 element = SYMBOLESPACE;
  688.             // Deuxième remplacement : Remplacer s0 par carvide ?
  689.             if (element == symboles[0])
  690.                 element = carvide;
  691.            
  692.             //
  693.             if (c != colonnes-1)
  694.             {
  695.                 // Nous ne sommes pas en dernière colonne --> Ajouter un espace
  696.                 if (fprintf(fgrille, "%c ", element) != 2)
  697.                     AfficheErreur("EcrireGrille2D: Impossible d'écrire la grille de jeu dans le fichier", STOPEXIT);
  698.             }
  699.             else
  700.             {
  701.                 // Nous sommes en dernière colonne --> Ne pas Ajouter d'espace, mais un retour chariot
  702.                 if (fprintf(fgrille, "%c\n", element) != 2)
  703.                     AfficheErreur("EcrireGrille2D: Impossible d'écrire la grille de jeu dans le fichier", STOPEXIT);
  704.             }
  705.         } // for c
  706.     } // for l
  707.    
  708.     fclose(fgrille);
  709.     return 0;
  710. }
  711.  
  712. // Affiche la grille relative au plan N°"plan".
  713. // Le plan "0" contient le cumul des possibilités par case.
  714. // Les plans 1 à 9 indiquent les possibilités de placement
  715. // du symbole N°1 à nbsymboles.
  716. //
  717. // TODO : VÉRIFIEZ LA VALIDITÉ DES PARAMÈTRES, NOTAMMENT "plan"
  718. //
  719. void AfficheGrille3DPlan(TGrille3D grille3D, int nlignes, int ncolonnes, int plan) {
  720.     int l, c;
  721.    
  722.     for (c = 0; c < ncolonnes; c++)
  723.         printf("---+");
  724.     puts("");
  725.     for (l = 0; l < nlignes; l++)
  726.     {
  727.         for (c = 0; c < ncolonnes; c++)
  728.             printf("%2d |", grille3D[l][c][plan]);
  729.         puts("");
  730.         for (c = 0; c < ncolonnes; c++)
  731.             printf("---+");
  732.         puts("");
  733.     }
  734.     puts("");
  735. }
  736.  
  737. // Retourne vrai (1) si le symbole N°"plan" peut être placé
  738. // dans la ligne "ligne" sur la grille de jeu
  739. // faux (0) sinon
  740. // (plan doit être compris entre 1 et MAXPLANS)
  741. bool symboleautoriseenligne(TGrille2D grille2D, int GTaille,
  742.                             int ligne, int plan,
  743.                             const char *symboles, const int nbsymboles)
  744. {
  745.     int c;
  746.    
  747.     for (c = 0; c < GTaille; c++)
  748.         if (grille2D[ligne][c] == plan2char(symboles, nbsymboles, plan))
  749.             return false;
  750.     return true;
  751. }
  752.  
  753. // Retourne vrai (1) si le symbole N°"plan" peut être placé
  754. // dans la colonne "colonne" sur la grille de jeu
  755. // faux (0) sinon
  756. // (plan doit être compris entre 1 et MAXPLANS)
  757. bool symboleautoriseencolonne(TGrille2D grille2D, int GTaille,
  758.                               int colonne, int plan,
  759.                               const char *symboles, const int nbsymboles)
  760. {
  761.     int l;
  762.    
  763.     for (l = 0; l < GTaille; l++)
  764.         if (grille2D[l][colonne] == plan2char(symboles, nbsymboles, plan))
  765.             return false;
  766.     return true;
  767. }
  768.  
  769. // Retourne vrai (1) si le symbole N°"plan" peut être placé
  770. // dans la région à laquelle appartient le couple "(ligne, colonne)"
  771. // faux (0) sinon
  772. // (plan doit être compris entre 1 et GTaille)
  773. //
  774. // ligne et colonne doivent être comprises entre 0 et GTaille-1
  775. // TODO : A verifier !
  776. //
  777. bool symboleautoriseenregion(TGrille2D grille2D,
  778.                              const unsigned int RTaille,
  779.                              const unsigned int ligne,
  780.                              const unsigned int colonne,
  781.                              const unsigned int plan,
  782.                              const char *symboles, const int nbsymboles)
  783. {
  784.     unsigned int rligne, rcolonne; // Position en haut à gauche de la région
  785.     unsigned int ltmp, ctmp; // Calcul temporaire du multiple de RTaille
  786.     unsigned int m, n; // ligne "modulo RTaille" et colonne "modulo RTaille"
  787.    
  788.     char carplan; // Caractère correspondant au plan N°plan
  789.    
  790.     carplan = plan2char(symboles, nbsymboles, plan);
  791.    
  792.     // si ligne est comprise entre 1 et GTaille
  793.     // et si colonne est comprise entre 1 et GTaille.
  794.     // Pour une grille 9*9 et des régions 3*3,
  795.     // lorsque ligne ou colonne (lc) vaut 1 à GTaille,
  796.     // rligne ou rcolonne (rlc) vaut :
  797.     // lc = 1 --> rlc = 1 | lc-1 = 0 | (lc-1)/RTaille = 0 | 1+[(lc-1)/RTaille]*RTaille = 1 = rlc
  798.     // lc = 2 --> rlc = 1 | lc-1 = 1 | (lc-1)/RTaille = 0 | 1+[(lc-1)/RTaille]*RTaille = 1 = rlc
  799.     // lc = 3 --> rlc = 1 | lc-1 = 2 | (lc-1)/RTaille = 0 | 1+[(lc-1)/RTaille]*RTaille = 1 = rlc
  800.     // lc = 4 --> rlc = 4 | lc-1 = 3 | (lc-1)/RTaille = 1 | 1+[(lc-1)/RTaille]*RTaille = 4 = rlc
  801.     // lc = 5 --> rlc = 4 | lc-1 = 4 | (lc-1)/RTaille = 1 | 1+[(lc-1)/RTaille]*RTaille = 4 = rlc
  802.     // lc = 6 --> rlc = 4 | lc-1 = 5 | (lc-1)/RTaille = 1 | 1+[(lc-1)/RTaille]*RTaille = 4 = rlc
  803.     // lc = 7 --> rlc = 7 | lc-1 = 6 | (lc-1)/RTaille = 2 | 1+[(lc-1)/RTaille]*RTaille = 7 = rlc
  804.     // lc = 8 --> rlc = 7 | lc-1 = 7 | (lc-1)/RTaille = 2 | 1+[(lc-1)/RTaille]*RTaille = 7 = rlc
  805.     // lc = 9 --> rlc = 7 | lc-1 = 8 | (lc-1)/RTaille = 2 | 1+[(lc-1)/RTaille]*RTaille = 7 = rlc
  806.     ltmp = ligne / RTaille;
  807.     ctmp = colonne / RTaille;
  808.     rligne = ltmp * RTaille;
  809.     rcolonne = ctmp * RTaille;
  810.     for (m=0; m<RTaille; m++)
  811.         for (n=0; n<RTaille; n++)
  812.             if (grille2D[rligne+m][rcolonne+n] == carplan)
  813.                 return false; // Inutile de continuer, le résultat est "faux"
  814.    
  815.     return true;
  816. }
  817.  
  818. // Mise à jour des plans.
  819. // Pour un sudoku "classique" (9x9) : plans 1 à 9 de la grille 3D pour énumérer
  820. // les possibilités de placer les chiffres 1 à 9 (1 chiffre par plan "p").
  821. // Pour les sudoku de taille > 9x9 les chiffres sont remplacés par des symboles
  822. // (caractères) à raison d'un symbole associé à chaque plan.
  823. //
  824. // --> Pour chaque case de la grille, il faut vérifier si
  825. // 1) la case est vide (sinon plus rien à placer -> plans 1 à 9 contiennent
  826. //    "carvide" pour cette case)
  827. // 2) le chiffre correspondant au plan p est autorisé dans la ligne courante
  828. // 3) le chiffre correspondant au plan p est autorisé dans la colonne courante
  829. // 4) le chiffre correspondant au plan p est autorisé dans la région courante
  830. //
  831. // Cette procédure met à jour les compteurs des plans 1 à 9.
  832. // Elle met à jour le cumul des possibilités (plan 0).
  833. //
  834. // Cette procédure est très très peu efficace !!!
  835. // Il y a moyen de l'améliorer et de l'accélérer fortement !!!
  836. //
  837. // ATTENTION au caractère vide : A l'extérieur "carvide" est le caractère vide
  838. // DANS LE FICHIER, mais dans la grille c'est symboles[0]
  839. // sauf si symboles[0] == SYMBOLESPACE auquel cas il est remplacé
  840. // par un espace --> Ceci est géré par une macro
  841. //
  842. void miseajourPlans(TGrille2D grille2D, TGrille3D grille3D,
  843.                     int GTaille, int RTaille, char carvide,
  844.                     const char *symboles, const int nbsymboles)
  845. {
  846.     int l, c, p; // Lignes, colonnes, plans
  847.    
  848.     for (l = 0; l < GTaille; l++)
  849.     {
  850.         for (c = 0; c < GTaille; c++)
  851.         {
  852.             grille3D[l][c][0] = 0; // RAZ cumul possibilités
  853.             // Ci-dessous c'est bien <= GTaille et non < GTaille ou <= MAXPLANS
  854.             // car seuls GTaille + 1 plans sont utilisés pour une grille de taille GTaille
  855.             for (p = 1; p <= GTaille; p++)
  856.             {
  857.                 grille3D[l][c][p] =
  858.                 ((grille2D[l][c] == carvide) &&
  859.                  (symboleautoriseenligne(grille2D, GTaille, l, p, symboles, nbsymboles)) &&
  860.                  (symboleautoriseencolonne(grille2D, GTaille, c, p, symboles, nbsymboles)) &&
  861.                  (symboleautoriseenregion(grille2D, RTaille, l, c, p, symboles, nbsymboles)));
  862.                 grille3D[l][c][0] += grille3D[l][c][p]; // cumul des possibilités par case
  863.             }
  864.         }
  865.     }
  866. }
  867.  
  868. // Affiche les possibilités de jeu restant pour chaque case
  869. // (sans garantir que cela conduise à une solution globale !!!).
  870. //
  871. // ATTENTION :
  872. // grille[0][0] correspond à la case en haut à droite de la grille de jeu,
  873. // mais grille3D[0][0][p] correspond à cette [même] case
  874. // dans le plan p de la grille3D
  875. void afficheGrillePossibilites(TGrille3D grille3D,
  876.                                const int GTaille,
  877.                                const int RTaille,
  878.                                const char *symboles, const int nbsymboles)
  879. {
  880.     int l, c; // ligne colonne
  881.     int m, n; // ligne "modulo RTaille" et colonne "modulo RTaille"
  882.    
  883.     for (c = 0; c < GTaille; c++) {
  884.         for (m = 0; m < RTaille-1; m++)
  885.             printf("--");
  886.         printf("-+");
  887.     }
  888.     puts("");
  889.     for (l = 0; l < GTaille; l++)
  890.     {
  891.         for (m = 0; m < RTaille; m++)
  892.         {
  893.             for (c = 0; c < GTaille; c++) {
  894.                 // Il faut convertir chaque numéro de plan en symbole
  895.                 printf("%c", (grille3D[l][c][1+m*RTaille]==0?' ':plan2char(symboles, nbsymboles, 1+m*RTaille)));
  896.                 for (n = 1; n < RTaille; n++) {
  897.                     // Il faut convertir chaque numéro de plan en symbole
  898.                     printf(" %c", (grille3D[l][c][1+n+m*RTaille]==0?' ':plan2char(symboles, nbsymboles, 1+n+m*RTaille)));
  899.                 }
  900.                 printf("|");
  901.             }
  902.             puts("");
  903.         }
  904.         for (c = 0; c < GTaille; c++) {
  905.             for (m = 0; m < RTaille-1; m++)
  906.                 printf("--");
  907.             printf("-+");
  908.         }
  909.         puts("");
  910.     }
  911.     puts("");
  912. }
  913.  
  914. // Joue un coup sur la grille et le mémorise dans la pile
  915. //
  916. // Le symbole joué est représenté par son N°plan (attention [1..GTaille]).
  917. // ligne et colonne doivent être comprises entre 0 et GTaille-1)
  918. //
  919. // ATTENTION : AUCUN CONTROLE EFFECTUE
  920. //
  921. // Appelle systématiquement miseajourPlans() même si ce n'est pas efficace
  922. //
  923. void jouerUnCoup(TGrille2D grille2D, TGrille3D grille3D,
  924.                  const int GTaille, const int RTaille,
  925.                  const char *symboles, const int nbsymboles,
  926.                  const int ligne, const int colonne,
  927.                  const int plan,
  928.                  TPileCoupsJoues *pile)
  929. {
  930.     // Ci-dessous nous ajoutons 1 à ligne et colonne pour que l'utilisateurs
  931.     // "voit" les lignes et les colonnes numérotées à partir de 1
  932.     printf("jouerUnCoup: place %d en (%d, %d)\n", plan, ligne+1, colonne+1);
  933.     yellow();
  934.     // Placer le symbole sur la grille de jeu
  935.     grille2D[ligne][colonne] = plan2char(symboles, nbsymboles, plan);
  936.     empileCoupJoue(pile, ligne, colonne, plan); // "Mémorise le coup joué"
  937.     miseajourPlans(grille2D, grille3D, GTaille, RTaille, CARGRILLEVIDE,
  938.                    symboles, nbsymboles);
  939.     reset();
  940. }
  941.  
  942. // Annule le dernier coup sur la grille et le supprime de la pile
  943. //
  944. // ATTENTION : CETTE PROCEDURE REQUIERT UN CALCUL COMPLET DES COMPTEURS
  945. // DES POSSIBILITES DE JEU
  946. // Ceci n'est pas effectué dans/par la procédure "annuleruncoup" pour permettre
  947. // d'accélerer les annulations "en cascade".
  948. // Il n'est pas possible de procéder simplement pour mettre à jour les
  949. // compteurs de manière locale car l'annulation d'un coup implique la
  950. // possibilité de rejouer ce symbole dans la région contenant la position
  951. // courante (ligne, colonne), et il faut que toutes les contraintes/compteurs
  952. // soient remises à jour pour réautoriser UNIQUEMENT EN CERTAINES POSITIONS
  953. // de la région concernée à l'issue de l'annulation, CQFD.
  954. //
  955. // ATTENTION : AUCUN CONTROLE EFFECTUE
  956. //
  957. // Appelle systématiquement miseajourPlans() même si ce n'est pas efficace
  958. //
  959. void annulerUnCoup(TGrille2D grille2D, TGrille3D grille3D, const int GTaille, const int RTaille, const char *symboles, const int nbsymboles, TPileCoupsJoues *pile) {
  960.     int ligne, colonne, plan;
  961.    
  962.     depileCoupJoue(pile, &ligne, &colonne, &plan); // Dépile dernier coup joué
  963.     // Ci-dessous nous ajoutons 1 à ligne et colonne pour que l'utilisateurs
  964.     // "voit" les lignes et les colonnes numérotées à partir de 1
  965.     printf("annulerUnCoup: annule le placement de %d en (%d, %d)\n",
  966.            plan, ligne+1, colonne+1);
  967.     grille2D[ligne][colonne] = CARGRILLEVIDE; // Enlève le symbole de la grille de jeu
  968.     miseajourPlans(grille2D, grille3D, GTaille, RTaille, CARGRILLEVIDE,
  969.                    symboles, nbsymboles);
  970. }
  971.  
  972. // Saisit un coup à jouer
  973. //
  974. // TODO : Vérifier que les lignes colonnes sont correctement saisies en récupérant le code de retour de scanf...
  975. //
  976. void saisirUnCoup(const int GTaille, const char *symboles, const int nbsymboles, int *ligne, int *colonne, int *plan) {
  977.     char symbole[2]; // Symbole saisi sous forme d'une chaîne de 2 caractères
  978.     do {
  979.         puts("\nVeuillez entrer le coup à jouer sous la forme : ligne (>=1) colonne (>=1) symbole");
  980.         scanf("%d %d %1s", ligne, colonne, symbole);
  981.         // TODO : Récupérez et traitez en conséquence le code de retour de scanf
  982.         // TODO : Indiquez à l'utilisateur la raison du refus éventuel du coup joué
  983.     } while (*ligne < 1 || *ligne > GTaille || *colonne < 1 || *colonne > GTaille ||
  984.              char2plan(symboles, nbsymboles, symbole[0]) <= 0);
  985.    
  986.     // En ce point la saisie est OK a priori --> Calculons le N° de symbole/plan
  987.     *plan = char2plan(symboles, nbsymboles, symbole[0]);
  988. }
  989.  
  990. // Vérifie si la grille est complête ou non.
  991. // Cette fonction est nécessaire car le plan 0 de la grille3D peut être rempli
  992. // de 0 dans deux cas : soit il n'y a plus aucune possibilité de jeu, mais la
  993. // grille (2D) n'est pas pleine en raison de l'impossibilité de complêter la
  994. // grille (grille infaisable) ou la grille (2D) est pleine et en ce cas la
  995. // résolution est terminée (grille faisable, et trouvée !).
  996. // Cette fonction détecte le cas où la grille est terminée & faisable.
  997. //
  998. bool grille2DComplete(TGrille2D grille2D, const int GTaille, const char *symboles) {
  999.     int l, c, cumul = 0;
  1000.    
  1001.     for (l = 0; l < GTaille; l++)
  1002.         for (c = 0; c < GTaille; c++)
  1003.             if (grille2D[l][c] != CARGRILLEVIDE)
  1004.                 cumul++;
  1005.     return cumul == GTaille * GTaille;
  1006. }
  1007.  
  1008.  
  1009.  
  1010.  
  1011. //////////////////////////////////////////////////////////////////////////////
  1012. //////////////////////////// PROGRAMME PRINCIPAL /////////////////////////////
  1013. //////////////////////////////////////////////////////////////////////////////
  1014. int main(void) {
  1015.     TGrille2D grille2D;   // Grille de jeu (2D)
  1016.     TGrille3D grille3D;   // Grille 3D
  1017.     TPileCoupsJoues pile; // Pile des coups joués
  1018.     int lignes, colonnes; // Nombre lignes et de colonnes dans la grille de jeu
  1019.     int nbsymboles;       // Nombre symboles non vides (i.e. plans dans la grille de jeu)
  1020.     int tailleregion;     // Taille des régions dans la grille de jeu
  1021.     char carvide;         // Caractère idenfiant case vide dans grille stocké dans fichier
  1022.     char symboles[MAXSYMBOLES+1]; // Symboles autorisés dans la grille de jeu
  1023.     // (+1 : pour stocker \0 car lu comme une chaine de caractères)
  1024.     int ligne, colonne; // Ligne et colonne pour le coup saisi
  1025.     int plan;                // Variable de boucle pour énumérer les plans 1 à MAXPLANS
  1026.     int GTaille = 0; // Taille de la grille (4, 9, 16, 25...)
  1027.     int RTaille = 0; // Taille d'une région (2, 3,  4,  5...)
  1028.     int menu;
  1029.    
  1030.     char nomgrille[256]; // Chemin complet de la grille (attention : aucune vérification sur la taille du chemin)
  1031.     puts("Bonjour, bienvenue dans votre jeux de sudoku préféré.\n\n");
  1032.     strcpy(nomgrille, CheminGrilles()); // Copie du chemin d'accès au grilles (répertoire/dossier)
  1033.     strcat(nomgrille, ChoixGrille());   // Choix du nom de la grille via le menu et concaténation
  1034.    
  1035.     printf("\nVous avez choisi la grille : \"%s\"\n", nomgrille);
  1036.    
  1037.     GTaille = lireTailleGrille2D(nomgrille);
  1038.     if (GTaille == 0)
  1039.         AfficheErreur("hexadoku: fichier grille introuvable ou taille de grille incorrecte (en argument sur la ligne de commande)", STOPEXIT);
  1040.    
  1041.     RTaille = RacineEntiere(GTaille);
  1042.     printf("# Sudoku de taille %ux%u - %d régions de taille %dx%d\n", GTaille, GTaille, GTaille, RTaille, RTaille);
  1043.    
  1044.     // TODO: Vérifier si la taille de la grille ne dépasse pas 25
  1045.    
  1046.     InitGrille2D(grille2D, '.');
  1047.     InitGrille3D(grille3D);
  1048.     initPileCoupsJoues(&pile);
  1049.    
  1050.     puts("\nHexadoku :");
  1051.     puts("------------");
  1052.    
  1053.     LireGrille2D(nomgrille, grille2D, &lignes, &colonnes, &tailleregion, &carvide, symboles);
  1054.     nbsymboles = strlen(symboles) - 1; // -1 pour décompter symbole vide/N°0
  1055.     printf("Car vide : <%c>\n", carvide);
  1056.     printf("Symboles : <%s>\n", symboles);
  1057.     printf("Régions  : %d x %d\n", tailleregion, tailleregion);
  1058.     printf("NSymboles: %d\n\n", nbsymboles);
  1059.     AfficherGrille2D(grille2D, lignes, colonnes, tailleregion);
  1060.     EcrireGrille2D("sudoku_bak.dat", grille2D, lignes, colonnes, tailleregion, carvide, symboles);
  1061.    
  1062.     miseajourPlans(grille2D, grille3D, GTaille, RTaille, CARGRILLEVIDE, symboles, nbsymboles);
  1063.    
  1064.     /*for (plan=1; plan<=nbsymboles; plan++) {
  1065.      printf("Possibilités de placement du symbole %d :\n\n", plan);
  1066.      AfficheGrille3DPlan(grille3D, lignes, colonnes, plan);
  1067.      }*/
  1068.    
  1069.     //afficheGrillePossibilites(grille3D, GTaille, RTaille, symboles, nbsymboles);
  1070.    
  1071.     /*do {
  1072.         saisirUnCoup(GTaille, symboles, nbsymboles, &ligne, &colonne, &plan);
  1073.        
  1074.         // Vérifier si le coup est valide et le jouer si oui, l'invalider sinon
  1075.         ligne--;
  1076.         colonne--;
  1077.        
  1078.         // Le test est le même que dans miseajourPlans()
  1079.         if ((grille2D[ligne][colonne] == CARGRILLEVIDE) &&
  1080.             (symboleautoriseenligne(grille2D, GTaille, ligne, plan, symboles, nbsymboles)) &&
  1081.             (symboleautoriseencolonne(grille2D, GTaille, colonne, plan, symboles, nbsymboles)) &&
  1082.             (symboleautoriseenregion(grille2D, RTaille, ligne, colonne, plan, symboles, nbsymboles))) {
  1083.             puts("Coup valide");
  1084.             // grille2D[ligne][colonne] = plan2char(symboles, nbsymboles, plan);
  1085.            
  1086.             jouerUnCoup(grille2D, grille3D, GTaille, RTaille,
  1087.                         symboles, nbsymboles,
  1088.                         ligne, colonne, plan,
  1089.                         &pile);
  1090.         } else {
  1091.             puts("Coup invalide, veuillez recommencer");
  1092.         }
  1093.         AfficherGrille2D(grille2D, lignes, colonnes, tailleregion);
  1094.         afficheGrillePossibilites(grille3D, GTaille, RTaille, symboles, nbsymboles);
  1095.     } while (!grille2DComplete(grille2D, GTaille, symboles));
  1096.    
  1097.     puts("\nGrille complète, bien joué !");
  1098.     LireGrille2D(nomgrille, grille2D, &lignes, &colonnes, &tailleregion, &carvide, symboles);
  1099.     puts("");
  1100.     AfficherGrille2D(grille2D, lignes, colonnes, tailleregion);
  1101.    
  1102.     puts("\nAnnulation des coups joués, en sens inverse :");
  1103.     while (!pileVide(pile)) {
  1104.         annulerUnCoup(grille2D, grille3D, GTaille, RTaille, symboles, nbsymboles, &pile);
  1105.     }*/
  1106.    
  1107.     do {
  1108.         puts("\n[SUDOKU MENU]\n");
  1109.         puts("[1. Jouer un coup]");
  1110.         puts("[2. Obtenir de l'aide]");
  1111.         puts("[3. Annuler son dernier coup]");
  1112.         puts("[4. Quitter le jeux]");
  1113.         scanf("%d",&menu);
  1114.         switch (menu) {
  1115.             case 1:
  1116.                    
  1117.                     saisirUnCoup(GTaille, symboles, nbsymboles, &ligne, &colonne, &plan);
  1118.                    
  1119.                     // Vérifier si le coup est valide et le jouer si oui, l'invalider sinon
  1120.                     ligne--;
  1121.                     colonne--;
  1122.                    
  1123.                     // Le test est le même que dans miseajourPlans()
  1124.                     if ((grille2D[ligne][colonne] == CARGRILLEVIDE) &&
  1125.                         (symboleautoriseenligne(grille2D, GTaille, ligne, plan, symboles, nbsymboles)) &&
  1126.                         (symboleautoriseencolonne(grille2D, GTaille, colonne, plan, symboles, nbsymboles)) &&
  1127.                         (symboleautoriseenregion(grille2D, RTaille, ligne, colonne, plan, symboles, nbsymboles))) {
  1128.                         puts("Coup valide");
  1129.                         // grille2D[ligne][colonne] = plan2char(symboles, nbsymboles, plan);
  1130.                        
  1131.                         jouerUnCoup(grille2D, grille3D, GTaille, RTaille,
  1132.                                     symboles, nbsymboles,
  1133.                                     ligne, colonne, plan,
  1134.                                     &pile);
  1135.                     } else {
  1136.                         puts("Coup invalide, veuillez recommencer");
  1137.                     }
  1138.                     AfficherGrille2D(grille2D, lignes, colonnes, tailleregion);
  1139.                
  1140.                 break;
  1141.             case 2:
  1142.                 afficheGrillePossibilites(grille3D, GTaille, RTaille, symboles, nbsymboles);
  1143.                 break;
  1144.             case 3:
  1145.                 annulerUnCoup(grille2D, grille3D, GTaille, RTaille, symboles, nbsymboles, &pile);
  1146.                 break;
  1147.             case 4:
  1148.                 return -1;
  1149.             default:
  1150.                 puts("[Entrer une valeur entre 1 et 4 !]");
  1151.                 break;
  1152.         }
  1153.     } while (menu !=4);
  1154.     return 0;
  1155. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
Top