Pièce jointe « ez_othello.c »
Téléchargement 1 #include "ez-draw.h"
2 #include <limits.h>
3 #define TAILLE_CASE 36
4 #define HAUT_TITRE 36
5 #define HAUT_LEGENDE 36
6 #define PROFMAX 16
7 #define PLUS 1
8 #define MOINS 0
9 #define TRUE 1
10 #define FALSE 0
11
12 typedef unsigned char Boolean;
13
14 typedef int Damier [10][10];
15
16 Damier d; // tableau à 2 dimensions qui représente le damier où l'on joue
17 int dir[8][2]; // pour aller dans les huit direction possibles
18
19 int nb[2]; // indique le nombre de pions de chaque joueur
20 Boolean passe[2]; // indique si le joueur passe
21 int trait,ntrait; // trait indique le joueur qui a le trait (i.e "la main") et ntrait celui qui ne l'a pas
22
23
24 int i_clic, j_clic; // coordonnées dans la grille de la case on l'on joue
25
26 Window win, win1, win2=None, win3, win4;
27
28
29 /* Pour la seconde partie */
30
31
32 enum{JOUEUR_ORDI,JOUEUR1_JOUEUR2};
33 int mode=JOUEUR1_JOUEUR2;
34
35 typedef struct coord
36 {
37 int l,c;
38 } Coord;
39
40 Coord libre[60]; // tableau des cases libres
41 int spl; // sommet de libre
42
43 int pile[PROFMAX][8]; //Indique le nombre de pions pris dans chacune des 8 directions
44 int sp; // sommet de pile
45
46 int val[PROFMAX]; // tableau où sont stockées les valeurs de retour provisoires
47 int v,mcp; // mcp indique le meilleur coup possible
48 int prof,pmax=10; // prof indique la profondeur où l'on se trouve, pmax est la profondeur maximale
49
50
51
52 void init()
53 {
54 int i,j,k,pas;
55 Coord u;
56
57 // on initialise sp
58 sp=-1;
59
60 // On borde le damier de cases fictives
61 for(i=1;i<9;i++)
62 {
63 for (j=1;j<9;j++) d[i][j]=-1;
64 d[i][0]=5;
65 d[i][9]=5;
66 }
67 for(j=0;j<10;j++)
68 {
69 d[0][j]=5;
70 d[9][j]=5;
71 }
72
73 // On place les 4 pions au centre
74 d[4][4]=1;d[4][5]=0;
75 d[5][4]=0;d[5][5]=1;
76 nb[0]=2;nb[1]=2;
77
78 //On initialise le tableau des directions
79 dir[0][0]=-1; dir[0][1]=1;
80 dir[1][0]=-1; dir[1][1]=0;
81 dir[2][0]=-1; dir[2][1]=-1;
82 dir[3][0]=0; dir[3][1]=1;
83 dir[4][0]=0; dir[4][1]=-1;
84 dir[5][0]=1; dir[5][1]=-1;
85 dir[6][0]=1; dir[6][1]=0;
86 dir[7][0]=1; dir[7][1]=1;
87
88 //On initialise le tableaux des cases libres en partant du centre de maniere concentrique
89 pas=3;
90 spl=-1;
91 for(k=3;k>0;k--)
92 {
93 for(j=k;j<=k+pas;j++)
94 {
95 u.l=k;
96 u.c=j;
97 spl++;
98 libre[spl]=u;
99 u.l=k+pas;
100 spl++;
101 libre[spl]=u;
102 }
103 for(i=k+1;i<k+pas;i++)
104 {
105 u.l=i;
106 u.c=k;
107 spl++;
108 libre[spl]=u;
109 u.c=k+pas;
110 spl++;
111 libre[spl]=u;
112 }
113 pas=pas+2;
114 }
115 trait=MOINS;
116 ntrait=PLUS;
117 passe[MOINS]=FALSE;
118 }
119
120
121 void dessine_pion(int x,int y,int joueur)
122 {
123 int a,b,c,e;
124 e=TAILLE_CASE/9;
125 a=HAUT_TITRE;
126 b=TAILLE_CASE/2;
127 c=TAILLE_CASE;
128 ez_set_color(joueur==PLUS?ez_green:ez_black);
129 ez_fill_circle(win,c+(x-1)*c+e,a+b+(y-1)*c+e,c+x*c-e,a+b+y*c-e);
130 }
131
132
133
134 void dessine_grille(Window win)
135 {
136 int a,b,c,hl,i,j;
137 a=HAUT_TITRE;
138 b=TAILLE_CASE/2;
139 c=TAILLE_CASE;
140 hl=HAUT_LEGENDE;
141 /* Affiche le titre */
142 ez_set_color(ez_magenta);
143 ez_set_nfont(2);
144 ez_draw_text(win,EZ_MC,c*5,a-20,"Reversi_Othello");
145
146 /*Dessine la grille*/
147 ez_set_color(ez_blue);
148 for(i=0;i<=8;i++)
149 {
150 ez_draw_line(win,c+i*c,a+b,c+i*c,a+b+8*c);
151 ez_draw_line(win,c,a+b+i*c,c+8*c,a+b+i*c);
152 }
153
154 /* Affichage des coordonnées */
155 ez_set_nfont(1);
156 for(i=1;i<=8;i++)
157 {
158 ez_draw_text(win,EZ_MC,b+i*c,a+5,"%d", i);
159 ez_draw_text(win,EZ_MC,b,a+i*c,"%d", i);
160 }
161
162 /* Dessine les pions*/
163 for (i=1;i<=8;i++)
164 for(j=1;j<=8;j++)
165 if (d[i][j]!=-1)
166 {
167 if(d[i][j]==PLUS)
168 dessine_pion(j,i,PLUS);
169 else
170 dessine_pion(j,i,MOINS);
171 }
172
173 /* Affiche legende en bas
174 dessine_pion(b+4*c, a+c*9+hl-4,trait);*/
175 ez_set_color (ez_black); ez_set_nfont (0);
176 ez_draw_text (win, EZ_BL, b, a+c*9+hl-4, "Le trait est aux:");
177 ez_set_color(trait==PLUS?ez_green:ez_black);
178 ez_fill_circle(win,b+3*c,b+9*c+hl-4,b+3*c+28,b+9*c+hl-4+28);
179
180 ez_set_color (ez_black);
181 ez_draw_text (win, EZ_BL, b+4*c, a+c*9+hl-4, "Pour passer cliquer ici => ");
182 ez_set_color (ez_blue);
183 ez_draw_rectangle(win,9*c,a+4+9*c,10*c,a+4+10*c);
184
185 ez_set_color (ez_black);
186 ez_draw_text (win, EZ_BL, b, a+c*10+hl-4, "Tapez 'h' pour les consignes");
187 ez_draw_text (win, EZ_BR, 7*c+18, a+c*10+hl-4, "Mode: ");
188 ez_set_color (ez_red);
189 ez_draw_text (win, EZ_BR, 10*c, a+c*10+hl-4,
190 mode == JOUEUR1_JOUEUR2 ? "JOUEUR1/JOUEUR2" : "JOUEUR1/ORDI ");
191
192 ez_set_color (ez_black);
193 }
194
195
196 /* La procédure possible vérifie si c'est possible de jouer en (i_clic,j_clic)
197 et empile le nombre de prises pour chacune des huit directions */
198 Boolean possible()
199 {
200 int i,j,k,n;
201 Boolean poss;
202 poss=FALSE;
203 sp++;
204 for(k=0;k<8;k++)
205 {
206 i=i_clic+dir[k][0];
207 j=j_clic+dir[k][1];
208 if (d[i][j]==ntrait)
209 {
210 n=0;
211 while(d[i][j]==ntrait)
212 {
213 n++;
214 i=i+dir[k][0];
215 j=j+dir[k][1];
216 }
217 if (d[i][j]==trait)
218 {
219 pile[sp][k]=n;
220 poss=TRUE;
221 }
222 else pile[sp][k]=0;
223 }
224 else pile[sp][k]=0;
225 }
226 if(!poss) sp--;
227 return poss;
228 }
229
230 // Joue le coup n°p et le retire de la "pile" des coups possibles
231 void jouer(int p)
232 {
233 int i,j,k,n;
234 Coord aux;
235 aux=libre[p];
236 libre[p]=libre[spl];
237 libre[spl]=aux;
238 spl--;
239 d[i_clic][j_clic]=trait;
240 nb[trait]++;
241 for(k=0;k<8;k++)
242 {
243 n=pile[sp][k];
244 i=i_clic;
245 j=j_clic;
246 while(n>0)
247 {
248 i=i+dir[k][0];
249 j=j+dir[k][1];
250 d[i][j]=trait;
251 nb[trait]++;
252 nb[ntrait]--;
253 n--;
254 }
255 }
256 }
257
258 // Recherche (i_clic,j_clic) dans la liste des coups possibles avant de le jouer
259 void jouer_coup()
260 {
261 int i;
262 Boolean trouve;
263 trouve=FALSE;
264 i=-1;
265 while (i<spl && !trouve)
266 {
267 i++;
268 trouve=i_clic==libre[i].l && j_clic==libre[i].c;
269 }
270 jouer(i);
271 }
272
273 // Déjoue le coup n°p
274 void dejouer(int p)
275 {
276 int i,j,k,n;
277 Coord aux;
278 spl++;
279 i_clic=libre[spl].l;
280 j_clic=libre[spl].c;
281 aux=libre[p];
282 libre[p]=libre[spl];
283 libre[spl]=aux;
284 d[i_clic][j_clic]=-1;
285 nb[trait]--;
286 for(k=0;k<8;k++)
287 {
288 n=pile[sp][k];
289 i=i_clic;
290 j=j_clic;
291 while (n>0)
292 {
293 i=i+dir[k][0];
294 j=j+dir[k][1];
295 d[i][j]=ntrait;
296 nb[trait]--;
297 nb[ntrait]++;
298 n--;
299 }
300 }
301 sp--;
302 }
303
304 // Evaluation qui tient compte du nombres de la différence des coups jouables
305 int eval2()
306 {
307 int x,y,i,j,k,u,j1,j2,t[2];
308 t[PLUS]=0;
309 t[MOINS]=0;
310 for (u=0;u<=spl;u++)
311 {
312 x=libre[u].l;
313 y=libre[u].c;
314 for(k=0;k<8;k++)
315 {
316 i=x+dir[k][0];
317 j=y+dir[k][1];
318 if(d[i][j]==0 || d[i][j]==1) //La case (x,y) est peut être un coup jouable
319 {
320 j2=d[i][j];
321 j1=(j2+1) % 2; //la case (x,y) est peut être jouable pour le joueur j1
322 do
323 {
324 i=i+dir[k][0];
325 j=j+dir[k][1];
326
327 }
328 while(d[i][j]==j2);
329 if ( d[i][j]==j1) t[j1]++;
330 }
331 }
332 }
333 return t[PLUS]-t[MOINS];
334 }
335
336 // Fonction d'évaluation qui tient compte de la différence de pions
337 int eval1()
338 {
339 return nb[PLUS]-nb[MOINS];
340 }
341
342 // Fonction d'évaluation
343 int eval()
344 {
345 if (spl<14)
346 return eval1();
347 else
348 return eval2();
349 }
350
351 // Permet d'élaguer l'arbre de recherche du meilleur coup
352 Boolean alphabeta()
353 {
354 int i;
355 Boolean b;
356 i=prof-1;
357 b=FALSE;
358 while(i>=0 && !b)
359 {
360 if (trait==PLUS)
361 b=val[prof]>=val[i];
362 else
363 b=val[prof]<=val[i];
364 i=i-2;
365 }
366 return b;
367 }
368
369 // Explore toutes les possibilités jusqu'à la profondeur pmax
370 int parcours()
371 {
372 int i,v,aux;
373 if (prof==pmax) return eval();
374 else
375 {
376 if (trait==PLUS)
377 val[prof]=INT_MIN;
378 else
379 val[prof]=INT_MAX;
380 i=0;
381 while (i<=spl && !alphabeta())
382 {
383 i_clic=libre[i].l;
384 j_clic=libre[i].c;
385 if (possible())
386 {
387 jouer(i);
388 aux=trait;
389 trait=ntrait;
390 ntrait=aux;
391 prof++;
392 v=parcours();
393 prof--;
394 aux=trait;
395 trait=ntrait;
396 ntrait=aux;
397 dejouer(i);
398 if (trait==PLUS)
399 {
400 if (v>=val[prof])
401 {
402 if (prof==0) mcp=i;
403 val[prof]=v;
404 }
405 else
406 if (v<val[prof]) val[prof]=v;
407 }
408 }
409 i++;
410 }
411 return val[prof];
412 }
413 }
414
415 //La fenêtre win1 indique que l'on ne peut pas passer son tour
416 void win1_event(Ez_event *ev)
417 {
418 switch(ev->type)
419 {
420 case Expose :
421 ez_set_nfont(2);
422 ez_draw_text(ev->win,EZ_TL,30,30,
423 " vous n'avez pas le droit de passer\n"
424 " car il existe des cases jouables !\n"
425 " \n"
426 " \n");
427 ez_draw_text(ev->win,EZ_TL,30,120,
428 " Une case jouable est la case (%d,%d)\n",i_clic,j_clic);
429 ez_set_color(ez_red);
430 ez_draw_text(ev->win,EZ_TL,30,300,
431 " Fermer cette fenêtre et veuillez jouer votre coup");
432 ez_set_color(ez_black);
433 break;
434 case ButtonPress :
435 case KeyPress :
436 case WindowClose : ez_window_destroy(win1);
437 }
438 }
439
440 // La fenêtre win2 donne les consignes pour jouer et permet de choisir le Mode
441 void win2_event(Ez_event *ev)
442 {
443 ez_set_nfont(1);
444 switch(ev->type)
445 {
446 case Expose:
447 ez_set_color(ez_black);
448 ez_draw_text(ev->win,EZ_TL,10,10,
449 "Pour jouer un coup, sélectionner une case en cliquant dessus,\n"
450 "Pour indiquer que vous n'avez pas d'autre choix que passer,\n"
451 "cliquer dans la case prévue, en bas à droite\n"
452 "\n"
453 "j: Pour jouer contre un autre joueur (on passe en MODE_JOUEUR)\n"
454 "o: Pour jouer contre l'ordinateur (on passe en MODE_ORDI)\n"
455 "q: Pour quitter\n"
456 "\n"
457 "\n"
458 " Une fois votre choix fait vous n'aurez plus la possibilité de changer\n"
459 );
460 break;
461 case ButtonPress:
462 case KeyPress:
463 switch(ev->key_sym)
464 {
465 case XK_j: mode=JOUEUR1_JOUEUR2;
466 ez_send_expose(ev->win);
467 break;
468 case XK_o: mode=JOUEUR_ORDI;
469 ez_send_expose(ev->win);
470 break;
471 }
472 case WindowClose: ez_window_destroy (win2);
473 }
474 }
475
476 // La fenêtre win3 indique que le coup choisi n'est pas possible
477 void win3_event(Ez_event *ev)
478 {
479 switch(ev->type)
480 {
481 case Expose :
482 ez_set_nfont(2);
483 ez_draw_text(ev->win,EZ_TL,30,30,
484 " Il n'est pas possible de jouer ce coup\n"
485 " \n");
486
487 ez_set_color(ez_red);
488 ez_draw_text(ev->win,EZ_TL,30,300,
489 " Fermer cette fenêtre et veuillez jouer un coup admissible");
490 ez_set_color(ez_black);
491 break;
492 case ButtonPress :
493 case KeyPress :
494 case WindowClose : ez_window_destroy(win3);
495 }
496 }
497
498 // La fenêtre win4 indique que la partie est terminée
499 void win4_event(Ez_event *ev)
500 {
501 switch(ev->type)
502 {
503 case Expose :
504 ez_set_nfont(2);
505 ez_draw_text(ev->win,EZ_TL,100,30,
506 " La partie est fini");
507 ez_set_color (ez_black);
508 if (nb[PLUS]==nb[MOINS])
509 ez_draw_text (win4, EZ_BL,100,100,"Il y a match nul\n");
510 else
511 {
512 ez_draw_text (win4, EZ_BL, 100, 100, "Les: ");
513 ez_set_color(nb[PLUS]>nb[MOINS]?ez_green:ez_black);
514 ez_fill_circle(win4,150,80,178,108);
515 ez_set_color(ez_black);
516 ez_draw_text (win4, EZ_BL, 190, 100, "ont gagné!");
517 if (nb[PLUS]>nb[MOINS])
518 ez_draw_text (win4, EZ_BL,150,150,"%d à %d", nb[PLUS],nb[MOINS]);
519 else
520 ez_draw_text (win4, EZ_BL,150,150,"%d à %d", nb[MOINS],nb[PLUS]);
521 }
522 break;
523 case ButtonPress :
524 case KeyPress :
525 case WindowClose : ez_window_destroy(win4);
526 }
527 }
528
529 // Un clic de souris a eu lieu dans la fenêtre win
530 void clic_case(int x, int y)
531 {
532 int aux, a=HAUT_TITRE, b=TAILLE_CASE/2, c=TAILLE_CASE;
533 int i;
534 Boolean jeu_possible=FALSE;
535 if(x>=9*c && x<10*c && y>=a+4+9*c && y<=a+4+10*c) /* On passe son tour */
536 {
537 i=0;
538 while (i<=spl && !jeu_possible) // Vérifie si l'on a le droit de passer
539 {
540 i_clic=libre[i].l;
541 j_clic=libre[i].c;
542 jeu_possible=possible();
543 i++;
544 }
545 if (!jeu_possible)
546 {
547 passe[trait]=TRUE;
548 aux=trait;
549 trait=ntrait;
550 ntrait=aux;
551 passe[trait]=FALSE;
552 }
553 else
554 {
555 sp--;
556 win1=ez_window_create(600,400,"Attention!",win1_event);
557 }
558 }else
559 {
560 if (x>=c && x<=9*c && y>=a+b && y<=a+b+8*c)
561 {
562 i_clic=(y-a-b)/c+1;
563 j_clic=(x-c)/c+1;
564 if (d[i_clic][j_clic]!=-1) /* la case est déjà jouée*/
565 {
566 win3=ez_window_create(600,400,"Attention!",win3_event);
567 }else
568 { /* on joue en (i_clic,j_clic) */
569 if (possible())
570 {
571 jouer_coup();
572 sp--;
573 aux=trait;
574 trait=ntrait;
575 ntrait=aux;
576 passe[trait]=FALSE;
577 }
578 else win3=ez_window_create(600,400,"Attention!",win3_event);
579 }
580 }
581 }
582 }
583
584
585 // La fenêtre win est la fenêtre où se déroule la partie
586 void win_event(Ez_event *ev)
587 {
588 switch (ev->type)
589 {
590 case Expose:
591 dessine_grille(ev->win);
592 break;
593 case ButtonPress:
594 clic_case(ev->mx,ev->my);
595 dessine_grille(ev->win);
596 //ez_send_expose(ev->win);
597 if (mode==JOUEUR_ORDI && trait==PLUS)
598 {
599 prof=0;
600 mcp=-1;
601 v=parcours();
602 if (mcp!=-1)
603 {
604 i_clic=libre[mcp].l;
605 j_clic=libre[mcp].c;
606 // si c'est possible on joue en i_clic,j_clic);
607 if (possible()) jouer(mcp);
608 sp--;
609 }
610 else
611 passe[trait]=TRUE;
612 int aux;
613 aux=trait;
614 trait=ntrait;
615 ntrait=aux;
616 passe[trait]=FALSE;
617 ez_send_expose(ev->win);
618 }
619 if(spl<14) pmax=spl+1; // En fin de partie on change pmax
620 if ((passe[trait]&& passe[ntrait]) || spl==-1)
621 {
622 dessine_grille(ev->win);
623 win4=ez_window_create(600,300,"Partie terminée",win4_event);
624 }
625 break;
626 case MotionNotify:
627 break;
628 case ButtonRelease:
629 break;
630 case KeyPress: if (ev->key_sym== XK_h && win2==None)
631 win2=ez_window_create(600,300,"Aide",win2_event);
632
633 break;
634
635 case WindowClose:
636 ez_window_destroy (win);
637 break;
638 }
639 }
640
641 int main()
642 {
643
644 if(ez_init()<0) exit(1);
645
646 init();
647 win=ez_window_create(TAILLE_CASE*11,TAILLE_CASE*10+HAUT_TITRE+HAUT_LEGENDE,"Reversi-Othello",win_event);
648 ez_auto_quit(0);
649 ez_main_loop();
650 system ("pause");
651
652 return 0;
653 }
Fichiers joints
Pour vous référer aux pièces jointes d'une page, utilisez attachment:filename, comme indiqué ci-dessous dans la liste de fichiers. N'utilisez pas l'URL du lien [get], car elle peut changer et donc être facilement cassée.Vous n'êtes pas autorisé à joindre un fichier à cette page.