/* jeu-vie.c : le jeu de la vie de John Conway * * Edouard.Thiel@lif.univ-mrs.fr - 14/04/2009 - version 1.2 * * Compilation sous Unix : * gcc -Wall jeu-vie.c ez-draw.c -o jeu-vie -lX11 -lXext -L/usr/X11R6/lib * Compilation sous Windows : * gcc -Wall jeu-vie.c ez-draw.c -o jeu-vie.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 ---------------------------*/ /* Taille de la grille */ #define GRI_XM 100 #define GRI_YM 80 /* Taille en pixels */ #define W_X0 3 #define W_Y0 30 #define W_TA 7 /* Taille des fenetres */ #define WIN1_W (W_X0+W_TA*GRI_XM+W_X0) #define WIN1_H (W_Y0+W_TA*GRI_YM+20) /* Delai de l'animation */ #define DELAY1 200 /* Etats d'une case */ enum { E_VIDE, E_MORT, E_SURV, E_NAIS }; typedef struct { char *tab; int xmax, ymax, lastx, lasty, anim, delay, generation; } Grille; Grille grille; /*-------------------------------G R I L L E --------------------------------*/ void grille_vider (Grille *g) { int t; for (t = g->xmax*g->ymax-1; t >= 0; t--) g->tab[t] = 0; g->anim = g->generation = 0; } int grille_creer (Grille *g, int xmax, int ymax) { g->xmax = xmax; g->ymax = ymax; g->tab = malloc (xmax*ymax*sizeof(char)); if (g->tab == NULL) { perror ("grille_creer"); return -1; } grille_vider (g); g->delay = DELAY1; return 0; } void grille_liberer (Grille *g) { free (g->tab); g->tab = NULL; } void grille_exemple1 (Grille *g) { int x[] = {10, 11, 12, 12, 11, 30, 30, 31, 31, 31, 32, 32}, y[] = {10, 10, 10, 9, 8, 30, 31, 29, 32, 33, 30, 31}, i, n = sizeof(x)/sizeof(int); for (i = 0; i < n; i++) g->tab[y[i]*g->xmax+x[i]] = E_SURV; } void grille_etape (Grille *g) { int dx[] = {1, 1, 0, -1}, dy[] = {0, 1, 1, 1}, x, y, t, i, n, a, b; /* On balaie sequentiellement tous les points de la grille sauf le bord */ for (y = 1; y < g->ymax-1; y++) for (x = 1; x < g->xmax-1; x++) { n = 0; /* Nombre de voisins */ /* Ce voisin a deja ete traite' : s'il vient de mourir ou s'il a survecu, alors la case etait occupe'e avant. */ for (i = 0; i < 4; i++) { a = g->tab[(y-dy[i])*g->xmax + (x-dx[i])]; if (a == E_MORT || a == E_SURV) n++; } /* Ce voisin n'est pas encore traite' : s'il survit ou vient de naitre, alors la case est occupee. */ for (i = 0; i < 4; i++) { a = g->tab[(y+dy[i])*g->xmax + (x+dx[i])]; if (a == E_SURV || a == E_NAIS) n++; } t = y*g->xmax+x; b = g->tab[t]; if (b == E_VIDE || b == E_MORT) { /* La case est vide ou vient d'etre vide'e. Une naissance aura lieu si il y a exactement 3 voisins. */ g->tab[t] = (n == 3) ? E_NAIS : E_VIDE; } else { /* b == E_SURV || b == E_NAIS */ /* La case est occupe'e (survivant ou naissance). Elle survivra si il y a 2 ou 3 voisins. */ g->tab[t] = (n == 2 || n == 3) ? E_SURV : E_MORT; } } g->generation++; } void grille_modif (Ez_window win, Grille *g, int mx, int my, int clic, int bouton) { int x = (mx - W_X0) / W_TA, y = (my - W_Y0) / W_TA, a, t; if (g->anim) { ez_start_timer (win, -1); g->anim = 0; } if (x < 1 || x >= g->xmax-1 || y < 1 || y >= g->ymax-1) return; if (!clic && g->lastx == x && g->lasty == y) return; g->lastx = x; g->lasty = y; t = y * g->xmax + x; a = g->tab[t]; if (clic && bouton == 1) g->tab[t] = (a == E_MORT || a == E_VIDE) ? E_SURV : E_VIDE; else g->tab[t] = (bouton == 1) ? E_SURV : E_VIDE; ez_send_expose (win); } /*------------------------------ D E S S I N S ------------------------------*/ void cell_legende (Ez_window win, int x, int y, Ez_uint32 color, char *s) { ez_set_color (color); ez_fill_rectangle (win, x, y, x+W_TA-2, y+W_TA-2); ez_set_color (ez_black); ez_draw_text (win, EZ_BL, x+W_TA+5, y+W_TA+1, "%s", s); } void win1_redessiner (Ez_window win, Grille *g) { int x, y, a; cell_legende (win, 10, 15, ez_red, "naissance si 3 voisins"); cell_legende (win, 165, 15, ez_green, "survie si 2 ou 3 voisins"); cell_legende (win, 335, 15, ez_yellow, "mort"); ez_set_color (ez_black); ez_draw_text (win, EZ_TL, 400, 10, "generation %-7d delai %-4d ms animation %s", g->generation, g->delay, g->anim ? "ON " : "OFF"); ez_set_color (ez_grey); ez_draw_rectangle (win, W_X0+ W_TA-2, W_Y0+ W_TA-2, W_X0+(g->xmax-1)*W_TA , W_Y0+(g->ymax-1)*W_TA ); for (y = 0; y < g->ymax; y++) for (x = 0; x < g->xmax; x++) { a = g->tab[y*g->xmax+x]; if (a == E_VIDE) continue; switch (a) { case E_MORT : ez_set_color (ez_yellow); break; case E_SURV : ez_set_color (ez_green ); break; case E_NAIS : ez_set_color (ez_red ); break; } ez_fill_rectangle (win, W_X0+ x *W_TA, W_Y0+ y *W_TA, W_X0+(x+1)*W_TA-2, W_Y0+(y+1)*W_TA-2); } ez_set_color (ez_black); ez_draw_text (win, EZ_BL, 10, WIN1_H-5, "espace : anime d,D : delai v : vider q : quitter " "souris : bouton 1 dessine/efface, bouton 3 efface"); } /*--------------------------- E V E N E M E N T S ---------------------------*/ void win1_onExpose (Ez_event *ev) { win1_redessiner (ev->win, &grille); } void win1_onMotionNotify (Ez_event *ev) { if (ev->mb >= 1) grille_modif (ev->win, &grille, ev->mx, ev->my, 0, ev->mb); } void win1_onButtonPress (Ez_event *ev) { grille_modif (ev->win, &grille, ev->mx, ev->my, 1, ev->mb); } void win1_onButtonRelease (Ez_event *ev) { (void) ev; /* Parametre inutilise' */ } void win1_onKeyPress (Ez_event *ev) { switch (ev->key_sym) { case XK_q : ez_quit (); break; case XK_space : grille.anim = !grille.anim; ez_start_timer (ev->win, grille.anim ? 0 : -1); ez_send_expose (ev->win); break; case XK_v : if (grille.anim) ez_start_timer (ev->win, -1); grille_vider (&grille); ez_send_expose (ev->win); break; case XK_e : if (grille.anim) ez_start_timer (ev->win, -1); grille_vider (&grille); grille_exemple1 (&grille); ez_send_expose (ev->win); break; case XK_d : grille.delay /= 1.1; if (grille.delay < 0) grille.delay = 0; ez_send_expose (ev->win); break; case XK_D : grille.delay = grille.delay*1.1 + 1; if (grille.delay > 2000) grille.delay = 2000; ez_send_expose (ev->win); break; } } void win1_onTimerNotify (Ez_event *ev) { grille_etape (&grille); ez_send_expose (ev->win); ez_start_timer (ev->win, grille.delay); } 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; } } /*------------------ P R O G R A M M E P R I N C I P A L ------------------*/ int main () { Ez_window win1; if (ez_init() < 0) exit(1); grille_creer (&grille, GRI_XM, GRI_YM); grille_exemple1 (&grille); win1 = ez_window_create (WIN1_W, WIN1_H, "Jeu de la vie", win1_event); ez_window_dbuf (win1, 1); ez_main_loop (); exit(0); }