/* jeu-taquin.c : un jeu de taquin * * Edouard.Thiel@lif.univ-mrs.fr - 03/07/2011 - version 1.2 * * Compilation sous Unix : * gcc -Wall jeu-taquin.c ez-draw.c -o jeu-taquin -lX11 -lXext -L/usr/X11R6/lib * Compilation sous Windows : * gcc -Wall jeu-taquin.c ez-draw.c -o jeu-taquin.exe -lgdi32 * * This program is free software under the terms of the * GNU Lesser General Public License (LGPL) version 2.1. */ #include "ez-draw.h" /*------------------------- D E F I N I T I O N S ---------------------------*/ #define TAQUIN_H 5 #define TAQUIN_L 5 #define ANIME_NB 10 #define MELAN_NB (TAQUIN_H*TAQUIN_L*2) #define DELAY1 30 #define DELAY2 10 typedef struct { int grille[TAQUIN_H][TAQUIN_L]; int clic_i, clic_j, vide_i, vide_j; enum { E_DEBUT, E_JEU, E_ANIME, E_GAGNE, E_MELAN } etat; int anim_etape, melan_etape; } App; #define CASE_XB 20 #define CASE_YB 40 #define CASE_YC 30 #define CASE_XM 50 #define CASE_YM 50 #define WIN1_H (CASE_YB+CASE_YM*TAQUIN_H+CASE_YC) #define WIN1_L (CASE_XB+CASE_XM*TAQUIN_L+CASE_XB) typedef struct { App *app; Ez_window win1; } Gui; /*------------------------------- M O D E L E -------------------------------*/ void init_grille (App *app) { int i, j, k = 1; for (i = 0; i < TAQUIN_H; i++) for (j = 0; j < TAQUIN_L; j++) app->grille[i][j] = k++; app->vide_i = TAQUIN_H-1; app->vide_j = TAQUIN_L-1; app->grille[app->vide_i][app->vide_j] = 0; } int coup_est_possible (App *app) { if (app->clic_i < 0 || app->clic_i >= TAQUIN_H || app->clic_j < 0 || app->clic_j >= TAQUIN_L) return 0; if ( (app->clic_i == app->vide_i && app->clic_j != app->vide_j) || (app->clic_i != app->vide_i && app->clic_j == app->vide_j) ) return 1; return 0; } int case_est_poussee (App *app, int i, int j) { if ( ( (app->clic_i <= i && i <= app->vide_i) || (app->vide_i <= i && i <= app->clic_i) ) && ( (app->clic_j <= j && j <= app->vide_j) || (app->vide_j <= j && j <= app->clic_j) ) ) return 1; return 0; } void calculer_deplacement (App *app, int *si, int *sj, int *n) { int ni = app->clic_i - app->vide_i, nj = app->clic_j - app->vide_j; *n = abs(ni)+abs(nj); *si = ni / *n; *sj = nj / *n; } void pousser_cases (App *app) { int si, sj, n, ki, kj, k; calculer_deplacement (app, &si, &sj, &n); for (k = 0; k < n; k++) { ki = app->vide_i+k*si; kj = app->vide_j+k*sj; app->grille[ki][kj] = app->grille[ki+si][kj+sj]; } app->vide_i = app->clic_i; app->vide_j = app->clic_j; app->grille[app->vide_i][app->vide_j] = 0; } int piece_est_bonne (App *app, int i, int j) { if (i == TAQUIN_H-1 && j == TAQUIN_L-1) return app->grille[i][j] == 0; return app->grille[i][j] == i*TAQUIN_L+j+1; } int partie_est_gagnee (App *app) { int i, j; for (i = 0; i < TAQUIN_H; i++) for (j = 0; j < TAQUIN_L; j++) if (! piece_est_bonne (app, i, j)) return 0; return 1; } void coup_aleatoire (App *app) { /* On alterne les lignes et les colonnes selon melan_etape */ if (app->melan_etape % 2 == 0) { app->clic_i = ez_random (TAQUIN_H-1); if (app->clic_i >= app->vide_i) app->clic_i ++; app->clic_j = app->vide_j; } else { app->clic_j = ez_random (TAQUIN_L-1); if (app->clic_j >= app->vide_j) app->clic_j ++; app->clic_i = app->vide_i; } } /*---------------------------------- V U E ---------------------------------*/ /* Coordonnees pixels x,y --> coordonnees grille j,i */ int grille_get_x (int j) { return CASE_XB + j*CASE_XM; } int grille_get_y (int i) { return CASE_YB + i*CASE_YM; } /* Coordonnes grille j,i --> coordonnees pixels x,y */ int grille_get_j (int x) { return (x - CASE_XB) / CASE_XM - (x < CASE_XB); } int grille_get_i (int y) { return (y - CASE_YB) / CASE_YM - (y < CASE_YB); } void dessin_case_xy (Ez_window win, int x, int y, int val, int clic, int bonne) { int x1 = x+2, y1 = y+2, x2 = x+CASE_XM-2, y2 = y+CASE_YM-2; if (val == 0) return; ez_set_thick (clic ? 3 : 1); ez_set_color (clic ? ez_black : ez_grey); ez_draw_rectangle (win, x1, y1, x2, y2); ez_set_color (bonne ? ez_blue : ez_red); ez_set_nfont (3); ez_draw_text (win, EZ_MC, x+CASE_XM/2, y+CASE_YM/2, "%d", val); } void dessin_case_ij (Ez_window win, int i, int j, int val, int clic, int bonne) { int xb = grille_get_x (j), yb = grille_get_y (i); dessin_case_xy (win, xb, yb, val, clic, bonne); } void dessin_case_animee (Ez_window win, App *app, int i, int j) { int xb = grille_get_x (j), yb = grille_get_y (i), si, sj, n; calculer_deplacement (app, &si, &sj, &n); xb -= sj * CASE_XM * app->anim_etape / ANIME_NB; yb -= si * CASE_YM * app->anim_etape / ANIME_NB; dessin_case_xy (win, xb, yb, app->grille[i][j], 0, 0); } void dessin_taquin (Ez_window win, App *app) { int i, j; for (i = 0; i < TAQUIN_H; i++) for (j = 0; j < TAQUIN_L; j++) { if ( (app->etat == E_ANIME || app->etat == E_MELAN) && case_est_poussee (app, i, j) ) dessin_case_animee (win, app, i, j); else dessin_case_ij (win, i, j, app->grille[i][j], i == app->clic_i && j == app->clic_j, piece_est_bonne (app, i, j)); } } /*-------------------- E V E N E M E N T S W I N 1 ----------------------*/ void win1_onExpose (Ez_event *ev) { Gui *gui = ez_get_data (ev->win); App *app = gui->app; char *s; ez_set_color (ez_magenta); ez_set_nfont (2); ez_draw_text (ev->win, EZ_TC, WIN1_L/2, 10, app->etat == E_GAGNE ? "BRAVO !!" : "JEU DE TAQUIN"); dessin_taquin (ev->win, app); switch (app->etat) { case E_DEBUT : s = "Pressez espace pour melanger"; break; case E_JEU : s = "Cliquez sur une case"; break; case E_ANIME : s = "Deplacement ..."; break; case E_GAGNE : s = "Pressez espace pour recommencer"; break; case E_MELAN : s = "Melange en cours ..."; break; default : s = ""; } ez_set_color (ez_black); ez_set_nfont (0); ez_draw_text (ev->win, EZ_BL, 10, WIN1_H-8, s); } void win1_onMotionNotify (Ez_event *ev) { (void) ev; /* Parametre inutilise' */ } void win1_onButtonPress (Ez_event *ev) { Gui *gui = ez_get_data (ev->win); App *app = gui->app; if (app->etat != E_JEU) return; app->clic_i = grille_get_i (ev->my); app->clic_j = grille_get_j (ev->mx); ez_send_expose (ev->win); } void win1_onButtonRelease (Ez_event *ev) { Gui *gui = ez_get_data (ev->win); App *app = gui->app; if (app->etat != E_JEU) return; if (coup_est_possible (app)) { app->etat = E_ANIME; app->anim_etape = 0; ez_start_timer (ev->win, DELAY1); } else { app->clic_i = app->clic_j = -1; } ez_send_expose (ev->win); } void win1_onKeyPress (Ez_event *ev) { Gui *gui = ez_get_data (ev->win); App *app = gui->app; switch (ev->key_sym) { case XK_q : ez_quit (); break; case XK_space : if (app->etat == E_DEBUT || app->etat == E_GAGNE) { app->etat = E_MELAN; app->melan_etape = 0; app->anim_etape = 0; coup_aleatoire (app); ez_start_timer (ev->win, DELAY1); ez_send_expose (ev->win); } break; } } void win1_onTimerNotify (Ez_event *ev) { Gui *gui = ez_get_data (ev->win); App *app = gui->app; if (app->etat != E_ANIME && app->etat != E_MELAN) return; app->anim_etape ++; if (app->anim_etape >= ANIME_NB) { pousser_cases (app); app->clic_i = app->clic_j = -1; if (app->etat == E_MELAN) { app->melan_etape ++; if (app->melan_etape >= MELAN_NB) app->etat = E_JEU; else { coup_aleatoire (app); app->anim_etape = 0; } } else { app->etat = E_JEU; if (partie_est_gagnee (app)) app->etat = E_GAGNE; } } if (app->etat == E_ANIME) ez_start_timer (ev->win, DELAY1); else if (app->etat == E_MELAN) ez_start_timer (ev->win, DELAY2); ez_send_expose (ev->win); } void win1_event (Ez_event *ev) /* Appele'e a chaque evenement sur win1 */ { switch (ev->type) { case Expose : win1_onExpose (ev); break; case MotionNotify : win1_onMotionNotify (ev); break; case ButtonPress : win1_onButtonPress (ev); break; case ButtonRelease : win1_onButtonRelease (ev); break; case KeyPress : win1_onKeyPress (ev); break; case TimerNotify : win1_onTimerNotify (ev); break; } } /*------------------------ I N I T G E N E R A L E ------------------------*/ void app_init (App *app) { init_grille (app); app->clic_i = app->clic_j = -1; app->etat = E_DEBUT; app->anim_etape = -1; } void gui_init (Gui *gui, App *app) { gui->app = app; gui->win1 = ez_window_create (WIN1_L, WIN1_H, "Jeu de taquin", win1_event); ez_window_dbuf (gui->win1, 1); ez_set_data (gui->win1, gui); } /*------------------ P R O G R A M M E P R I N C I P A L ------------------*/ int main () { App app; Gui gui; if (ez_init() < 0) exit(1); app_init (&app); gui_init (&gui, &app); ez_main_loop (); exit(0); }