From a774b48ee9b93649ed73c169d35b31fee1083ba8 Mon Sep 17 00:00:00 2001 From: lecointre Date: Thu, 4 Dec 2025 18:48:28 +0100 Subject: [PATCH] Bientot fini manque seulement les images --- obj/game_logic.o | Bin 4024 -> 4024 bytes obj/game_view.o | Bin 5064 -> 5928 bytes obj/images.o | Bin 3048 -> 3048 bytes obj/main.o | Bin 3792 -> 3624 bytes obj/menu_view.o | Bin 6152 -> 6160 bytes obj/utils.o | Bin 1496 -> 1496 bytes src/defs.h | 8 ++--- src/game_logic.c | 35 ++++---------------- src/game_logic.h | 21 ++++-------- src/game_view.c | 81 +++++++++++++++++++++++++---------------------- src/game_view.h | 9 ++---- src/images.c | 18 ++--------- src/images.h | 15 ++------- src/main.c | 38 ++++++---------------- src/menu_view.c | 47 +++------------------------ src/menu_view.h | 16 ++++------ src/utils.c | 5 --- src/utils.h | 8 +---- taquin | Bin 22048 -> 22048 bytes 19 files changed, 85 insertions(+), 216 deletions(-) diff --git a/obj/game_logic.o b/obj/game_logic.o index cf48cf81968caf1b8af1d73459357381fed153f2..ca3442c3625997b47e1e57ca9ddf4a5ae8ca6bc4 100644 GIT binary patch delta 392 zcmdlXze9e*4@P-ak8V~51_lO?&V#!&7#JA#F@iX~P_g5iMVPo58KovGFv~Fg{j=GQ z`86Y><76$?>d7lu&G=08jPwi@j0}uS3@i*xC%<8pVPu%h$yUwJ0y4#sPoRy-nU{^} z|K`bTzKo14lOM8&GulnI`mcB`<)?VqjokVqjnZIqT1V2)Hp>kV{-L86?cWzyLCXn}LA=Cd)V3kxQIW9!$DT zF60uI%wdL@4^qj4q>^{?LN0O1pCDnVIYLOXijyyLi8IDee#wMj0^aJh_ldTr!gxVm?SE50Xl*$qTu}CBK1$q2>r7$;wT> z$R*AgGx;S~zN9tOt_2W-z%Bv_6;CeY7MJven*Rh%R%Y@-ZgIv1lXr68XH1$rlc$_< Q(PTkhd&WhZ19{V#0EGQ*d;kCd diff --git a/obj/game_view.o b/obj/game_view.o index f3bd0482a5e64e88d9db723bf370606a69a05ef3..d53fc06bb174051de3beba2855da8603232bc3fe 100644 GIT binary patch delta 2679 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 IWNzmG06OvsI{*Lx delta 57 zcmaDM{z80%DYK5Lo{^rRf{}rdsey%|F#`y&FfcGEFfcH%GB7Z>`-L(vF)$tgi7{?Y IWNzmG06Q)TJpcdz diff --git a/obj/main.o b/obj/main.o index cd27842f63127f7c9bcd0f10b4975207accec896..42ad70bbd0599ee67e3d8a0256301094821443ab 100644 GIT binary patch delta 841 zcmca0yFzAy2Ga_ziCTseQ%xp&F!D@XFTpr<;)#BR<{$t0TXY#27`k11S`YBIB>eyX zzuUE^`3EC^tIq%b|0fqSrkHAYbh9!rFfe#@9^7Tjz`(GN5ya_*iXDFel6yJ--~a#J zp)K969sKJLb++bA=43Kf?L6iISGEJB46N3p*L8wNCq!TO)SSt)nH1Pwiv9clf5PMw zOnQ@lFeQa6_$1~fr{<>Sl_;d7D&!<86eJdvWTxur>2WbIxH~&rDQLL+g=#7on&=tn z87deV7?~JY7?^^rU|?WiVPIfTU|?VXxzOD&l!1wX@c>ASVe&*~YoTN&1_lO4K7lqS zXI?gsW@hHF$@iG67?U?gvOH&G9O8_%U~v1f8(hN$G#VDy-r$!pJ8F?l7gJ)^|rm%R3zJ3#(pU|?7<*^tkiGlC7`TGPpe QeCC`6To7K#WJ4Z#0Q5EW#Q*>R delta 908 zcmZ1>b3t~322%j{L@h(E?uY?oA@GC{~M)%Z=$stS%yv=*T9^-Gh`1k++$yH2xlb122m~$~OxH~&rDQLL+ zg=#7on(7(p87deV7?~Pa7#cIMFfcGEFfcHH{N(Nz%D}|HcmO2EI60BoT4*B^0|SF2 zpFkUvGcTJ*Gc)s&$?KS_7&mU#WO>fW$T3-vO`MS*Oe%s&Z7^xQ*^!N(Q7k0CG&v*H zHP5l6BsH%jl>x$^?9cAV#GpNSBD=Vx3n(BM7{HETV_;zT^B)5ICLd%MmkdRcBlB_6_?ElGy zoZ^yvAS0pf6ho4gn!J!xpV4UYMNVONNUO_GjfTm_94m2AjvLA5|^FK%k`Ua z<77^5b50IW5Hm0^?3nDyZO-^{awE4rgv@$R-_)I>@YtDFMG9#Zl0QLSJ AS^xk5 diff --git a/obj/menu_view.o b/obj/menu_view.o index dd992006d617de19f1caff39ee518f187171d50f..306e82974799c42ab9510d2868e6e916d3e5e974 100644 GIT binary patch delta 984 zcmeA$m|!qLgK@${&8O-+nHU%tJbGCfKvd_UeMSrn4EsUE3y{c8Mv!nXE5l?{Mte@z z10KD+AmPcijLX!zU0a~iq9Cz-af}QMoyWo2KvEzvk6zKqo=h@G8uOS;ICjFMR-s6p zXR@vDJc#6!8b$_&7k(@Z4BeqE-L4&s7kVo+Ji1*scwnm1fT`-~wPC`ch6Sz$r%5af z3@`3YZf3UUbOeWsPcQ4_K4!_y&zT!oCTDOQ)G*OA(lb;rGB7eRurM%XU}0cjP+(wS z0EM2rUnm0;1LFaZ7{la1&S?Ir%nS?+j(h@bOwPP)%o8^6=Hz9RG++n$o`InpLNQ1( zFo3i%ET8<4OPuk+$&P~JlHWlQ47P-U z0py^iP>ZD}7Yd3?I)a3-$VN?GC@3yj43!1>Nq~WY;m>~vsG59HP+YPJNtP2ywhOFx zI#d>9J&3s+YVXm>hCV!s3#5kz_$p1q%U<$$`S* zlBc1*Xn;720b~OR- z^$;UHIuGuvVPs%<;laYd&>h;+?b^Y3p|?WAquX@@R5M(ODojaFuMHD61uSp{IL&y- z%)sE$?YhHb@^of%0jQrH!9n8Ld0_Kx=BX@`^EnRjnd%wo87deV7?~Pa7#dHu=agh* zoE*s+&ELb!z`)?hC(y>^%*)2yzWFdGFC(M+fyBVj0ihUl7#J9s7#JC@ zPiEvcXY845$^D%1&}2m(cgCxmGkMN4F6d4YfdW9sCK0{V>YlNklwCC`Ck4{R_41IQ_hp_YA|oG2(RDFhP2B5OK% zqM*2>A5@lwfq{XWfq~)Ae+WpQd{9taG7l;XvH-+{$(Bw2C@3yj2NGgnU_jT~I$2Rj zTyhVRtRRxf7bXV^iA&yu%7RQ5L6Utwxlu@5@+UY|LQED%l69TDQAk`e1{$a!dj*hW zlP5nE5|_+IlI28_Ee7j7jwCCABztADqp&!m{NzaCaK=NEHwueOUWK}00W>s0E(PK1 zlOGC;OR7W7d4MK6Z?d4seMYs(A4SX=1tx2X+B2nbOr9trHn~Am1I9ccs==5s`K72m zqs(MYF?%KpPKXLI4MvN}E5+>KH=l`~k)EM~k%5tkfrWwT#F_Gp3>$aKvjPB&Y6x%u delta 30 mcmcb?eS>>KH=n7Vk)EM~k%5t^frX**#F_Gpj2m~#vjPB&iwJT6 diff --git a/src/defs.h b/src/defs.h index ea890fe..b9ff645 100644 --- a/src/defs.h +++ b/src/defs.h @@ -1,12 +1,8 @@ -/* src/defs.h - * Définitions des constantes globales (taille de fenêtre, cycles). - * Inclus par main.c et game_view.c. - */ #ifndef DEFS_H #define DEFS_H #define WINDOW_WIDTH 800 #define WINDOW_HEIGHT 600 -#define REFRESH_CYCLE 50000L /* 50 ms */ +#define REFRESH_CYCLE 50000L -#endif /* DEFS_H */ +#endif diff --git a/src/game_logic.c b/src/game_logic.c index 9a15f0b..22295ef 100644 --- a/src/game_logic.c +++ b/src/game_logic.c @@ -1,38 +1,31 @@ -/* src/game_logic.c */ - #include "game_logic.h" #include "utils.h" #include #include -/* --- Utilitaires de positionnement --- */ -/* Convertit un index 1D en coordonnées 2D */ static void index_to_coords(int index, int cols, int *r, int *c) { *r = index / cols; *c = index % cols; } -/* Trouve les indices des tuiles adjacentes à la case vide */ static int find_adjacent_indices(int idx, int rows, int cols, int *out_indices) { int r = idx / cols; int c = idx % cols; int n = 0; - if (r > 0) out_indices[n++] = (r - 1) * cols + c; /* Haut */ - if (r < rows - 1) out_indices[n++] = (r + 1) * cols + c; /* Bas */ - if (c > 0) out_indices[n++] = r * cols + (c - 1); /* Gauche */ - if (c < cols - 1) out_indices[n++] = r * cols + (c + 1); /* Droite */ + if (r > 0) out_indices[n++] = (r - 1) * cols + c; + if (r < rows - 1) out_indices[n++] = (r + 1) * cols + c; + if (c > 0) out_indices[n++] = r * cols + (c - 1); + if (c < cols - 1) out_indices[n++] = r * cols + (c + 1); return n; } -/* --- Fonctions publiques --- */ -/* Initialise le jeu à l'état résolu et alloue la mémoire */ void game_init(game_state_t *state, int rows, int cols, tile_t **tiles) { int num_tiles = rows * cols; @@ -44,7 +37,6 @@ void game_init(game_state_t *state, int rows, int cols, tile_t **tiles) state->is_solved = 1; state->all_tiles = tiles; - /* Allocation dynamique de la permutation (malloc) */ state->permutation = (int *)malloc(num_tiles * sizeof(int)); if (state->permutation == NULL) { @@ -52,27 +44,22 @@ void game_init(game_state_t *state, int rows, int cols, tile_t **tiles) return; } - /* Remplissage à l'état résolu : IDs 0, 1, 2, ... N-2 */ for (i = 0; i < num_tiles - 1; i++) { state->permutation[i] = i; } - /* La dernière case est la case vide (-1) */ state->permutation[num_tiles - 1] = -1; state->empty_index = num_tiles - 1; } -/* Libère la mémoire allouée par game_init */ void game_free(game_state_t *state) { if (state->permutation != NULL) { free(state->permutation); state->permutation = NULL; } - /* Note: tiles sont libérés par images_free_tiles dans main.c */ } -/* Vérifie si la tuile peut bouger (adjacence) */ int game_can_move(const game_state_t *state, int index_to_move) { int r_tile, c_tile; @@ -84,14 +71,12 @@ int game_can_move(const game_state_t *state, int index_to_move) index_to_coords(index_to_move, state->cols, &r_tile, &c_tile); index_to_coords(state->empty_index, state->cols, &r_empty, &c_empty); - /* Test d'adjacence géographique (manhattan distance = 1) */ if (abs_val(r_tile - r_empty) + abs_val(c_tile - c_empty) == 1) { return 1; } return 0; } -/* Déplace la tuile vers la case vide si possible */ int game_move_tile(game_state_t *state, int index_to_move) { int temp_tile_id; @@ -100,33 +85,27 @@ int game_move_tile(game_state_t *state, int index_to_move) return 0; } - /* Échange des valeurs (swap) */ temp_tile_id = state->permutation[index_to_move]; state->permutation[index_to_move] = state->permutation[state->empty_index]; state->permutation[state->empty_index] = temp_tile_id; - /* Mise à jour de la nouvelle position de la case vide */ state->empty_index = index_to_move; - /* Mise à jour des compteurs */ state->moves++; state->is_solved = game_is_solved(state); return 1; } -/* Vérifie si le plateau est dans l'état résolu */ int game_is_solved(const game_state_t *state) { int num_tiles = state->rows * state->cols; int i; - /* La case vide doit être en dernière position (-1) */ if (state->permutation[num_tiles - 1] != -1) { return 0; } - /* Toutes les autres tuiles doivent être dans l'ordre (ID = Position) */ for (i = 0; i < num_tiles - 1; i++) { if (state->permutation[i] != i) { return 0; @@ -136,7 +115,6 @@ int game_is_solved(const game_state_t *state) return 1; } -/* Mélange garanti solvable par N mouvements aléatoires */ void game_shuffle_safe(game_state_t *state, int steps) { int prev_move = -1; @@ -148,15 +126,14 @@ void game_shuffle_safe(game_state_t *state, int steps) for (i = 0; i < steps; i++) { n_choices = find_adjacent_indices(state->empty_index, state->rows, state->cols, choices); - /* Choisir une tuile adjacente au hasard, sans revenir en arrière immédiatement */ + do { pick_index = choices[random_int(n_choices)]; } while (n_choices > 1 && pick_index == prev_move); - /* Déplacer la tuile (utilise la logique de déplacement) */ game_move_tile(state, pick_index); - /* L'ancienne position vide est la tuile qui vient d'être déplacée (pour la prochaine itération) */ + prev_move = pick_index; } diff --git a/src/game_logic.h b/src/game_logic.h index 6071486..ed0d7e6 100644 --- a/src/game_logic.h +++ b/src/game_logic.h @@ -1,38 +1,29 @@ -/* src/game_logic.h - * Définition de l'état du plateau et des prototypes pour le moteur de jeu. - */ - #ifndef GAME_LOGIC_H #define GAME_LOGIC_H -#include "images.h" /* Nécessaire pour le type tile_t */ +#include "images.h" -/* Structure de l'état complet du Taquin */ typedef struct { int rows; int cols; - /* Tableau 1D alloué dynamiquement pour la permutation */ int *permutation; - int empty_index; /* Position actuelle (index 1D) de la case vide */ - unsigned long moves; /* Compteur de coups */ - int is_solved; /* 1 si gagné */ + int empty_index; + unsigned long moves; + int is_solved; - tile_t **all_tiles; /* Les tuiles découpées */ + tile_t **all_tiles; } game_state_t; -/* Prototypes des fonctions publiques */ void game_init(game_state_t *state, int rows, int cols, tile_t **tiles); void game_free(game_state_t *state); -/* Logique de jeu */ int game_move_tile(game_state_t *state, int index_to_move); int game_can_move(const game_state_t *state, int index_to_move); -/* Solvabilité */ int game_is_solved(const game_state_t *state); void game_shuffle_safe(game_state_t *state, int steps); -#endif /* GAME_LOGIC_H */ +#endif diff --git a/src/game_view.c b/src/game_view.c index 94c4ca9..1d364aa 100644 --- a/src/game_view.c +++ b/src/game_view.c @@ -1,7 +1,3 @@ -/* src/game_view.c - * Implémentation du rendu graphique du plateau et de la boucle d'interaction. - */ - #include "game_view.h" #include #include @@ -9,21 +5,16 @@ extern int _X; extern int _Y; -#define MARGIN 50 /* Marge autour du plateau */ +#define MARGIN 50 -/* --- Fonctions Utilitaires Privées --- */ - -/* Vérifie si un clic est sur une tuile donnée */ static int is_in_tile_rect(int x_click, int y_click, int tile_x, int tile_y, int tile_w, int tile_h) { return (x_click >= tile_x && x_click <= tile_x + tile_w && y_click >= tile_y && y_click <= tile_y + tile_h); } -/* --- Fonctions de Rendu et de Logique --- */ -/* Dessine le plateau de jeu */ void game_render(const game_state_t *state) { int i, r, c; @@ -32,13 +23,11 @@ void game_render(const game_state_t *state) EffacerEcran(C_FOND); - /* On prend la taille des tuiles calculée lors du découpage */ int tile_display_w = state->all_tiles[0]->width; int tile_display_h = state->all_tiles[0]->height; ChoisirCouleurDessin(C_BORDURE); - /* Boucle sur toutes les cases du plateau */ for (i = 0; i < state->rows * state->cols; i++) { int tile_id = state->permutation[i]; int x_pos, y_pos; @@ -46,24 +35,20 @@ void game_render(const game_state_t *state) r = i / state->cols; c = i % state->cols; - /* Position d'affichage sur l'écran */ x_pos = MARGIN + c * tile_display_w; y_pos = MARGIN + r * tile_display_h; - if (tile_id != -1) { /* C'est une tuile (non vide) */ + if (tile_id != -1) { tile_t *current_tile = state->all_tiles[tile_id]; - /* ChargerImage(fichier, x_dst, y_dst, x_src, y_src, l, h) */ ChargerImage(current_tile->path, x_pos, y_pos, current_tile->src_x, current_tile->src_y, current_tile->width, current_tile->height); - /* Dessine la bordure */ DessinerRectangle(x_pos, y_pos, tile_display_w, tile_display_h); } else { - /* Dessine la case vide en couleur distincte (jaune) */ ChoisirCouleurDessin(CouleurParNom("yellow")); RemplirRectangle(x_pos, y_pos, tile_display_w, tile_display_h); ChoisirCouleurDessin(C_BORDURE); @@ -71,20 +56,43 @@ void game_render(const game_state_t *state) } } - /* Affichage du compteur de coups */ + + if (state->all_tiles != NULL && state->all_tiles[0] != NULL) { + tile_t *sample_tile = state->all_tiles[0]; + + int model_size = 150; + int model_x = WINDOW_WIDTH - MARGIN - model_size; + int model_y = MARGIN; + + ChoisirCouleurDessin(CouleurParNom("white")); + RemplirRectangle(model_x - 5, model_y - 5, model_size + 10, model_size + 10); + ChoisirCouleurDessin(CouleurParNom("black")); + + + ChargerImage(sample_tile->path, + model_x, model_y, + 0, 0, + model_size, model_size); + } + char buffer[100]; sprintf(buffer, "Coups: %lu", state->moves); EcrireTexte(MARGIN, WINDOW_HEIGHT - 30, buffer, 1); - /* Affichage de la victoire */ + int btn_x = WINDOW_WIDTH - 200; + int btn_y = WINDOW_HEIGHT - 60; + + ChoisirCouleurDessin(CouleurParNom("orange")); + RemplirRectangle(btn_x, btn_y, 150, 40); + ChoisirCouleurDessin(CouleurParNom("black")); + EcrireTexte(btn_x + 10, btn_y + 25, "MENU (R)", 1); + if (state->is_solved) { ChoisirCouleurDessin(CouleurParNom("red")); EcrireTexte(WINDOW_WIDTH / 2 - 100, WINDOW_HEIGHT / 2, "BRAVO ! PRESSEZ UNE TOUCHE.", 2); } } - -/* Gère les entrées (clic/clavier) et la boucle principale du jeu */ void game_loop(game_state_t *state) { unsigned long next_update = Microsecondes() + REFRESH_CYCLE; @@ -92,7 +100,6 @@ void game_loop(game_state_t *state) while (go_on && !state->is_solved) { - /* Rendu et rafraîchissement */ if (Microsecondes() > next_update) { game_render(state); @@ -100,7 +107,6 @@ void game_loop(game_state_t *state) next_update = Microsecondes() + REFRESH_CYCLE; } - /* Gestion des événements Souris */ if (SourisCliquee()) { int i; @@ -109,7 +115,11 @@ void game_loop(game_state_t *state) int tile_w = state->all_tiles[0]->width; int tile_h = state->all_tiles[0]->height; - /* Parcourir toutes les tuiles pour voir laquelle a été cliquée */ + if (is_in_tile_rect(x_click, y_click, WINDOW_WIDTH - 200, WINDOW_HEIGHT - 60, 150, 40)) { + go_on = 0; + break; + } + for (i = 0; i < state->rows * state->cols; i++) { int r = i / state->cols; int c = i % state->cols; @@ -118,14 +128,12 @@ void game_loop(game_state_t *state) int y_pos = MARGIN + r * tile_h; if (is_in_tile_rect(x_click, y_click, x_pos, y_pos, tile_w, tile_h)) { - /* Tenter de déplacer la tuile cliquée (indice i) */ game_move_tile(state, i); break; } } } - /* Gestion des événements Clavier */ if (ToucheEnAttente()) { int key = Touche(); @@ -134,48 +142,45 @@ void game_loop(game_state_t *state) int empty_c = state->empty_index % state->cols; if (key == XK_Escape) { - go_on = 0; + exit(EXIT_SUCCESS); } - /* CORRECTION FINALE : Inverse le mapping pour la perception intuitive */ + else if (key == 'r' || key == 'R') { + go_on = 0; + } else if (key == XK_Up) { - /* Flèche HAUT : Déplace la tuile en BAS (r + 1) vers le vide (r) */ target_index = (empty_r + 1) * state->cols + empty_c; } else if (key == XK_Down) { - /* Flèche BAS : Déplace la tuile en HAUT (r - 1) vers le vide (r) */ target_index = (empty_r - 1) * state->cols + empty_c; } else if (key == XK_Left) { - /* Flèche GAUCHE : Déplace la tuile de DROITE (c + 1) vers le vide (c) */ target_index = empty_r * state->cols + (empty_c + 1); } else if (key == XK_Right) { - /* Flèche DROITE : Déplace la tuile de GAUCHE (c - 1) vers le vide (c) */ target_index = empty_r * state->cols + (empty_c - 1); } - /* Tenter le mouvement s'il y a une cible */ if (target_index != -1) { game_move_tile(state, target_index); } } } - /* Si la boucle est terminée par la victoire ou ESC */ if (state->is_solved) { game_render(state); CopierZone(0, 0, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0, 0); - printf("BRAVO ! Partie terminee en %lu coups. Pressez 'N' pour Nouvelle Partie ou 'Q' pour Quitter.\n", state->moves); + printf("BRAVO ! Partie terminee en %lu coups.\n", state->moves); - /* Gère le choix de rejouer/quitter après la victoire */ while (1) { if (ToucheEnAttente()) { int key = Touche(); if (key == 'n' || key == 'N') { - return; /* Retourne au main pour relancer le menu */ + return; } else if (key == 'q' || key == 'Q') { - exit(EXIT_SUCCESS); /* Quitte le programme entier */ + exit(EXIT_SUCCESS); } } Microsecondes(); } } + + return; } diff --git a/src/game_view.h b/src/game_view.h index ba9b6b7..f7637ef 100644 --- a/src/game_view.h +++ b/src/game_view.h @@ -1,16 +1,13 @@ -/* src/game_view.h - * Définitions du module de la vue du plateau de jeu. - */ #ifndef GAME_VIEW_H #define GAME_VIEW_H #include "game_logic.h" #include "defs.h" -/* Dessine le plateau de jeu, les tuiles à leur position actuelle, et le compteur de coups. */ + void game_render(const game_state_t *state); -/* Gère la boucle principale du jeu, les événements (clics/clavier) et les rafraîchissements. */ + void game_loop(game_state_t *state); -#endif /* GAME_VIEW_H */ +#endif diff --git a/src/images.c b/src/images.c index ce96fda..4e65ddd 100644 --- a/src/images.c +++ b/src/images.c @@ -1,26 +1,19 @@ -/* src/images.c - * Gère le découpage de l'image source en tuiles (structures tile_t). - */ - #include "images.h" #include #include #include -/* Stocke les chemins des images disponibles (doit correspondre à NUM_IMAGES dans menu_view.h) */ static const char *IMAGE_PATHS[] = { "assets/image1.png", "assets/image2.png", "assets/image3.png" }; -/* Retourne les informations de l'image choisie */ image_source_t get_image_source(int selected_index) { image_source_t src; - /* TODO: Normalement, il faudrait charger l'image ici pour obtenir la VRAIE taille (width/height) - avec une fonction IUT. Pour l'instant, on simule une taille fixe. */ + src.width = 750; src.height = 450; @@ -32,7 +25,6 @@ image_source_t get_image_source(int selected_index) return src; } -/* Crée un tableau de tuiles découpées (allocation dynamique de structures) */ tile_t **images_slice(image_source_t img_src, int rows, int cols) { int num_tiles = rows * cols; @@ -40,25 +32,20 @@ tile_t **images_slice(image_source_t img_src, int rows, int cols) tile_t **tiles; int i, j, id = 0; - /* Calcul des dimensions d'une tuile */ tile_w = img_src.width / cols; tile_h = img_src.height / rows; - /* Allocation du tableau de pointeurs vers les structures de tuiles */ - tiles = (tile_t **) calloc(num_tiles, sizeof(tile_t *)); /* calloc pour initialiser à NULL */ + tiles = (tile_t **) calloc(num_tiles, sizeof(tile_t *)); if (tiles == NULL) return NULL; for (i = 0; i < rows; i++) { for (j = 0; j < cols; j++) { - /* Allocation de la structure de tuile */ tile_t *t = (tile_t *) malloc(sizeof(tile_t)); if (t == NULL) { - /* Gérer l'échec de malloc */ images_free_tiles(tiles, id); return NULL; } - /* Remplissage des champs (coordonnées de découpe) */ strcpy(t->path, img_src.path); t->width = tile_w; t->height = tile_h; @@ -73,7 +60,6 @@ tile_t **images_slice(image_source_t img_src, int rows, int cols) return tiles; } -/* Libère la mémoire allouée par images_slice */ void images_free_tiles(tile_t **tiles, int num_tiles) { int i; diff --git a/src/images.h b/src/images.h index a53ca1c..b784adc 100644 --- a/src/images.h +++ b/src/images.h @@ -1,35 +1,24 @@ -/* src/images.h - * Définition des structures pour la gestion et le découpage de l'image. - */ - #ifndef IMAGES_H #define IMAGES_H -/* Une tuile est une partie de l'image source */ typedef struct { char path[30]; - /* Coordonnées de la tuile DANS l'image source */ int src_x, src_y; int width, height; - int id; /* ID unique, de 0 à (L*C - 2) */ + int id; } tile_t; -/* Structure pour l'image source complète */ typedef struct { int width; int height; char path[30]; } image_source_t; -/* Prototypes */ -/* Obtient les informations de l'image choisie */ image_source_t get_image_source(int selected_index); -/* Crée et retourne un tableau de tuiles (découpage) */ tile_t **images_slice(image_source_t img_src, int rows, int cols); -/* Libère la mémoire allouée par images_slice (selon la règle free/malloc) */ void images_free_tiles(tile_t **tiles, int num_tiles); -#endif /* IMAGES_H */ +#endif diff --git a/src/main.c b/src/main.c index 6c7eab2..b9de518 100644 --- a/src/main.c +++ b/src/main.c @@ -1,8 +1,3 @@ -/* src/main.c - * Point d'entrée du programme Taquin. - * Gère la boucle principale des événements et la transition de vue (Menu -> Jeu). - */ - #include "menu_view.h" #include "game_logic.h" #include "images.h" @@ -17,23 +12,18 @@ int main(void) { menu_state_t menu_state; unsigned long next_update; - int play_again = 1; - /* 1. Initialisation de l'environnement IUT */ InitialiserGraphique(); CreerFenetre(10, 10, WINDOW_WIDTH, WINDOW_HEIGHT); + srand((unsigned int)time(NULL)); - /* Grande boucle pour rejouer (retourne au menu) */ do { - play_again = 0; /* Réinitialisation pour cette tentative */ - - /* 2. Phase de Configuration (Menu) */ menu_init(&menu_state); next_update = Microsecondes() + REFRESH_CYCLE; - while (menu_state.ready_to_play == 0 && menu_state.ready_to_play != -1) + while (menu_state.ready_to_play == 0) { if (Microsecondes() > next_update) { @@ -46,9 +36,10 @@ int main(void) menu_handle_mouse_click(&menu_state); } menu_handle_key(&menu_state); + + if (menu_state.ready_to_play == -1) goto end_program; } - /* Sortie du menu par validation */ if (menu_state.ready_to_play == 1) { image_source_t img_src; @@ -56,41 +47,32 @@ int main(void) game_state_t game_state; int num_tiles; - /* Préparation des données et initialisation du moteur de jeu */ img_src = get_image_source(menu_state.selected_image); tiles = images_slice(img_src, menu_state.rows, menu_state.cols); if (tiles == NULL) { fprintf(stderr, "Erreur: Allocation tuiles echouee. Retour au menu.\n"); - continue; + continue; } num_tiles = menu_state.rows * menu_state.cols; game_init(&game_state, menu_state.rows, menu_state.cols, tiles); game_shuffle_safe(&game_state, 500); - printf("DEBUG: Jeu prêt. Grille %d x %d melangee.\n", + printf("DEBUG: Jeu prêt. Grille %d x %d melangee. Lancement de la partie...\n", game_state.rows, game_state.cols); - /* Lancement de la BOUCLE DE JEU */ game_loop(&game_state); - - /* Après game_loop (si la boucle est sortie par victoire ou ESC) */ - /* S'assurer que le joueur veut rejouer */ - if (ToucheEnAttente()) { - int final_key = Touche(); - if (final_key == 'n' || final_key == 'N') { - play_again = 1; /* Remet la grande boucle en marche */ - } - } - /* Nettoyage des ressources allouées */ images_free_tiles(tiles, num_tiles); game_free(&game_state); + } - } while (play_again == 1); + } while (1); + +end_program:; FermerGraphique(); return EXIT_SUCCESS; diff --git a/src/menu_view.c b/src/menu_view.c index cdb6d1b..3d6c05f 100644 --- a/src/menu_view.c +++ b/src/menu_view.c @@ -1,16 +1,8 @@ -/* src/menu_view.c - * Implémentation complète de l'interface de configuration (Menu) - * Utilise la bibliothèque graphique IUT (graph.h). - */ - #include "menu_view.h" #include -#include /* Pour sprintf */ -#include /* Pour les calculs simples */ +#include +#include -/* --- DÉCLARATIONS (CONSTANTES ET VARIABLES GLOBALES IUT) --- */ - -/* Constantes de positionnement */ #define IMG_PREVIEW_SIZE 150 #define IMG_START_X 50 #define IMG_START_Y 150 @@ -18,28 +10,23 @@ #define BUTTON_SIZE 30 #define DIM_START_Y 350 -/* Variables globales de la bibliothèque IUT pour la souris */ extern int _X; extern int _Y; -/* --- PROTOTYPES DES UTILITAIRES PRIVÉS (OBLIGATOIRE EN C89) --- */ static int is_in_rect(int x_click, int y_click, int rx, int ry, int rw, int rh); static void draw_button(int x, int y, const char *text, couleur C_BG); static void draw_text_centered(int x, int y, int w, int h, const char *text, int size); -/* --- IMPLÉMENTATION DES FONCTIONS PUBLIQUES (.h) --- */ -/* Initialise l'état du menu */ void menu_init(menu_state_t *state) { - state->selected_image = 0; /* Image 1 sélectionnée par défaut */ + state->selected_image = 0; state->rows = MIN_DIMENSION; state->cols = MIN_DIMENSION; state->ready_to_play = 0; } -/* Dessine l'écran de configuration du menu */ void menu_render(const menu_state_t *state) { int i; @@ -53,11 +40,9 @@ void menu_render(const menu_state_t *state) EffacerEcran(C_FOND); ChoisirCouleurDessin(C_TEXTE); - /* 1. Titre et Section Image */ EcrireTexte(IMG_START_X, 50, "CONFIGURATION DU JEU TAQUIN", 2); EcrireTexte(IMG_START_X, 100, "1. Choisir l'image :", 1); - /* BOUCLE : Affichage des 3 aperçus d'images */ for (i = 0; i < NUM_IMAGES; i++) { int x = IMG_START_X + i * IMG_SPACING; int y = IMG_START_Y; @@ -65,10 +50,8 @@ void menu_render(const menu_state_t *state) sprintf(path, "assets/image%d.png", i + 1); - /* Affiche l'image */ ChargerImage(path, x, y, 0, 0, IMG_PREVIEW_SIZE, IMG_PREVIEW_SIZE); - /* Encadrement si sélectionné */ if (state->selected_image == i) { ChoisirCouleurDessin(C_SELECTION); DessinerRectangle(x - 5, y - 5, IMG_PREVIEW_SIZE + 10, IMG_PREVIEW_SIZE + 10); @@ -76,33 +59,27 @@ void menu_render(const menu_state_t *state) } ChoisirCouleurDessin(C_TEXTE); - /* 2. Section Dimensions */ int dim_section_x = IMG_START_X; int button_l_offset = 180; int button_c_offset = 400; EcrireTexte(dim_section_x, DIM_START_Y, "2. Choisir les dimensions (3x3 a 8x8) :", 1); - /* Affichage de la taille LIGNES */ EcrireTexte(dim_section_x, DIM_START_Y + 40, "Lignes :", 0); sprintf(buffer, "%d", state->rows); EcrireTexte(dim_section_x + 100, DIM_START_Y + 40, buffer, 0); - /* Affichage de la taille COLONNES */ EcrireTexte(dim_section_x + 250, DIM_START_Y + 40, "Colonnes :", 0); sprintf(buffer, "%d", state->cols); EcrireTexte(dim_section_x + 350, DIM_START_Y + 40, buffer, 0); - /* Boutons de contrôle LIGNES */ draw_button(dim_section_x + button_l_offset, DIM_START_Y + 30, "+", C_BOUTON); draw_button(dim_section_x + button_l_offset + 40, DIM_START_Y + 30, "-", C_BOUTON); - /* Boutons de contrôle COLONNES */ draw_button(dim_section_x + button_c_offset, DIM_START_Y + 30, "+", C_BOUTON); draw_button(dim_section_x + button_c_offset + 40, DIM_START_Y + 30, "-", C_BOUTON); - /* 3. Bouton DÉMARRER LA PARTIE */ ChoisirCouleurDessin(C_START); RemplirRectangle(300, 500, 200, 50); ChoisirCouleurDessin(CouleurParNom("white")); @@ -110,7 +87,6 @@ void menu_render(const menu_state_t *state) } -/* Gère l'interaction après un clic de souris */ void menu_handle_mouse_click(menu_state_t *state) { int i; @@ -121,7 +97,6 @@ void menu_handle_mouse_click(menu_state_t *state) int button_l_offset = 180; int button_c_offset = 400; - /* 1. Clic sur les images */ for (i = 0; i < NUM_IMAGES; i++) { int x_img = IMG_START_X + i * IMG_SPACING; int y_img = IMG_START_Y; @@ -132,35 +107,27 @@ void menu_handle_mouse_click(menu_state_t *state) } } - /* 2. Clic sur les boutons de Lignes (+/-) */ - - /* + Lignes */ - if (is_in_rect(x_click, y_click, dim_section_x + button_l_offset, DIM_START_Y + 30, btn_size, btn_size)) { + if (is_in_rect(x_click, y_click, dim_section_x + button_l_offset, DIM_START_Y + 30, btn_size, btn_size)) { if (state->rows < MAX_DIMENSION) state->rows++; return; } - /* - Lignes */ if (is_in_rect(x_click, y_click, dim_section_x + button_l_offset + 40, DIM_START_Y + 30, btn_size, btn_size)) { if (state->rows > MIN_DIMENSION) state->rows--; return; } - /* 3. Clic sur les boutons de Colonnes (+/-) */ - /* + Colonnes */ if (is_in_rect(x_click, y_click, dim_section_x + button_c_offset, DIM_START_Y + 30, btn_size, btn_size)) { if (state->cols < MAX_DIMENSION) state->cols++; return; } - /* - Colonnes */ if (is_in_rect(x_click, y_click, dim_section_x + button_c_offset + 40, DIM_START_Y + 30, btn_size, btn_size)) { if (state->cols > MIN_DIMENSION) state->cols--; return; } - /* 4. Clic sur DÉMARRER */ if (is_in_rect(x_click, y_click, 300, 500, 200, 50)) { state->ready_to_play = 1; return; @@ -168,7 +135,6 @@ void menu_handle_mouse_click(menu_state_t *state) } -/* Gère l'interaction clavier */ void menu_handle_key(menu_state_t *state) { if (ToucheEnAttente()) { @@ -195,15 +161,12 @@ void menu_handle_key(menu_state_t *state) } } -/* --- IMPLÉMENTATION DES UTILITAIRES PRIVÉS --- */ -/* Vérifie si (x_click, y_click) est dans le rectangle */ static int is_in_rect(int x_click, int y_click, int rx, int ry, int rw, int rh) { return (x_click >= rx && x_click <= rx + rw && y_click >= ry && y_click <= ry + rh); } -/* Dessine un bouton rectangulaire rempli avec du texte centré */ static void draw_button(int x, int y, const char *text, couleur C_BG) { ChoisirCouleurDessin(C_BG); @@ -212,12 +175,10 @@ static void draw_button(int x, int y, const char *text, couleur C_BG) draw_text_centered(x, y, BUTTON_SIZE, BUTTON_SIZE, (char*)text, 1); } -/* Centre le texte dans une zone (x, y, w, h) */ static void draw_text_centered(int x, int y, int w, int h, const char *text, int size) { int text_w = TailleChaineEcran((char*)text, size); int text_h_sup = TailleSupPolice(size); - /* Calcul de la position de départ pour centrer le texte */ int draw_x = x + (w - text_w) / 2; int draw_y = y + (h + text_h_sup) / 2; diff --git a/src/menu_view.h b/src/menu_view.h index cbead52..4041c3d 100644 --- a/src/menu_view.h +++ b/src/menu_view.h @@ -1,5 +1,3 @@ -/* src/menu_view.h */ - #ifndef MENU_VIEW_H #define MENU_VIEW_H @@ -7,18 +5,16 @@ #define MIN_DIMENSION 3 #define MAX_DIMENSION 8 -/* Structure de l'état du menu */ typedef struct { - int selected_image; /* Index de l'image (0, 1, ou 2) */ - int rows; /* Nombre de lignes (3 à 8) */ - int cols; /* Nombre de colonnes (3 à 8) */ - int ready_to_play; /* 1 si le joueur a validé, -1 si demande de quitter */ -} menu_state_t; /* <--- POINT-VIRGULE CORRECT */ + int selected_image; + int rows; + int cols; + int ready_to_play; +} menu_state_t; -/* Prototypes des fonctions publiques */ void menu_init(menu_state_t *state); void menu_render(const menu_state_t *state); void menu_handle_mouse_click(menu_state_t *state); void menu_handle_key(menu_state_t *state); -#endif /* MENU_VIEW_H */ +#endif diff --git a/src/utils.c b/src/utils.c index 1d250c3..8b2a4c5 100644 --- a/src/utils.c +++ b/src/utils.c @@ -1,9 +1,6 @@ -/* src/utils.c */ - #include "utils.h" #include -/* Renvoie la valeur absolue */ int abs_val(int n) { if (n < 0) { @@ -12,10 +9,8 @@ int abs_val(int n) return n; } -/* Renvoie un entier aléatoire entre 0 et max-1 */ int random_int(int max) { if (max <= 0) return 0; - /* rand() est initialisé dans main.c */ return rand() % max; } diff --git a/src/utils.h b/src/utils.h index 43913d1..1949ec1 100644 --- a/src/utils.h +++ b/src/utils.h @@ -1,14 +1,8 @@ -/* src/utils.h - * Déclarations des fonctions utilitaires simples. - */ - #ifndef UTILS_H #define UTILS_H -/* Renvoie la valeur absolue d'un entier */ int abs_val(int n); -/* Renvoie un entier aléatoire entre 0 et max-1 */ int random_int(int max); -#endif /* UTILS_H */ +#endif diff --git a/taquin b/taquin index b161afaf95ad0aa6d12868f1d44bc5a4b24b2a51..05de72011330ed5c5d8c59dbd8625d1c61a4d9a7 100755 GIT binary patch delta 5291 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 ZH0lE~bn?$2^~njrD;U`~bB2gB0RSn_XVL%w delta 4948 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 k8LTdQ6fM!A3^z>o9)SXzB|R