Génération d'un labyrinthe amovible en C
Fermé[Dal] Messages postés 6198 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 13 décembre 2024 - 10 janv. 2023 à 12:42
- Génération d'un labyrinthe amovible en C
- Generation ryzen - Guide
- Generation mot de passe - Télécharger - Sécurité
- Réinitialiser chromecast 1ere génération - Guide
- Comment générer un qr code - Guide
- Kindle 11eme generation - Accueil - Guide tablettes
15 réponses
8 janv. 2023 à 01:57
Ok c'est bon j'ai enfin réussi
void afficher_une_tuile_coord_ecran(struct point debut_tuile, int dessin[3][3], char contenance) { int temp = debut_tuile.y; for(int li = 0; li < 3; li++){ for(int co = 0; co < 3; co++){ gotoligcol(debut_tuile.x,debut_tuile.y); if (li == 1 && co == 1){ Color(0,11); printf("%c", contenance); } else if(dessin[li][co] == 1){ Color(12,12); printf("%d", dessin[li][co]); } else if(dessin[li][co] != 1) { Color(11,11); printf("%d", dessin[li][co]); } debut_tuile.y = debut_tuile.y + 1; } debut_tuile.x = debut_tuile.x + 1; debut_tuile.y = temp; } }
J'ai testé ma fonction avec ton exemple pour l'affichage de la tuile restante et cela à bien marcher.
1 janv. 2023 à 17:47
Bonjour,
Je ne vois pas ce qui vous bloque. Un exemple avec un tableau de structure et des enum pour une lecture/écriture du code plus simple.
enum OrientedTile { OT_TT = 1+2+4, // 1 peut aller à gauche OT_T1 = 2+4+8, // 2 peut aller en bas OT_T2 = 1+4+8, // 4 peut aller à droite OT_T3 = 1+2+8, // 8 peut aller en haut OT_LL = 4+8, OT_L1 = 1+8, OT_L2 = 1+2, OT_L3 = 2+4, OT_II = 2+8, OT_I1 = 1+4, }; enum Contains { Nothing, Token1, Token2, Token3, Token4, Gift, }; struct Cell { enum OrientedTile tile; enum Contains contains; }; int main() { struct Cell board[7][7]; board[0][0] = (struct Cell){OT_L3,Token1}; board[0][2] = (struct Cell){OT_TT,Gift}; board[0][4] = (struct Cell){OT_TT,Gift}; board[0][6] = (struct Cell){OT_L2,Token2}; board[2][0] = (struct Cell){OT_T1,Gift}; ... ... // remplir avec 6 parmi {x, Gift} avec x=OT_TT OT_T1 OT_T2 ou OT_T3 // remplir avec 6 parmi {x, Gift} avec x=OT_LL OT_L1 OT_L2 ou OT_L3 // remplir avec 10 parmi {x, Nothing} avec x=OT_LL OT_L1 OT_L2 ou OT_L3 // remplir avec 12 parmi {x, Nothing} avec x=OT_II ou OT_I1 };
J'ai donné des valeurs choisies aux tuiles, ce nombre devrait permettre de:
- les dessiner
- gérer le moment où les pions devront se déplacer parmi les tuiles.
2 janv. 2023 à 19:07
Salut Dalfab, Salut Ebumiii,
J'ai l'impression que l'on ne dispose pas de l'énoncé en entier, car le but et principe du jeu ne sont pas vraiment décrits.
Il semble clair que les tuiles en L ou en T peuvent être orientées n'importe comment avant que le "Labyrinthe" ne soit créé en disposant les tuiles selon les règles prévues.
Au sujet de la 50ème tuile, qui peut être insérée par un joueur à un bout et qui résulte en l'expulsion de la tuile opposée, il est probable que, selon le but et principe du jeu (que l'on ne connaît pas) le joueur ait la possibilité de décider de l'orientation de la pièce avant de l'insérer (un peu comme une pièce de Tetris).
Dans ce cas, un moyen plus commode de déterminer l'orientation pourrait être pratique. Le fait que des déplacements soient possibles vers le haut, le bas, la gauche ou la droite n'est pas utilisé dans l'état de l'énoncé communiqué (c'est peut être dans une partie de l'énoncé qu'on n'a pas), mais en tout état de cause, cela peut se déduire de la forme et de l'orientation.
Alors, je proposerais un type struct tuile :
- qui indique la forme de la tuile (fixe) : L ou T
- qui indique l'orientation (variable, sauf pour les 16 tuiles inamovibles) : Nord, Ouest, Sud, Est
- qui indique si elle est vide, ou si elle contient quelque chose (fixe)
On peut effectivement utiliser des types enum pour ces 3 attributs.
Avec cela, on peut créer un tableau qui recense exhaustivement les 50 tuiles, avec leurs attributs, en mettant, par exemple, les 16 tuiles dont la position et orientation est fixe en début. Les 34 tuiles qui suivent pourraient être mélangées après avoir été exhaustivement insérées (mélange de Fisher-Yates) et leur orientation initiale choisie au hasard.
Un deuxième tableau à 2 dimensions de 7 x 7 peut alors servir à stocker les tuiles dans le tableau de jeu.
Au lieu de stocker les tuiles dans le tableau de jeu, on peut d'ailleurs stocker les indices des éléments du tableau de 50 tuiles. Cela sera plus efficace de décaler des entiers (indices) stockés dans le tableau de jeu de 7 x 7 lorsqu'il s'agira d'insérer une tuile à "une extrémité", plutôt que des struct (quoique le C assure bien l'affectation de types struct).
Il y a une autre difficulté dans (la dernière partie de) l'énoncé (qui nous est montré), qui est l'affichage en mode console.
Selon l'exemple d'affichage de l'énoncé, une tuile nécessitant pour un affichage 4 lignes (3 lignes pour la dessiner et une ligne séparatrice) sur 4 colonnes (3 colonnes pour la dessiner et une colonne séparatrice), un affichage ligne par ligne permis par le C standard suppose de "composer" le dessin d'une des 7 lignes en 4 lignes de 28 caractères correspondant visuellement aux éléments composant chacune les 7 tuiles de cette ligne du tableau de jeu. C'est un peu coton à faire, mais une fonction à laquelle on passe le tableau de jeu, le tableau de pièces, le numéro de la ligne à afficher et la ligne de terminal la composant à afficher, devrait pouvoir faire cela.
On peut même écrire des tests unitaires si la fonction renvoie la chaîne à afficher pour chaque ligne de terminal.
:-)
3 janv. 2023 à 17:45
Salut Dal,
Merci pour ton aide. Voici ce que nous avons réussie pour l'instant.
#include <stdio.h> enum OrientationTuile { Nord, Ouest, Sud, Est, }; enum Forme { L, T, I, }; enum Contenance{ Tresor, Vide, Pion1, Pion2, Pion3, Pion4, }; struct Tuile { enum OrientationTuile tuile; enum Forme forme; enum Contenance contenance; }; int main() { struct Tuile tab[50]; tab[0] = (struct Tuile) {Ouest,L,Pion1}; tab[1] = (struct Tuile) {Nord,T,Tresor}; tab[2] = (struct Tuile) {Nord,T,Tresor}; tab[3] = (struct Tuile) {Sud,L,Pion2}; tab[4] = (struct Tuile) {Est,T,Tresor}; tab[5] = (struct Tuile) {Est,T,Tresor}; tab[6] = (struct Tuile) {Nord,T,Tresor}; tab[7] = (struct Tuile) {Ouest,T,Tresor}; tab[8] = (struct Tuile) {Est,T,Tresor}; tab[9] = (struct Tuile) {Sud,T,Tresor}; tab[10] = (struct Tuile) {Ouest,T,Tresor}; tab[11] = (struct Tuile) {Ouest,T,Tresor}; tab[12] = (struct Tuile) {Nord,L,Pion3}; tab[13] = (struct Tuile) {Sud,T,Tresor}; tab[14] = (struct Tuile) {Sud,T,Tresor}; tab[15] = (struct Tuile) {Est,L,Pion4}; for(int i = 16; i<50; i++){ tab[i] = (struct Tuile) } return 0; }
Comme tu peux l'apercevoir, nous bloquons sur le premier tableau de 50 tuiles où l'on dois placer dans les 16 premières les tuiles fixes et pour le reste les tuiles aléatoires. Peux-tu nous expliquer comment réaliser cela plus précisément (avec un code par exmple) car malgré tes explications concises, comme nous débutons dans la programmation, nous avons du mal à tout comprendre.
Voici le reste du sujet qui te permettra peut-être à mieux comprendre.
Merci beaucoup de votre aide.
3 janv. 2023 à 20:08
Salut Ebumiii,
De rien, c'est un bon début.
Voilà pour te donner une idée de comment poursuivre pour les 34 tuiles qui suivent :
#include <stdio.h> #include <stdlib.h> #include <time.h> enum OrientationTuile { NORD, OUEST, SUD, EST, MAX_ORIENTATION_TUILE }; enum Forme { FORME_L, FORME_T, FORME_I, }; enum Contenance{ TRESOR, VIDE, PION1, PION2, PION3, PION4, }; struct Tuile { enum OrientationTuile orientation; enum Forme forme; enum Contenance contenance; }; int main(void) { srand(time(NULL)); struct Tuile tab[50]; tab[0] = (struct Tuile) {OUEST, FORME_L, PION1}; tab[1] = (struct Tuile) {NORD, FORME_T, TRESOR}; tab[2] = (struct Tuile) {NORD, FORME_T, TRESOR}; tab[3] = (struct Tuile) {SUD, FORME_L, PION2}; tab[4] = (struct Tuile) {EST, FORME_T, TRESOR}; tab[5] = (struct Tuile) {EST, FORME_T, TRESOR}; tab[6] = (struct Tuile) {NORD, FORME_T, TRESOR}; tab[7] = (struct Tuile) {OUEST, FORME_T, TRESOR}; tab[8] = (struct Tuile) {EST, FORME_T, TRESOR}; tab[9] = (struct Tuile) {SUD, FORME_T, TRESOR}; tab[10] = (struct Tuile) {OUEST, FORME_T, TRESOR}; tab[11] = (struct Tuile) {OUEST, FORME_T, TRESOR}; tab[12] = (struct Tuile) {NORD, FORME_L, PION3}; tab[13] = (struct Tuile) {SUD, FORME_T, TRESOR}; tab[14] = (struct Tuile) {SUD, FORME_T, TRESOR}; tab[15] = (struct Tuile) {EST, FORME_L, PION4}; /* * Selon l'énoncé, il faut ensuite : * - 6 tuiles T avec trésor que l'on met en positions 16 à 21 * - 6 tuiles L avec trésor que l'on met en positions 22 à 27 * - 10 tuiles L sans trésor que l'on met en positions 28 à 37 * - 12 tuiles I sans trésor que l'on met en positions 38 à 49 */ /* 6 tuiles T avec trésor que l'on met en positions 16 à 21 */ for (int i = 16; i < 22; i++) { tab[i].forme = FORME_T; tab[i].contenance= TRESOR; tab[i].orientation = rand() % MAX_ORIENTATION_TUILE; } /* faire la suite :-) */ return 0; }
J'ai changé quelques petites choses.
Comme les enum sont des constantes entières, je préfère les représenter en CAPITALES et que les membres ne soient pas trop courts pour limiter les risques d'être repris accidentellement comme nom de variable.
Je préfère "orientation" pour le nom du membre du type struct tuile définissant l'orientation, plutôt que "tuile"... et j'ai ajouté un MAX_ORIENTATION_TUILE à l'enum pour obtenir commodément le nombre de membres de l'enum.
Il te reste ensuite à mélanger les tuiles en positions 16 à 49.
Les indices des tuiles 0 à 48 pourraient ensuite être insérés dans le tableau de jeu et la tuile en indice 49 est la 50ème qui n'est pas sur le tableau de jeu.
Modifié le 3 janv. 2023 à 21:59
J'ai aussi lu les règles supplémentaires que tu n'avais pas postées avant.
Je pense que tu vas devoir distinguer les trésors entre eux, vu qu'il y en a 24 et que le but du jeu est, pour un joueur, d'arriver sur la case du labyrinthe qui comprend les trésors qui lui sont attribués. Du coup un enum est moins utile pour la contenance, et tu pourrais décider que le membre contenance est un char.
Les instructions disent d'utiliser des caractères spéciaux et une couleur, par exemple. Le C standard ne permet pas d'afficher de la couleur. Si tu tiens à le faire, tu peux voir ce fil.
Comme il y a 24 trésors, pour s'y retrouver le plus simple pourrait être de choisir les lettres 'A' à 'X' non colorés. Comme les char sont des types entiers, tu peux incrémenter une variable pour les insérer tous.
Par exemple :
#include <stdio.h> #include <stdlib.h> #include <time.h> enum OrientationTuile { NORD, OUEST, SUD, EST, MAX_ORIENTATION_TUILE }; enum Forme { FORME_L, FORME_T, FORME_I, }; #define CASE_VIDE ' ' #define CASE_PION1 '1' #define CASE_PION2 '2' #define CASE_PION3 '3' #define CASE_PION4 '4' #define CASE_TRESOR1 'A' struct Tuile { enum OrientationTuile orientation; enum Forme forme; char contenance; }; int main(void) { srand(time(NULL)); struct Tuile tab[50]; char tresor = CASE_TRESOR1; tab[0] = (struct Tuile) {OUEST, FORME_L, CASE_PION1}; tab[1] = (struct Tuile) {NORD, FORME_T, tresor++}; tab[2] = (struct Tuile) {NORD, FORME_T, tresor++}; tab[3] = (struct Tuile) {SUD, FORME_L, CASE_PION2}; tab[4] = (struct Tuile) {EST, FORME_T, tresor++}; tab[5] = (struct Tuile) {EST, FORME_T, tresor++}; tab[6] = (struct Tuile) {NORD, FORME_T, tresor++}; tab[7] = (struct Tuile) {OUEST, FORME_T, tresor++}; tab[8] = (struct Tuile) {EST, FORME_T, tresor++}; tab[9] = (struct Tuile) {SUD, FORME_T, tresor++}; tab[10] = (struct Tuile) {OUEST, FORME_T, tresor++}; tab[11] = (struct Tuile) {OUEST, FORME_T, tresor++}; tab[12] = (struct Tuile) {NORD, FORME_L, CASE_PION3}; tab[13] = (struct Tuile) {SUD, FORME_T, tresor++}; tab[14] = (struct Tuile) {SUD, FORME_T, tresor++}; tab[15] = (struct Tuile) {EST, FORME_L, CASE_PION4}; /* * Selon l'énoncé, il faut ensuite : * - 6 tuiles T avec trésor que l'on met en positions 16 à 21 * - 6 tuiles L avec trésor que l'on met en positions 22 à 27 * - 10 tuiles L sans trésor que l'on met en positions 28 à 37 * - 12 tuiles I sans trésor que l'on met en positions 38 à 49 */ /* 6 tuiles T avec trésor que l'on met en positions 16 à 21 */ for (int i = 16; i < 22; i++) { tab[i].forme = FORME_T; tab[i].contenance= tresor++; tab[i].orientation = rand() % MAX_ORIENTATION_TUILE; } /* faire la suite :-) */ return 0; }
Vous n’avez pas trouvé la réponse que vous recherchez ?
Posez votre questionModifié le 3 janv. 2023 à 23:09
Le problème ici est de voir comment des données mélangées peuvent être placées dans la table 7x7, tout en cohabitant avec des tuiles qui ont une position déterminée.
Il y a plein de manières, certaines compliquées d'autres plus simples.
J'étais plutôt parti sur un remplissage de la grille 7x7 avec :
- on la remplit entièrement avec l'indication pour chaque tuile comme étant ni T ni L ni I (c'était la valeur 0 de mon enum OrientedTile)
- on met les bonnes tuiles aux bonnes positions
- donc toutes les autres sont pour le moment dans l'état : ni T, ni L, ni I.
Puis dans un autre tableau linéaire rempli avec les 50-16 tuiles choisies en fonction des critères autorisées dans l'ordre des critères.
Puis cet autre tableau est mélangé.
Il reste à recopier en parcourant toutes les cases de la grille 7x7 et identifiant celles qui sont dans l'état ni L ni T ni I, pour les remplacer successivement par celle du tableau mélangé.
Il va alors rester la dernière du tableau mélangé qui sera la tuile de plus pour débuter le jeu.
Pour utiliser la méthode indiquée par Dal, on peut trouver une "bijection" (désolé pour le gros mot) entre les indices du tableau linéaire à 50 éléments et la grille 7x7. C'est faisable. On voit que les tuiles fixes sont celles qui ont à la fois i et j qui sont pairs (et donc pour k l'indice dans le tableau tab, k <= 15), les mélangeables ont soit i soit j qui est impair et un k >= 16. La tuile k=49 ne correspondant à aucun (i,j), c'est la tuile pour débuter le jeu.
Un autre moyen partant du code de Dal. On peut directement considérer que le tableau tab est aussi la grille 7x7 + 1 élément. C'est selon moi la solution la plus simple, mais me parait difficile à trouver quand on débute.
L'indice dans tab est directement 7*j+i. On utilise la "formule" 7*j+i pour accéder à une case de la grille 7x7
Après avoir fait le mélange des éléments 16 à 49, on a les éléments de 1 à 15 qui ne sont pas à leur place.
Il suffit de faire un échange avec l'élément qui a leur place attendue par exemple:
tmp = tab[1]; tab[1] = tab[0*7+2]; tab[0*7+2] = tmp; // seconde tuile à sa place tmp = tab[2]; tab[2] = tab[0*7+4]; tab[0*7+4] = tmp; // troisième tuile à sa place ...
Il y a certainement d'autres manières de faire.
4 janv. 2023 à 00:09
Bonjour, voici ce que nous avons réalisé en suivant vos instructions:
#include <stdio.h> #include <stdlib.h> #include <time.h> enum OrientationTuile { NORD, OUEST, SUD, EST, MAX_ORIENTATION_TUILE }; enum Forme { FORME_L, FORME_T, FORME_I, }; #define CASE_VIDE ' ' #define CASE_PION1 '1' #define CASE_PION2 '2' #define CASE_PION3 '3' #define CASE_PION4 '4' #define CASE_TRESOR1 'A' struct Tuile { enum OrientationTuile orientation; enum Forme forme; char contenance; }; void swap(struct Tuile tab[], int i, int j) { struct Tuile temp[1]; temp[0] = tab[i]; tab[i] = tab[j]; tab[j] = temp[0]; } void melanger(struct Tuile tab[], int n) { for (int i = 16; i <= n - 2; i++) { int j = i + rand() % (n - i); swap(tab, i, j); } } int main(void) { srand(time(NULL)); struct Tuile tab[50]; char tresor = CASE_TRESOR1; tab[0] = (struct Tuile) {OUEST, FORME_L, CASE_PION1}; tab[1] = (struct Tuile) {NORD, FORME_T, tresor++}; tab[2] = (struct Tuile) {NORD, FORME_T, tresor++}; tab[3] = (struct Tuile) {SUD, FORME_L, CASE_PION2}; tab[4] = (struct Tuile) {EST, FORME_T, tresor++}; tab[5] = (struct Tuile) {EST, FORME_T, tresor++}; tab[6] = (struct Tuile) {NORD, FORME_T, tresor++}; tab[7] = (struct Tuile) {OUEST, FORME_T, tresor++}; tab[8] = (struct Tuile) {EST, FORME_T, tresor++}; tab[9] = (struct Tuile) {SUD, FORME_T, tresor++}; tab[10] = (struct Tuile) {OUEST, FORME_T, tresor++}; tab[11] = (struct Tuile) {OUEST, FORME_T, tresor++}; tab[12] = (struct Tuile) {NORD, FORME_L, CASE_PION3}; tab[13] = (struct Tuile) {SUD, FORME_T, tresor++}; tab[14] = (struct Tuile) {SUD, FORME_T, tresor++}; tab[15] = (struct Tuile) {EST, FORME_L, CASE_PION4}; /* * Selon l'énoncé, il faut ensuite : * - 6 tuiles T avec trésor que l'on met en positions 16 à 21 * - 6 tuiles L avec trésor que l'on met en positions 22 à 27 * - 10 tuiles L sans trésor que l'on met en positions 28 à 37 * - 12 tuiles I sans trésor que l'on met en positions 38 à 49 */ /* 6 tuiles T avec trésor que l'on met en positions 16 à 21 */ for (int i = 16; i < 22; i++) { tab[i].forme = FORME_T; tab[i].contenance= tresor++; tab[i].orientation = rand() % MAX_ORIENTATION_TUILE; } for(int j = 22; j < 28; j++) { tab[j].forme = FORME_L; tab[j].contenance = tresor++; tab[j].orientation = rand() % MAX_ORIENTATION_TUILE; } for(int k = 28; k < 38; k++){ tab[k].forme = FORME_L; tab[k].contenance = CASE_VIDE; tab[k].orientation = rand() % MAX_ORIENTATION_TUILE; } for(int l = 38; l < 50; l++){ tab[l].forme = FORME_I; tab[l].contenance = CASE_VIDE; tab[l].orientation = rand() % MAX_ORIENTATION_TUILE; } int n = 50; melanger(tab, n); struct Tuile plateau[7][7]; /* Tuile fixe */ plateau[0][0] = tab[0]; plateau[0][2] = tab[1]; plateau[0][4] = tab[2]; plateau[0][6] = tab[3]; plateau[2][0] = tab[4]; plateau[2][2] = tab[5]; plateau[2][4] = tab[6]; plateau[2][6] = tab[7]; plateau[4][0] = tab[8]; plateau[4][2] = tab[9]; plateau[4][4] = tab[10]; plateau[4][6] = tab[11]; plateau[6][0] = tab[12]; plateau[6][2] = tab[13]; plateau[6][4] = tab[14]; plateau[6][6] = tab[15]; /* Tuile aleatoire */ plateau[0][1] = tab[16]; plateau[0][3] = tab[17]; plateau[0][5] = tab[18]; plateau[1][0] = tab[19]; plateau[1][1] = tab[20]; plateau[1][2] = tab[21]; plateau[1][3] = tab[22]; plateau[1][4] = tab[23]; plateau[1][5] = tab[24]; plateau[1][6] = tab[25]; plateau[2][1] = tab[26]; plateau[2][3] = tab[27]; plateau[2][5] = tab[28]; plateau[3][0] = tab[29]; plateau[3][1] = tab[30]; plateau[3][2] = tab[31]; plateau[3][3] = tab[32]; plateau[3][4] = tab[33]; plateau[3][5] = tab[34]; plateau[3][6] = tab[35]; plateau[4][1] = tab[36]; plateau[4][3] = tab[37]; plateau[4][5] = tab[38]; plateau[5][0] = tab[39]; plateau[5][1] = tab[40]; plateau[5][2] = tab[41]; plateau[5][3] = tab[42]; plateau[5][4] = tab[43]; plateau[5][5] = tab[44]; plateau[5][6] = tab[45]; plateau[6][1] = tab[46]; plateau[6][3] = tab[47]; plateau[6][5] = tab[48]; struct Tuile restant; restant = tab[49]; return 0; }
Grace à l'aide de Dal, nous avons crée un tableau de 50 structures avec les 16 premières valeurs représentant les tuiles fixes et les 34 restantes qu'on a mélangé grâce à une fonction permettant de reproduire le mélange de Fisher-Yates (on la fonction de ce site: https://www.techiedelight.com/fr/shuffle-given-array-elements-fisher-yates-shuffle/ ). Désormais, on possède le tableau avec les 50 structures dans les bonnes conditions, on a tout simplement affecter chaque case du tableau à deux dimension 7x7 par celle qui lui correspond (ce n'est pas jolie mais c'est ce qui nous a paru le plus simple à faire).
Ainsi, on suppose qu'on a le plateau grâce au tableau à deux dimensions mais à partir de ce moment on ne sait pas trop comment afficher plateau. Nous n'avons pas aussi trop compris l'utilisation à multiple reprise de trésor++, en effet est ce que nous devons pas plutôt crée plusieurs #define CASE_TRESORN (N allant de 1 à 24) représentant chacun une lettre de A à X où le fait de mettre trésor++ permet directement de faire cela.
Pour l'affichage du plateau, il n'est pas obligé de faire les lignes séparatrices (c'est facultatif), on pense aussi que cela peut compliqué les choses de rajouter les lignes séparatrices.
Pour les couleurs, on nous demande d'utiliser la fonction COLOR, on nous donne directement le programme permettant d'utiliser cette fonction.
#include <stdio.h> #include <stdlib.h> #include <windows.h> /////////// PROTOTYPES DES SOUS-PROGRAMMES void Color(int couleurDuTexte,int couleurDeFond); /////////////////////////////////////// // Nom du sous-programme : COLOR // Rôle : change la couleur du texte dans la console, ainsi que la couleur du fond pour la ligne // Compatibilité : windows XP /////////////////////////////////////// void Color(int couleurDuTexte,int couleurDeFond) // fonction d'affichage de couleurs { HANDLE H=GetStdHandle(STD_OUTPUT_HANDLE); SetConsoleTextAttribute(H,couleurDeFond*16+couleurDuTexte); } int main() { printf("Hello world!\n"); /* 0 : Noir 1 : Bleu foncé 2 : Vert foncé 3 : Turquoise 4 : Rouge foncé 5 : Violet 6 : Vert caca d'oie 7 : Gris clair 8 : Gris foncé 9 : Bleu fluo 10 : Vert fluo 11 : Turquoise 12 : Rouge fluo 13 : Violet 2 14 : Jaune 15 : Blanc */ // essai numero 1 Color(12,3); printf("Le texte va avoir la couleur 12 et le Fond la couleur 3\n"); // essai numero 2 : on repasse au noir et blanc Color(15, 0); printf("Hello world!\n"); // essai 3 : un peu de turquoise Color(11, 0); printf("Hello world!\n"); // et la derniere couleur reste jusqu'à ce qu'on change de nouveau printf("Hello world!\n"); //... return 0; }
Il nous ait aussi donné une fonction de manipulation de curseur à l'écran. Mais cela nous parait pas important pour l'instant .
#include <windows.h> void gotoligcol( int lig, int col ) { // ressources COORD mycoord; mycoord.X = col; mycoord.Y = lig; SetConsoleCursorPosition( GetStdHandle( STD_OUTPUT_HANDLE ), mycoord ); } int main () { // exemple d'appel au niveau du main // .... gotoligcol(5,15); // place le curseur ligne 5 colonne 15 à l'écran printf("bonjour"); // et écrit bonjour à cet endroit return 0; }
On vous remercie pour le temps que vous prenez pour nous aider, on vous est réellement reconnaissant.
:)
Modifié le 4 janv. 2023 à 11:27
mélangé grâce à une fonction permettant de reproduire le mélange de Fisher-Yates
Je n'ai pas vérifié ton implémentation (dans l'algorithme que je connais, on part de la fin du tableau), mais j'appellerais la fonction plutôt melanger_a_partir_de_16().
Dans tes boucles for, les variables d'index i, j, k et l que tu utilises sont locales à ton bloc for. Tu peux donc utiliser le même nom de variable i.
on a tout simplement affecter chaque case du tableau à deux dimension 7x7 par celle qui lui correspond (ce n'est pas jolie mais c'est ce qui nous a paru le plus simple à faire).
En fait, si tu fais, comme je le proposais, un tableau d'entiers pour ton "plateau" (tableau de jeu) stockant les indices, un moyen simple de remplir les cases non fixes est de parcourir le "plateau" et de mettre les indices dans l'ordre si l'emplacement dans le plateau n'est pas encore occupé.
/* Initialisation à 0 du tableau de jeu */ int plateau[7][7] = { 0 }; /* Tuiles fixes sur le tableau de jeu */ plateau[0][0] = 0; plateau[0][2] = 1; plateau[0][4] = 2; plateau[0][6] = 3; plateau[2][0] = 4; plateau[2][2] = 5; plateau[2][4] = 6; plateau[2][6] = 7; plateau[4][0] = 8; plateau[4][2] = 9; plateau[4][4] = 10; plateau[4][6] = 11; plateau[6][0] = 12; plateau[6][2] = 13; plateau[6][4] = 14; plateau[6][6] = 15; /* Tuiles aleatoires : les emplacements vides sont ceux contenant * zéro, à l'exception de celui aux coordonnées 0,0 qui représente * l'index 0 du tableau de tuiles */ int itab = 16; for (int i = 0; i < 7; i++) for (int j = 0; j < 7; j++) { if (i == 0 && j == 0) continue; if (plateau[i][j] == 0) plateau[i][j] = itab++; } int restant = 49; /* On accède à la tuile présente à des coordonnées données * via l'index stocké. Par exemple, la tuile au coin supérieur * gauche : */ struct Tuile une_tuile = tab[plateau[0][0]]; /* La tuile restante : */ struct Tuile tuile_restante = tab[restant];
L'idée est d'éviter de dupliquer l'information en stockant un moyen de se référer à l'information, plutôt que l'information elle-même qui est déjà en mémoire. On pourrait faire une correspondance similaire avec un "plateau" constitué de pointeurs sur struct, initialisé à NULL.
/* Initialisation à 0 du tableau de jeu */ struct Tuile * plateau[7][7] = { NULL }; /* Tuiles fixes sur le tableau de jeu */ plateau[0][0] = &tab[0]; plateau[0][2] = &tab[1]; plateau[0][4] = &tab[2]; plateau[0][6] = &tab[3]; plateau[2][0] = &tab[4]; plateau[2][2] = &tab[5]; plateau[2][4] = &tab[6]; plateau[2][6] = &tab[7]; plateau[4][0] = &tab[8]; plateau[4][2] = &tab[9]; plateau[4][4] = &tab[10]; plateau[4][6] = &tab[11]; plateau[6][0] = &tab[12]; plateau[6][2] = &tab[13]; plateau[6][4] = &tab[14]; plateau[6][6] = &tab[15]; /* Tuiles aleatoires : les emplacements vides sont ceux contenant * le pointeur NULL */ int itab = 16; for (int i = 0; i < 7; i++) for (int j = 0; j < 7; j++) if (plateau[i][j] == NULL) plateau[i][j] = &tab[itab++]; struct Tuile * restant = &tab[49]; /* On accède à la tuile présente à des coordonnées données * via le pointeur stocké. Par exemple, la tuile au coin supérieur * gauche : */ struct Tuile une_tuile = *plateau[0][0]; /* La tuile restante : */ struct Tuile tuile_restante = *restant;
Comme je ne sais pas si tu as vu les pointeurs, je n'ai pas proposé cette solution d'emblée, mais c'est un moyen sympathique de disposer un moyen indirect d'accéder aux données des tuiles : en stockant leurs adresses.
Pour effectuer les décalages nécessaires lorsque tu devras insérer une tuile, tu décaleras juste les adresses (ou si tu décides de stocker les index, juste les entiers représentant ces index).
Si tu peux utiliser des fonctions non standard de gestion de l'écran comme SetConsoleCursorPosition() cela va considérablement simplifier l'affichage du tableau, car tu peux dessiner chaque pièce caractère par caractère sans te soucier d'avoir à composer des lignes.
Nous n'avons pas aussi trop compris l'utilisation à multiple reprise de trésor++, en effet est ce que nous devons pas plutôt crée plusieurs #define CASE_TRESORN (N allant de 1 à 24) représentant chacun une lettre de A à X où le fait de mettre trésor++ permet directement de faire cela.
Oui, cela permet d'éviter cela.
Comme je l'ai rappelé, char est un type entier. Tu peux donc faire des opérations arithmétiques dessus. Pour les caractères ASCII, la valeur numérique correspond au code ASCII, qui sont consécutifs dans l'ordre alphabétique :
char tresor = CASE_TRESOR1; tab[1] = (struct Tuile) {NORD, FORME_T, tresor++};
Ligne 1 ci-dessus, tresor est initialisé à 'A' qui est une valeur entière valant 65.
Dans la ligne 3 d'affectation, la notation avec incrémentation postfixe (les ++ sont après) signifie :
- j'évalue la valeur actuelle de tresor (65)
- j'affecte cette cette valeur au membre correspondant de Tuile
- seulement après j'incrémente la valeur actuelle de tresor (qui vaut désormais 66 une fois cette ligne exécutée, et qui est donc prête à être affectée dans une instruction suivante)
(note donc : si l'on écrit ++i, l'incrémentation est faite avant)
Modifié le 4 janv. 2023 à 15:06
mélangé grâce à une fonction permettant de reproduire le mélange de Fisher-Yates
Je n'ai pas vérifié ton implémentation (dans l'algorithme que je connais, on part de la fin du tableau), mais j'appellerais la fonction plutôt melanger_a_partir_de_16().
Personnellement, j'aurais implémenté l'algorithme classique de Fisher-Yates, fonctionnant avec un tableau de n éléments (indicés de 0 à n-1) :
Pour mélanger un tableau a de n éléments (indicés de 0 à n-1), l'algorithme est le suivant.
Pour i allant de n − 1 à 1 faire :
j ← entier aléatoire entre 0 et i
échanger a[j] et a[i]
On peut alors passer à la fonction l'adresse de l'élément en 16ème position comme étant le début du tableau à mélanger, et un nombre d'éléments de 34 et non 50.
On appellerait alors la fonction en faisant :
melanger(&tab[16], 34);
Les paramètres disent explicitement ce qui est fait, alors que dans ta version (même si elle peut marcher) ils pourraient être perçus comme trompeurs.
Note aussi, dans ta fonction swap(), la variable temp n'a pas à être un tableau.
4 janv. 2023 à 14:38
Bonjour Dal,
On a compris ce que tu nous as envoyé et effectivement l'utilisation des pointeurs nous parait plus simple pour la suite programme (on a eu que quelque cours sur les pointeurs). Cependant, on a toujours du mal à savoir comment afficher une tuile selon les informations d'une structure.
On pense, qu'il faut crée plusieurs tableaux d'entier soit à deux dimensions 3x3 ou un simple tableau de 9 cases où on sautera une ligne toute les 3 valeurs. En effet , on suppose qu'à partir de cela on fait plusieurs if avec pour condition les valeurs de la structure lu en paramètre (on réalise tout ca dans une fonction qu'on nommera afficher_tuile() pour ne pas le réécrire). Ainsi, on réalisera cette fonction 49 fois pour obtenir le plateau en entier.
Exemple:
int une_tuile[3][3]; if (tab[] = (struct Tuile) {OUEST, FORMe_L, CASE_PION1}){ une_tuile[0][0] = 254; une_tuile[0][1] = 254; une_tuile[0][2] = 254; une_tuile[1][0] = 254; une_tuile[1][1] = 254; une_tuile[1][2] = 254; une_tuile[2][0] = 254; une_tuile[2][1] = 254; une_tuile[2][2] = 254; } else if(tab[]= (struct Tuile) {Nord, FORME_L,CASE_PION1}) { ...etc
254 représentant un carré noir en ASCII et 255 le vide. Mais on ne sait pas comment placé les trésors.
Voilà, c'est ce que nous pensons faire pour générer le labyrinthe mais il y a des fortes chances que cela ne sois pas ça.
Sachant que nous faisons de la programmation que depuis 2 mois, nous avons du mal à avoir la théorie pour réaliser les programmes. On bloque énormément sur des choses qui puissent vous paraître simple mais qui ne sont pas évidentes pour nous. Donc merci pour l'aide que tu nous apportes.
Modifié le 4 janv. 2023 à 15:58
Je ne comprends pas le code que tu as posté, mais sur le principe, cela ne me paraît pas pertinent de s'amuser à faire des tests de chaque cas de représentation visuelle pour prédessiner la forme de la tuile.
Ce que je ferais, c'est créer 3 tableaux de 3x3 char, représentant chaque forme de base L, T et I dans leur orientation NORD.
Ensuite, la forme à représenter selon l'orientation effective de la tuile peut être calculée.
Je ne suis pas matheux, mais il me semble que tu peux traiter chaque tableau comme composé de 9 points d'un repère orthonormé dont l'origine serait le point au centre de la forme et appliquer une formule pour faire des rotations antihoraires de 90 degrés de chaque coordonnées.
Creuse de ce côté.
Comme l'enum :
enum OrientationTuile { NORD, OUEST, SUD, EST, MAX_ORIENTATION_TUILE };
qui sert à stocker l'orientation propose justement déjà les orientations successives possibles dans le sens antihoraire (NORD vaut 0, OUEST vaut 1,...), il te suffit de faire un nombre de rotations correspondant à la valeur entière de l'orientation pour calculer la position finale de la tuile (NORD vaut 0 donc aucune rotation, OUEST vaut 1 donc 1 seule rotation,...).
S'il y a un cadeau, il peut être placé après le calcul de(s) rotation(s), sur le point au centre de la forme car il ne "bouge" pas.
Peu importe le caractère que tu mets dans tes tableaux des formes de base (mets des 'x' si tu veux, ou tu peux même mettre des 0 et des 1 et faire des tableaux de 3x3 int si tu trouves cela plus pratique).
Pour dessiner les formes, en revanche, il faudra choisir un affichage pour représenter le mur qui fonctionne bien en occupant l'espace horizontal et vertical où qu'il soit placé.
Vu que tu as droit à utiliser des fonctions non standard te permettant de colorer l'écran, tu pourrais choisir juste un espace ' ' avec un fond blanc ou gris. Cela te permettrait d'avoir l'espace occupé par un caractère à l'écran rempli au maximum et de faire une jonction propre horizontalement et verticalement.
(non testé de mon côté)
Modifié le 4 janv. 2023 à 16:28
A la réflexion, en poussant l'idée, comme le tableau représentant la forme de base ne sert, en réalité, qu'à déterminer les coordonnées par rapport au centre de la forme, tu pourrais juste stocker les coordonnées par rapport au centre.
Ainsi une forme L nécessiterait les 5 points suivants dans son orientation NORD par défaut :
(-1, -1), (-1, 0), (-1, 1), (0, 1), (1, 1)
je pense que cela nous arrange que les coordonnées négatives de l'axe vertical de notre repère soient inversées par rapport à la représentation habituelle, car cela correspond mieux au fonctionnement des coordonnées de l'écran.. sinon il faudra faire d'autres transformations.
Modifié le 4 janv. 2023 à 17:42
Ensuite, le dessin devient trivial, car il suffit de calculer les coordonnées à l'écran du centre d'une tuile donnée, pour dessiner les blocs qui correspondent aux points.
Si tu décides que les tuiles sont dessinées sur 3x3 sans lignes ou colonnes séparatrices et à partir d'un emplacement situé à la colonne 10 et ligne 2 de l'écran, par exemple, tu peux :
- faire une fonction qui retourne les coordonnées x, y à l'écran du centre de la tuile en lui passant le numéro de la colonne et de la ligne du tableau de jeu (de 1 à 7)
- et une autre fonction qui dessine la tuile en lui passant l'adresse de la tuile concernée et les coordonnées à l'écran de son centre.
Par exemple :-)
Modifié le 6 janv. 2023 à 18:59
Salut Dal, voici notre progression:
#include <stdio.h> #include <stdlib.h> #include <time.h> #include <windows.h> #define CASE_VIDE ' ' #define CASE_PION1 '1' #define CASE_PION2 '2' #define CASE_PION3 '3' #define CASE_PION4 '4' #define CASE_TRESOR1 'A' void Color(int couleurDuTexte,int couleurDeFond) // fonction d'affichage de couleurs { HANDLE H=GetStdHandle(STD_OUTPUT_HANDLE); SetConsoleTextAttribute(H,couleurDeFond*16+couleurDuTexte); } void gotoligcol( int lig, int col ) { COORD mycoord; mycoord.X = col; mycoord.Y = lig; SetConsoleCursorPosition( GetStdHandle( STD_OUTPUT_HANDLE ), mycoord ); } enum OrientationTuile { NORD, OUEST, SUD, EST, MAX_ORIENTATION_TUILE }; enum Forme { FORME_L, FORME_T, FORME_I, }; struct Tuile { enum OrientationTuile orientation; enum Forme forme; char contenance; }; void swap(struct Tuile tab[], int i, int j) { struct Tuile temp[1]; temp[0] = tab[i]; tab[i] = tab[j]; tab[j] = temp[0]; } void melanger_a_partir_de_16(struct Tuile tab[], int n) { for (int i = 16; i <= n - 2; i++) { int j = i + rand() % (n - i); swap(tab, i, j); } } void tourner_L_NORD(int tuile_en_L[3][3]){ tuile_en_L[0][0] = 1; tuile_en_L[0][1] = 0; tuile_en_L[0][2] = 0; tuile_en_L[1][0] = 1; tuile_en_L[1][2] = 0; tuile_en_L[2][0] = 1; tuile_en_L[2][1] = 1; tuile_en_L[2][2] = 1; } void tourner_L_OUEST(int tuile_en_L[3][3]){ tuile_en_L[0][0] = 1; tuile_en_L[0][1] = 1; tuile_en_L[0][2] = 1; tuile_en_L[1][0] = 1; tuile_en_L[1][2] = 0; tuile_en_L[2][0] = 1; tuile_en_L[2][1] = 0; tuile_en_L[2][2] = 0; } void tourner_L_SUD(int tuile_en_L[3][3]){ tuile_en_L[0][0] = 1; tuile_en_L[0][1] = 1; tuile_en_L[0][2] = 1; tuile_en_L[1][0] = 0; tuile_en_L[1][2] = 1; tuile_en_L[2][0] = 0; tuile_en_L[2][1] = 0; tuile_en_L[2][2] = 1; } void tourner_L_EST(int tuile_en_L[3][3]){ tuile_en_L[0][0] = 0; tuile_en_L[0][1] = 0; tuile_en_L[0][2] = 1; tuile_en_L[1][0] = 0; tuile_en_L[1][2] = 1; tuile_en_L[2][0] = 1; tuile_en_L[2][1] = 1; tuile_en_L[2][2] = 1; } void tourner_T_NORD(int tuile_en_T[3][3]){ tuile_en_T[0][0] = 1; tuile_en_T[0][1] = 1; tuile_en_T[0][2] = 1; tuile_en_T[1][0] = 0; tuile_en_T[1][2] = 0; tuile_en_T[2][0] = 1; tuile_en_T[2][1] = 0; tuile_en_T[2][2] = 1; } void tourner_T_OUEST(int tuile_en_T[3][3]){ tuile_en_T[0][0] = 1; tuile_en_T[0][1] = 0; tuile_en_T[0][2] = 1; tuile_en_T[1][0] = 0; tuile_en_T[1][2] = 1; tuile_en_T[2][0] = 1; tuile_en_T[2][1] = 0; tuile_en_T[2][2] = 1; } void tourner_T_SUD(int tuile_en_T[3][3]){ tuile_en_T[0][0] = 1; tuile_en_T[0][1] = 0; tuile_en_T[0][2] = 1; tuile_en_T[1][0] = 0; tuile_en_T[1][2] = 0; tuile_en_T[2][0] = 1; tuile_en_T[2][1] = 1; tuile_en_T[2][2] = 1; } void tourner_T_EST(int tuile_en_T[3][3]){ tuile_en_T[0][0] = 1; tuile_en_T[0][1] = 0; tuile_en_T[0][2] = 1; tuile_en_T[1][0] = 1; tuile_en_T[1][2] = 0; tuile_en_T[2][0] = 1; tuile_en_T[2][1] = 0; tuile_en_T[2][2] = 1; } void tourner_I_NORD(int tuile_en_I[3][3]){ tuile_en_I[0][0] = 1; tuile_en_I[0][1] = 0; tuile_en_I[0][2] = 1; tuile_en_I[1][0] = 1; tuile_en_I[1][2] = 1; tuile_en_I[2][0] = 1; tuile_en_I[2][1] = 0; tuile_en_I[2][2] = 1; } void tourner_I_OUEST(int tuile_en_I[3][3]){ tuile_en_I[0][0] = 1; tuile_en_I[0][1] = 1; tuile_en_I[0][2] = 1; tuile_en_I[1][0] = 0; tuile_en_I[1][2] = 0; tuile_en_I[2][0] = 1; tuile_en_I[2][1] = 1; tuile_en_I[2][2] = 1; } int main(void) { srand(time(NULL)); struct Tuile tab[50]; char tresor = CASE_TRESOR1; tab[0] = (struct Tuile) {OUEST, FORME_L, CASE_PION1}; tab[1] = (struct Tuile) {NORD, FORME_T, tresor++}; tab[2] = (struct Tuile) {NORD, FORME_T, tresor++}; tab[3] = (struct Tuile) {SUD, FORME_L, CASE_PION2}; tab[4] = (struct Tuile) {EST, FORME_T, tresor++}; tab[5] = (struct Tuile) {EST, FORME_T, tresor++}; tab[6] = (struct Tuile) {NORD, FORME_T, tresor++}; tab[7] = (struct Tuile) {OUEST, FORME_T, tresor++}; tab[8] = (struct Tuile) {EST, FORME_T, tresor++}; tab[9] = (struct Tuile) {SUD, FORME_T, tresor++}; tab[10] = (struct Tuile) {OUEST, FORME_T, tresor++}; tab[11] = (struct Tuile) {OUEST, FORME_T, tresor++}; tab[12] = (struct Tuile) {NORD, FORME_L, CASE_PION3}; tab[13] = (struct Tuile) {SUD, FORME_T, tresor++}; tab[14] = (struct Tuile) {SUD, FORME_T, tresor++}; tab[15] = (struct Tuile) {EST, FORME_L, CASE_PION4}; for (int i = 16; i < 22; i++) { tab[i].forme = FORME_T; tab[i].contenance= tresor++; tab[i].orientation = rand() % MAX_ORIENTATION_TUILE; } for(int j = 22; j < 28; j++) { tab[j].forme = FORME_L; tab[j].contenance = tresor++; tab[j].orientation = rand() % MAX_ORIENTATION_TUILE; } for(int k = 28; k < 38; k++){ tab[k].forme = FORME_L; tab[k].contenance = CASE_VIDE; tab[k].orientation = rand() % MAX_ORIENTATION_TUILE; } for(int l = 38; l < 50; l++){ tab[l].forme = FORME_I; tab[l].contenance = CASE_VIDE; tab[l].orientation = rand() % MAX_ORIENTATION_TUILE; } int n = 50; melanger_a_partir_de_16(tab, n); /* Initialisation à 0 du tableau de jeu */ int plateau[7][7]; for (int i = 0; i < 7; i++) { for (int j = 0; j < 7; j++) { plateau[i][j] = 0; } } /* Tuiles fixes sur le tableau de jeu */ plateau[0][0] = 0; plateau[0][2] = 1; plateau[0][4] = 2; plateau[0][6] = 3; plateau[2][0] = 4; plateau[2][2] = 5; plateau[2][4] = 6; plateau[2][6] = 7; plateau[4][0] = 8; plateau[4][2] = 9; plateau[4][4] = 10; plateau[4][6] = 11; plateau[6][0] = 12; plateau[6][2] = 13; plateau[6][4] = 14; plateau[6][6] = 15; /* Tuiles aleatoires : les emplacements vides sont ceux contenant * zéro, à l'exception de celui aux coordonnées 0,0 qui représente * l'index 0 du tableau de tuiles */ int itab = 16; for (int i = 0; i < 7; i++) for (int j = 0; j < 7; j++) { if (i == 0 && j == 0) continue; if (plateau[i][j] == 0) plateau[i][j] = itab++; } int restant = 49; int tuile_en_L[3][3] = { {1,0,0}, {1,0,0}, {1,1,1}, }; int tuile_en_T[3][3] = { {1,1,1}, {0,0,0}, {1,0,1}, }; int tuile_en_I[3][3] = { {1,0,1}, {1,0,1}, {1,0,1}, }; struct Tuile temp; temp = tab[1]; tab[1] = tab[plateau[0][1]]; tab[plateau[0][1]] = temp; temp = tab[1]; tab[1] = tab[plateau[0][1]]; tab[plateau[0][1]] = temp; //etc ... }
Mais nous constatons que c'est beaucoup trop long, et nous n'avons pas réussi à réaliser ton repère dans le tableau 3x3 permettant d'afficher les bonnes tuiles. Nous sommes vraiment perdu sur la suite sachant que devons rendre le code de l'affichage dimanche nous sommes vraiment inquiet. Pourrais tu, s'il te plaît, nous réaliser le code juste pour l'affichage du plateau. Nous savons qu'on est à rien de le réaliser mais malheureusement, on n'a pas la théorie pour réaliser cela.
Donc, nous te supplions de nous aider malgré toute l'aide que tu nous as déjà fournis.
Bonne soirée.
Modifié le 7 janv. 2023 à 02:39
Salut Ebumiii,
Le forum ne sert pas, en principe à faire faire le travail par d'autres.
Voilà cependant quelques indications.
En faisant des tests sur ton jeu de données, je pense qu'il y a des erreurs, à mon sens, dans ton initialisation de l'orientation de certaines des 16 tuiles fixes.
Si on suit l'ordre de l'enum orientation, les rotations sont antihoraires : Nord, Ouest, Sud, Est. Ce sont des rotations successives de la tuile orientée Nord de -90 degrés (un quart de tour vers la gauche, autour de l'origine qui est au centre du carré de 3x3).
Je ferais donc plutôt cela :
tab[0] = (struct Tuile) {EST, FORME_L, CASE_PION1}; tab[1] = (struct Tuile) {NORD, FORME_T, tresor++}; tab[2] = (struct Tuile) {NORD, FORME_T, tresor++}; tab[3] = (struct Tuile) {SUD, FORME_L, CASE_PION2}; tab[4] = (struct Tuile) {OUEST, FORME_T, tresor++}; tab[5] = (struct Tuile) {OUEST, FORME_T, tresor++}; tab[6] = (struct Tuile) {NORD, FORME_T, tresor++}; tab[7] = (struct Tuile) {EST, FORME_T, tresor++}; tab[8] = (struct Tuile) {OUEST, FORME_T, tresor++}; tab[9] = (struct Tuile) {SUD, FORME_T, tresor++}; tab[10] = (struct Tuile) {EST, FORME_T, tresor++}; tab[11] = (struct Tuile) {EST, FORME_T, tresor++}; tab[12] = (struct Tuile) {NORD, FORME_L, CASE_PION3}; tab[13] = (struct Tuile) {SUD, FORME_T, tresor++}; tab[14] = (struct Tuile) {SUD, FORME_T, tresor++}; tab[15] = (struct Tuile) {OUEST, FORME_L, CASE_PION4};
Ensuite, dans ton code, tu pars donc sur une représentation de tes formes de base de tuiles sous la forme d'un tableau de 3x3 entiers avec des 0 et des 1.
Je mettrais ces tableaux en variables globales et les nommerais de façon plus explicite pour que l'on comprenne que c'est une représentation du dessin des formes de base des tuiles, comme ceci :
int dessin_tuile_en_L[3][3] = { {1,0,0}, {1,0,0}, {1,1,1}, }; int dessin_tuile_en_T[3][3] = { {1,1,1}, {0,0,0}, {1,0,1}, }; int dessin_tuile_en_I[3][3] = { {1,0,1}, {1,0,1}, {1,0,1}, };
Une fois que tu as fait cela, tu peux écrire une fonction qui prend en paramètre une struct Tuile et renvoie le tableau représentant le dessin de base approprié pour cette tuile.
void get_dessin_de_base(int dessin[3][3], struct Tuile t) { int * p; switch (t.forme) { case FORME_L: p = (int *) dessin_tuile_en_L; break; case FORME_T: p = (int *) dessin_tuile_en_T; break; case FORME_I: p = (int *) dessin_tuile_en_I; break; } memcpy(dessin, p, sizeof(int) * 3 * 3); }
C'est sur ce dessin de base ainsi récupéré que tu vas appliquer les rotations.
OK, maintenant, pour afficher ton plateau de tuiles, je ferais les fonctions suivantes, utilisant un type struct point permettant de stocker des coordonnées :
void rotation_90(int dessin[3][3]) { /* TODO */ } struct point { int x; int y; }; void afficher_une_tuile_coord_ecran(struct point debut_tuile, int dessin[3][3], char contenance) { /* TODO */ } void afficher_une_tuile_coord_plateau(struct point debut_plateau, struct Tuile t, int li, int co) { /* TODO */ }
Pour les rotations, tu dois recenser les points qui composent chaque forme et leurs coordonnées dans un repère cartésien dont l'origine est au centre de la forme. Vois ceci pour comprendre comment calculer la transformation des coordonnées des points :
https://www.alloprof.qc.ca/fr/eleves/bv/mathematiques/les-rotations-dans-un-plan-cartesien-m1322
Dans mon cas, j'ai utilisé (x,y)↦(y,-x) pour la rotation antihoraire de 90 degrés, pour correspondre au système de coordonnées de l'écran (axe vertical inversé).
La fonction afficher_une_tuile_coord_plateau() permet d'afficher le plateau simplement en faisant ceci :
/* affichage du tableau */ clearscrn(); struct point debut_plateau = { .x = 10, .y = 2 }; for (int li = 0; li < 7; li++) for (int co = 0; co < 7; co++) { afficher_une_tuile_coord_plateau(debut_plateau, tab[plateau[li][co]], li, co); } /* affichage de la pièce restante */ gotoligcol(2, 45); printf("tuile restante :\n"); int dessin[3][3]; get_dessin_de_base(dessin, tab[restant]); afficher_une_tuile_coord_ecran( (struct point) { 45, 4 }, dessin, tab[restant].contenance);
Je me suis fait une petite fonction clearsrcn() pour effacer l'écran, une fonction faisant la même chose que gotoligcol() et une fonction gérant le mode inverse vidéo pour afficher les murs (en utilisant les séquences d'échappement des terminaux ANSI, car je suis sous Linux), et cela donne ceci à l'exécution :
Si, comme je le pense, la tuile restante peut être orientée au choix par l'utilisateur avant d'être insérée, son orientation pourrait être remise au Nord en attendant que l'utilisateur décide où l'insérer et selon quelle orientation.
7 janv. 2023 à 15:24
Salut dal,
je n'ai pas trop saisie comment on pouvais transformer le tableau en repère cartésien parce que sinon je ne vois pas comment appliqué la formule (x,y) > (y,-x) car du coup le centre du repère serait donc de coordonné (1,1).
Donc j'ai décidé d'affecter chaque valeur du tableau à celle qui lui correspond lorsqu'on effectue une rotation:
void rotation_90(int dessin[3][3]){
int temp1, temp2;
// aucune modification pour dessin[1][1] car c'est le centre du repere
dessin[0][2] = temp1; // rotation pour les corner des la tuile
dessin[0][2] = dessin[2][2];
dessin[2][2] = dessin[2][0];
dessin[2][0] = dessin[0][0];
dessin[0][0] = temp1;
dessin[0][1] = temp2; // rotation pour le reste de la tuile
dessin[0][1] = dessin[1][2];
dessin[1][2] = dessin[2][1];
dessin[2][1] = dessin[1][0];
dessin[1][0] = temp2;
}
En ce qui concerne la fonction afficher_une_tuile_coord_ecran, je n'ai pas trop compris ce qu'il fallait faire, pourrais tu m'en dire un peu plus s'il te plaît.
(oui il est incroyable ton tableau :] )
Modifié le 7 janv. 2023 à 16:36
Tu peux procéder comme tu fais car ton tableau ne fait que 3x3 points. Mais si tu avais une image à traiter cela devient impraticable. Ne serait-ce que les modestes tuiles que tu as postées dans tes images, elles font 75x75 soit 5625 pixels...
je n'ai pas trop saisie comment on pouvais transformer le tableau en repère cartésien parce que sinon je ne vois pas comment appliqué la formule (x,y) > (y,-x) car du coup le centre du repère serait donc de coordonné (1,1).
Il suffit de faire une translation des coordonnées en ajoutant -1 à chaque coordonnées. Le point du centre de coordonnées (1,1) se retrouve alors en (0,0). Tu peux alors faire ta rotation en appliquant (x,y)↦(y,-x). Ensuite tu refais une translation dans l'autre sens en ajoutant +1 à chaque coordonnées.
Bref, tu as trouvé un moyen praticable de faire tes rotations. Bravo !
Tu vois comment est appelée la fonction afficher_une_tuile_coord_ecran() dans cette partie de mon post où je m'en sert pour afficher la pièce restante.
/* affichage de la pièce restante */ gotoligcol(2, 45); printf("tuile restante :\n"); int dessin[3][3]; get_dessin_de_base(dessin, tab[restant]); afficher_une_tuile_coord_ecran( (struct point) { 45, 4 }, dessin, tab[restant].contenance);
Cette fonction est aussi appelée par afficher_une_tuile_coord_plateau(), une fois que la bonne tuile a subit le nombre de rotations nécessaires pour correspondre à son orientation et que l'on a pu calculer les coordonnées à l'écran de la tuile par rapport à la ligne et colonne du plateau.
La fonction afficher_une_tuile_coord_plateau() elle-même parcours le dessin et affiche chaque point individuellement placés avec gotoligcol() : on affiche un mur si un 1 est rencontré. Et au centre le char dans contenance. Chaque point est placé par rapport aux coordonnées du coin supérieur gauche à l'écran de la tuile qui sont passées en premier paramètre.
7 janv. 2023 à 16:08
Mais du coup les rotations de ma fonction se font dans le sens horaire du coup faudra t-il remettre l'affectation des 16 structures du tableau comme avant ?
Modifié le 7 janv. 2023 à 16:53
Tes transformations sont faites pixel par pixel manuellement en choisissant le prochain pixel à traiter dans le sens horaire, mais tu les déplaces bien dans le sens antihoraire.
J'ai pris un papier et un crayon et en suivant tes affectations à la main sur un tableau d'essai je suis arrivé à ce résultat :
0 1 2
┌─┬─┬─┐
0 │a│b│c│
├─┼─┼─┤
1 │d│e│f│ ─┐
├─┼─┼─┤ │
2 │g│h│i│ │ 0 1 2
└─┴─┴─┘ │ ┌─┬─┬─┐
│ 0 │c│f│i│
│ ├─┼─┼─┤
└► 1 │b│e│h│
├─┼─┼─┤
2 │a│d│g│
└─┴─┴─┘
C'est une rotation antihoraire.
Je n'ai pas compris ta question "faudra t-il remettre l'affectation des 16 structures du tableau comme avant ?".
7 janv. 2023 à 20:14
En fait, je voulais si on devait changer les caractéristique de l'orientation des 16 premières structures de tab car je pensait que ma fonction rotation faisait tourner dans un sens horaire. Mais tu m'as démontré finalement si on applique la fonction cela tournait bien dans un sens anti horaire.
7 janv. 2023 à 20:33
Concernant l'affichage, voici ce que j'ai fait je ne sais pas trop si cela correspond à ce que tu as expliquer.
void afficher_une_tuile_coord_ecran(struct point debut_tuile, int dessin[3][3], char contenance) { gotoligcol(debut_tuile.x,debut_tuile.y); for(int i = 0; i < 3; i++){ for(int j = 0; j < 3; j++){ if (i == 1 && i == 1) printf("%c", contenance); printf("%d", dessin[i][j]); } } }
Il y a vraiment une chose que je n'ai toujours pas comprise c'est comment on procède pour relier un les tableau dessin_tuile_en_T, dessin_tuile_en_L etc... à une structure selon ces caractérisque.
Cela concerne aussi les rotations. Je ne vois pas comment je peux les appliquer. Faut-il les faire dans le main auparavant ? Ou ici aussi il faut faire une fonction ?
Modifié le 7 janv. 2023 à 21:53
La fonction afficher_une_tuile_coord_plateau() elle-même parcours le dessin et affiche chaque point individuellement placés avec gotoligcol() : on affiche un mur si un 1 est rencontré. Et au centre le char dans contenance. Chaque point est placé par rapport aux coordonnées du coin supérieur gauche à l'écran de la tuile qui sont passées en premier paramètre.
Là tu utilises gotoligcol() une seule fois et printf() met tous tes points sur la même ligne à l'écran. Tu dois te servir de gotoligcol() dans les boucles imbriquées pour placer chaque point au bon endroit par rapport aux coordonnées à l'écran du coin supérieur gauche de départ.
Un conseil, utilise "ligne" et "colonne" (ou "li" et "co" pour faire plus court) comme noms de variables au lieu de i et j pour ne pas te tromper et parcourir correctement ton tableau.
Essaye de mettre au point cette fonction là en vérifiant que tu affiches correctement une tuile de test dont tu détermines la forme, l'orientation et la position à l'écran pour ton test.
Fais la suite quant tu auras réussi.
Pour ta 2ème série de questions, il me semble que j'ai tout dit ici :
Cette fonction est aussi appelée par afficher_une_tuile_coord_plateau(), une fois que la bonne tuile a subit le nombre de rotations nécessaires pour correspondre à son orientation et que l'on a pu calculer les coordonnées à l'écran de la tuile par rapport à la ligne et colonne du plateau.
Dans afficher_une_tuile_coord_plateau(), tu détermines (1) quel est le bon dessin à utiliser en fonction de la forme de la tuile passée, (2) le nombre de rotations à faire en fonction de l'orientation de la tuile (et tu les fais, stp, ces rotations que tu sais désormais faire, en appelant la fonction que tu as créée le bon nombre de fois), et (3) tu calcules les coordonnées à l'écran du coin supérieur gauche de la tuile en fonction de la ligne et colonne du plateau passée (ces coordonnées de de 0 à 6, et tu dois calculer où cela se trouve sur l'écran).
Quand tu as ces informations, la fonction afficher_une_tuile_coord_plateau() peut appeler afficher_une_tuile_coord_ecran().
7 janv. 2023 à 21:49
La tu penses que c'est bien ?
void afficher_une_tuile_coord_ecran(struct point debut_tuile, int dessin[3][3], char contenance) { for(int li = 0; li < 3; li++){ for(int co = 0; co < 3; co++){ gotoligcol(li,co); if (li == 1 && co == 1) printf("%c", contenance); printf("%d", dessin[li][co]); debut_tuile.y = co; } debut_tuile.x = li; } }
je ne suis pas sur pour les affectations de debut_tuile.x et debut_tuile.y
Modifié le 7 janv. 2023 à 23:49
La tu penses que c'est bien ?
Non.
As-tu essayé comme je te le disais "en vérifiant que tu affiches correctement une tuile de test dont tu détermines la forme, l'orientation et la position à l'écran pour ton test." ?
debut_tuile.x et debut_tuile.y sont passés à cette fonction pour que tu dessines à l'écran à partir de ces coordonnées d'écran (ces coordonnées sont déterminées par la fonction appelante, comme déjà indiqué et illustré par du code - je pense que c'est la 3ème fois que je le dis, je ne le répéterai plus, j'ai atteint mon quota).
Là, ta fonction va toujours placer la tuile à partir de 0,0 quelles que soit debut_tuile.x et debut_tuile.y
Cette fonction ne sert pas à affecter debut_tuile.x et debut_tuile mais à afficher le dessin de la tuile à un endroit donné.
(comme dans mon code d'exemple où j'affiche à un endroit donné la tuile supplémentaire)
8 janv. 2023 à 03:47
En ce qui concerne la fonction afficher_tuile_cord_plateau je ne comprend pas pourquoi les rotations elle ne s'effectue pas et pourquoi j'ai des caractères qui s'affiche en plus de la tuile.
void afficher_une_tuile_coord_plateau(struct point debut_plateau,
struct Tuile t, int li, int co) {
int dessin[3][3];
get_dessin_de_base(dessin, t);
switch (t.orientation) {
case EST :
rotation_90(dessin);
break;
case SUD :
rotation_90(dessin);
rotation_90(dessin);
break;
case OUEST:
rotation_90(dessin);
rotation_90(dessin);
rotation_90(dessin);
break;
}
debut_plateau.x = li * 3;
debut_plateau.y = co * 3;
afficher_une_tuile_coord_ecran(debut_plateau,dessin,t.contenance);
}
Une deuxième version pour les rotations qui ne marche pas non plus.
void afficher_une_tuile_coord_plateau(struct point debut_plateau, struct Tuile t, int li, int co) { int dessin[3][3]; get_dessin_de_base(dessin, t); if (t.orientation == EST) rotation_90(dessin); if (t.orientation == SUD){ for(int i = 0; i < 2; i++) rotation_90(dessin); } if (t.orientation == OUEST){ for(int i = 0; i < 3; i++) rotation_90(dessin); } debut_plateau.x = li * 3; debut_plateau.y = co * 3; afficher_une_tuile_coord_ecran(debut_plateau,dessin,t.contenance); }
8 janv. 2023 à 03:50
8 janv. 2023 à 05:34
Salut Dal,
tout d'abord désolé pour les questions répétitives qui ont pu t'agacer mais à force j'ai presque réaliser l'affichage du labyrinthe. J'ai passé toute la nuit à comprendre comment l'afficher désormais le plus compliqué fait j'ai un tout dernier problème, je ne comprend pourquoi j'ai des tuiles qui n'apparaisse pas sous la bonne forme. Exemple:
Je ne comprend pas pourquoi il y a des cases qui ne s'affichent pas ou s'affiche pas de la bonne couleur.
Voici notre code:
#include <stdio.h> #include <stdlib.h> #include <time.h> #include <windows.h> #define CASE_VIDE ' ' #define CASE_PION1 '1' #define CASE_PION2 '2' #define CASE_PION3 '3' #define CASE_PION4 '4' #define CASE_TRESOR1 'A' void Color(int couleurDuTexte,int couleurDeFond) // fonction d'affichage de couleurs { HANDLE H=GetStdHandle(STD_OUTPUT_HANDLE); SetConsoleTextAttribute(H,couleurDeFond*16+couleurDuTexte); } void gotoligcol( int lig, int col ) { COORD mycoord; mycoord.X = col; mycoord.Y = lig; SetConsoleCursorPosition( GetStdHandle( STD_OUTPUT_HANDLE ), mycoord ); } enum OrientationTuile { NORD, OUEST, SUD, EST, MAX_ORIENTATION_TUILE }; enum Forme { FORME_L, FORME_T, FORME_I, }; struct Tuile { enum OrientationTuile orientation; enum Forme forme; char contenance; }; void swap(struct Tuile tab[], int i, int j) { struct Tuile temp[1]; temp[0] = tab[i]; tab[i] = tab[j]; tab[j] = temp[0]; } void melanger_a_partir_de_16(struct Tuile tab[], int n) { for (int i = 16; i <= n - 2; i++) { int j = i + rand() % (n - i); swap(tab, i, j); } } void rien(int dessin[3][3]){ int temp1, temp2; dessin[0][0] = dessin[0][0]; dessin[0][1] = dessin[0][1]; dessin[0][2] = dessin[0][2]; dessin[1][0] = dessin[1][0]; dessin[1][2] = dessin[1][2]; dessin[2][0] = dessin[2][0]; dessin[2][1] = dessin[2][1]; dessin[2][2] = dessin[2][2]; } void rotation_90(int dessin[3][3]){ int temp1, temp2; // aucune modification pour dessin[1][1] car c'est le centre du repere dessin[0][2] = temp1; // rotation pour les corner des la tuile dessin[0][2] = dessin[2][2]; dessin[2][2] = dessin[2][0]; dessin[2][0] = dessin[0][0]; dessin[0][0] = temp1; dessin[0][1] = temp2; // rotation pour le reste de la tuile dessin[0][1] = dessin[1][2]; dessin[1][2] = dessin[2][1]; dessin[2][1] = dessin[1][0]; dessin[1][0] = temp2; } void rotation_180(int dessin[3][3]){ int temp1, temp2; // aucune modification pour dessin[1][1] car c'est le centre du repere dessin[0][2] = temp1; // rotation pour les corner des la tuile dessin[0][2] = dessin[2][0]; dessin[2][0] = temp1; dessin[0][0] = temp1; dessin[0][0] = dessin[2][2]; dessin[2][2] = temp1; dessin[0][1] = temp2; // rotation pour le reste de la tuile dessin[0][1] = dessin[2][1]; dessin[2][1] = temp2; dessin[1][0] = temp2; dessin[1][0] = dessin[1][2]; dessin[1][2] = temp2; } void rotation_270(int dessin[3][3]){ int temp1, temp2; // aucune modification pour dessin[1][1] car c'est le centre du repere dessin[0][2] = temp1; // rotation pour les corner des la tuile dessin[0][2] = dessin[0][0]; dessin[0][0] = dessin[2][0]; dessin[2][0] = dessin[2][2]; dessin[2][2] = temp1; dessin[0][1] = temp2; // rotation pour le reste de la tuile dessin[0][1] = dessin[1][0]; dessin[1][0] = dessin[2][1]; dessin[2][1] = dessin[1][2]; dessin[1][2] = temp2; } struct point { int x; int y; }; void afficher_une_tuile_coord_ecran(struct point debut_tuile, int dessin[3][3], char contenance) { int temp = debut_tuile.y; for(int li = 0; li < 3; li++){ for(int co = 0; co < 3; co++){ gotoligcol(debut_tuile.x,debut_tuile.y); if (li == 1 && co == 1){ Color(0,11); printf("%c", contenance); } if(dessin[li][co] == 1){ Color(12,12); printf("%d", dessin[li][co]); } if(dessin[li][co] == 0) { Color(11,11); printf("%d", dessin[li][co]); } debut_tuile.y = debut_tuile.y + 1; } debut_tuile.x = debut_tuile.x + 1; debut_tuile.y = temp; } } int dessin_tuile_en_L[3][3] = { {1,0,0}, {1,0,0}, {1,1,1}, }; int dessin_tuile_en_T[3][3] = { {1,1,1}, {0,0,0}, {1,0,1}, }; int dessin_tuile_en_I[3][3] = { {1,0,1}, {1,0,1}, {1,0,1}, }; void get_dessin_de_base(int dessin[3][3], struct Tuile t) { int * p; switch (t.forme) { case FORME_L: p = (int *) dessin_tuile_en_L; break; case FORME_T: p = (int *) dessin_tuile_en_T; break; case FORME_I: p = (int *) dessin_tuile_en_I; break; } memcpy(dessin, p, sizeof(int) * 3 * 3); } void afficher_une_tuile_coord_plateau(struct point debut_plateau, struct Tuile t, int li, int co) { int dessin[3][3]; get_dessin_de_base(dessin, t); if (t.orientation == 3) rotation_270(dessin); else if (t.orientation == 2) rotation_180(dessin); else if (t.orientation == 1) rotation_90(dessin); else if (t.orientation == 0) rien(dessin); debut_plateau.x = li * 4; debut_plateau.y = co * 4; afficher_une_tuile_coord_ecran(debut_plateau,dessin,t.contenance); } int main(void) { srand(time(NULL)); struct Tuile tab[50]; char tresor = CASE_TRESOR1; tab[0] = (struct Tuile) {EST, FORME_L, CASE_PION1}; tab[1] = (struct Tuile) {NORD, FORME_T, tresor++}; tab[2] = (struct Tuile) {NORD, FORME_T, tresor++}; tab[3] = (struct Tuile) {SUD, FORME_L, CASE_PION2}; tab[4] = (struct Tuile) {OUEST, FORME_T, tresor++}; tab[5] = (struct Tuile) {OUEST, FORME_T, tresor++}; tab[6] = (struct Tuile) {NORD, FORME_T, tresor++}; tab[7] = (struct Tuile) {EST, FORME_T, tresor++}; tab[8] = (struct Tuile) {OUEST, FORME_T, tresor++}; tab[9] = (struct Tuile) {SUD, FORME_T, tresor++}; tab[10] = (struct Tuile) {EST, FORME_T, tresor++}; tab[11] = (struct Tuile) {EST, FORME_T, tresor++}; tab[12] = (struct Tuile) {NORD, FORME_L, CASE_PION3}; tab[13] = (struct Tuile) {SUD, FORME_T, tresor++}; tab[14] = (struct Tuile) {SUD, FORME_T, tresor++}; tab[15] = (struct Tuile) {OUEST, FORME_L, CASE_PION4}; for (int i = 16; i < 22; i++) { tab[i].forme = FORME_T; tab[i].contenance= tresor++; tab[i].orientation = rand() % MAX_ORIENTATION_TUILE; } for(int i = 22; i < 28; i++) { tab[i].forme = FORME_L; tab[i].contenance = tresor++; tab[i].orientation = rand() % MAX_ORIENTATION_TUILE; } for(int i = 28; i < 38; i++){ tab[i].forme = FORME_L; tab[i].contenance = CASE_VIDE; tab[i].orientation = rand() % MAX_ORIENTATION_TUILE; } for(int i = 38; i < 50; i++){ tab[i].forme = FORME_I; tab[i].contenance = CASE_VIDE; tab[i].orientation = rand() % MAX_ORIENTATION_TUILE; } int n = 50; melanger_a_partir_de_16(tab, n); int plateau[7][7] = { 0 }; plateau[0][0] = 0; plateau[0][2] = 1; plateau[0][4] = 2; plateau[0][6] = 3; plateau[2][0] = 4; plateau[2][2] = 5; plateau[2][4] = 6; plateau[2][6] = 7; plateau[4][0] = 8; plateau[4][2] = 9; plateau[4][4] = 10; plateau[4][6] = 11; plateau[6][0] = 12; plateau[6][2] = 13; plateau[6][4] = 14; plateau[6][6] = 15; int itab = 16; for (int i = 0; i < 7; i++) for (int j = 0; j < 7; j++) { if (i == 0 && j == 0) continue; if (plateau[i][j] == 0) plateau[i][j] = itab++; } int restant = 49; int dessin[3][3]; struct point debut_plateau; debut_plateau.x = 0; debut_plateau.y = 0; for (int li = 0; li < 7; li++) for (int co = 0; co < 7; co++) { afficher_une_tuile_coord_plateau(debut_plateau, tab[plateau[li][co]], li, co); } gotoligcol(29, 0); Color(15,0); printf("tuile restante :\n"); get_dessin_de_base(dessin, tab[restant]); afficher_une_tuile_coord_ecran( (struct point) { 30, 3 }, dessin, tab[restant].contenance); return 0; }
Pourtant il me semble bien que les fonctions d'affichage parcours bien le tableau et applique bien les modifications selon la valeur du tableau.
Modifié le 8 janv. 2023 à 12:54
Il faut déboguer ton code. Pour éviter d'avoir à faire cela, il faut tester le code à mesure qu'on l'écris.
Une piste. Il est possible que cela soient tes fonctions rotation_180() et/ou rotation_270() qui soient en cause. Les as-tu testées ? Je n'ai pas le temps de m'y plonger, j'ai des obligations familiales aujourd'hui.
A quoi sert la fonction rien() ?
Il te suffit de lancer la fonction rotation_90() autant de fois que nécessaire pour faire les rotations additionnelles de 90°. Celle-là, on sait qu'elle fonctionne.
Et retire la fonction rien(), qui ne sert à rien (sauf à constituer du code où un bogue peut se glisser ou du code à maintenir).
Si ce n'est pas cela, teste individuellement chaque fonction avec un nouveau main(), en renommant l'autre, et en utilisant un jeu de test que tu détermines en entrée pour vérifier que chacune donne le résultat attendu en sortie.
Là tu fais cela après la bataille et tu joues au détective.
Une méthode de développement consiste à écrire les tests avant d'écrire le code (TDD). C'est très efficace pour éviter de se retrouver dans ta situation, pour se discipliner à écrire du code testable, et pour disposer de tests que tu peux exécuter automatiquement et garantissant l'absence de régression lors des futures évolutions du code ou refactorisations du code.
10 janv. 2023 à 11:40
Il y a une erreur dans ton code de rotation, même dans la fonction de rotation 90 degrés.
dessin[0][2] = temp1;
doit être remplacé par
temp1 = dessin[0][2];
Pareil pour temp2.
Sinon, tu écrases ces cases du tableau avec une valeur de temp1 ou temp2 qui ne sont pas initialisées.
En compilant avec les warnings (options gcc -Wall -Wextra), le compilateur avertit d'ailleurs qu'il y a un problème sur ce code : "warning: ‘temp1’ is used uninitialized in this function [-Wuninitialized]".
Modifié le 10 janv. 2023 à 13:37
voilà une illustration de tests pour tes fonctions :
int main(void) { struct Tuile tuile = (struct Tuile) {EST, FORME_L, CASE_PION1}; int dessin[3][3]; /* test get_dessin_de_base() */ { get_dessin_de_base(dessin, tuile); int dessin_expected[3][3] = { {1,0,0}, {1,0,0}, {1,1,1}, }; assert(memcmp(dessin, dessin_expected, 3 * 3 * sizeof(int)) == 0 && "get_dessin_de_base gets default L shape"); } /* test rotation_90() - one anticlockwise rotation */ { get_dessin_de_base(dessin, tuile); rotation_90(dessin); int dessin_expected[3][3] = { {0,0,1}, {0,0,1}, {1,1,1}, }; assert(memcmp(dessin, dessin_expected, 3 * 3 * sizeof(int)) == 0 && "one rotation_90 of L shape gives expected shape"); }; /* test rotation_90() - two anticlockwise rotations */ { get_dessin_de_base(dessin, tuile); rotation_90(dessin); rotation_90(dessin); int dessin_expected[3][3] = { {1,1,1}, {0,0,1}, {0,0,1}, }; assert(memcmp(dessin, dessin_expected, 3 * 3 * sizeof(int)) == 0 && "two rotation_90 of L shape gives expected shape"); }; /* done */ printf("All tests pass.\n"); return 0; }
(assert() est accessible par l'entête standard assert.h)
Si tu écris ces tests avant de mettre au point les fonctions en question, tu sais que quand le test passe, ta fonction est "au point" et tu peux passer au test du comportement suivant. Tu peux rejouer tous les tests automatiquement systématiquement pendant tes itérations de développement.
Lorsque tu modifies ton code pour le factoriser ou l'améliorer, tu peux ainsi t'assurer de l'absence de régressions.
Lorsque tu ajoutes de nouvelles fonctionnalités, tu écris d'abord le test pour cette nouvelle fonction et tu constates qu'elle échoue (tu ne l'as pas encore programmée). Lorsque le test passe, et ce sans effets de bord affectant les comportements précédemment testés, tu t'est assuré que ta nouvelle fonctionnalité est "au point" et qu'elle ne casse pas ce que tu as fait avant.
Tu n'exécutes le main() "normal" que lorsque ta fonction testée est "au point" et que tu veux voir le déroulement du programme avec tes fonctions testées "au point" avec des pièces choisies au hasard, avec l'interaction d'un utilisateur réel, etc.