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.
 All files | Selected Files: delete move to page copy to page

Vous n'êtes pas autorisé à joindre un fichier à cette page.