#include <stdio.h>
#include <conio.h>
/*-------------------------- F I L E T T O ----------------------------------
La tavola di gioco (una percorso a 24 nodi) viene allocata in un vettore;
ogni casella della Tavola vale 0 se vuota, 1 se occupata dal giocatore 1,
2 se occupata dal giocatore 2.

La valutazione della mossa migliore in ogni fase del gioco viene affidata
ad una funzione ricorsiva, che deve essere in grado di valutare la mossa
perfetta.
I giocatori inseriranno le mosse utilizzando le 24 lettere ABC..WX
--------------------------------------------------------------------------*/
void Maschera     ( int );
void Pedine       ( void );
int  InKey        ( void );
int  LeggiClock   ( void );
void ValutaMossa  ( int, int, int, int *, int * );
void Valuta6vuote ( int, int, int, int *);
void Valuta5vuote ( int, int, int, int, int, int, int, int, int *);
void Valuta4vuote ( int, int, int, int, int, int, int, int *);
void Valuta3vuote ( int, int, int, int, int, int, int *);

int Win00 (int) ; int Win01 (int) ; int Win02 (int) ;
int Win03 (int) ; int Win04 (int) ; int Win05 (int) ;
int Win06 (int) ; int Win07 (int) ; int Win08 (int) ;
int Win09 (int) ; int Win10 (int) ; int Win11 (int) ;
int Win12 (int) ; int Win13 (int) ; int Win14 (int) ;
int Win15 (int) ; int Win16 (int) ; int Win17 (int) ;
int Win18 (int) ; int Win19 (int) ; int Win20 (int) ;
int Win21 (int) ; int Win22 (int) ; int Win23 (int) ;

int Casa00 (int) ; int Casa01 (int) ; int Casa02 (int) ;
int Casa03 (int) ; int Casa04 (int) ; int Casa05 (int) ;
int Casa06 (int) ; int Casa07 (int) ; int Casa08 (int) ;
int Casa09 (int) ; int Casa10 (int) ; int Casa11 (int) ;
int Casa12 (int) ; int Casa13 (int) ; int Casa14 (int) ;
int Casa15 (int) ; int Casa16 (int) ; int Casa17 (int) ;
int Casa18 (int) ; int Casa19 (int) ; int Casa20 (int) ;
int Casa21 (int) ; int Casa22 (int) ; int Casa23 (int) ;

//--------------------------- Variabili Globali -----------------------------

int (*Vince[])( int ) =
{ Win00 , Win01 , Win02 , Win03 , Win04 , Win05 , Win06 , Win07 ,
  Win08 , Win09 , Win10 , Win11 , Win12 , Win13 , Win14 , Win15 ,
  Win16 , Win17 , Win18 , Win19 , Win20 , Win21 , Win22 , Win23 ,
};
int (*ValoreCasa[])( int ) =
{ Casa00, Casa01, Casa02, Casa03, Casa04, Casa05, Casa06, Casa07,
  Casa08, Casa09, Casa10, Casa11, Casa12, Casa13, Casa14, Casa15,
  Casa16, Casa17, Casa18, Casa19, Casa20, Casa21, Casa22, Casa23,
};

int Tavola [24]; // scacchiera di gioco

int PuntiMossa[ ] = { 0, 0, 0, 0, 0,  0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0,
                      1, 7, 3, 0, 7, 31, 0, 0, 3, 0, 15, 0, 0, 0, 0, 0,
                      1, 3, 7, 0, 3, 15, 0, 0, 7, 0, 31, 0, 0, 0, 0, 0   };
//===========================================================================
void main ( void )
{ int Giocatori,         // giocatori attivi:
                         // 0 : Umano - Umano
                         // 1 : Computer - Umano
                         // 2 : Umano - Computer
      Who,               // giocatore che deve muovere: 1(primo) o 2
      DoveGioco,         // mossa da fare da parte di Who
      QuantoVale,        // valore della mossa (vista da Who)
      Nvuote,            // numero delle caselle vuote (con valore 0)
      Finito,            // -1 = configurazione iniziale
                         // 0 = gioco in corso
                         // 1 = gioco finito (vinto 1)
                         // 2 = gioco finito (vinto 2)
                         // 3 = gioco finito in pareggio
                         // 27= gioco finito per abbandono
      i,
      Time1, // tempi misurati in 1/18.2 secondo
      Time2;

  //=============== configurazione parametri iniziali =======================
  Maschera(-1);
  Finito = -1;
  do
  { switch ( i=InKey() )
    { case  27 : Giocatori = 0; Finito = 27; break; // Abbandono
      case 315 : Giocatori = 0; Finito =  0; break; // Umano - Umano
      case 316 : Giocatori = 1; Finito =  0; break; // Computer - Umano
      case 317 : Giocatori = 2; Finito =  0; break; // Umano - Computer
    }
  }
  while (Finito < 0);

  for (i=0; i<24; Tavola[i++]=0 ); // pulizia scacchiera
  Maschera (Giocatori);
  Who = 1;
  Nvuote = 24;
  textcolor(2); gotoxy ( 2, 16); cprintf("24 Caselle Vuote");
    
  //=============================== ciclo delle mosse ======================
  while (!Finito)
  { textcolor(13+Who); gotoxy (32, 23);
    cprintf ("Muove il giocatore %d \n", Who);

    DoveGioco = -1;

    if (Giocatori == Who) // mossa decisa dalla funzione di valutazione
    { gotoxy (2, 18); textcolor(12); cprintf("     ATTENDERE !      ");
      Time1 = LeggiClock ();
      ValutaMossa (Who, -99, +1, &DoveGioco, &QuantoVale);
      Time2 = LeggiClock () - Time1;
      textcolor(13+Who);
      gotoxy (2, 18); cprintf("\aMossa %c ", DoveGioco+65);
      switch (QuantoVale)
      { case -1: cprintf("perdente"); break;
        case  0: cprintf("pareggio"); break;
        case +1: cprintf("vincente");
      }
      gotoxy (2, 20); cprintf("Calcolo in %6.1f secondi", Time2/18.2);
    }
    else // mossa del giocatore umano tramite keyboard
    { if ( (i = InKey() ) == 27)
        Finito = 27;
      else if (i>=65 && i<=88 && Tavola[i-65]==0) // ABCD..X
        DoveGioco = i-65;
      else if (i>=97 && i<=120 && Tavola[i-97]==0) // abcd..x
        DoveGioco = i-97;
      else if (i==319) // F5 help mossa migliore
      { gotoxy (2, 18); textcolor(12); cprintf("     ATTENDERE !      ");
        Time1 = LeggiClock ();
        ValutaMossa (Who, -99, +1, &DoveGioco, &QuantoVale);
        Time2 = LeggiClock () - Time1;
        textcolor(13+Who);
        gotoxy (2, 18); cprintf("\aMossa %c ", DoveGioco+65);
        switch (QuantoVale)
        { case -1: cprintf("perdente"); break;
          case  0: cprintf("pareggio"); break;
          case +1: cprintf("vincente");
        }
        gotoxy (2, 20); cprintf("Calcolo in %6.1f secondi", Time2/18.2);
        DoveGioco = -1;
      }
    }

    if (DoveGioco >= 0)
    { Tavola[DoveGioco] = Who; Nvuote --; // occupa la casella
      if ( (*Vince[DoveGioco])(Who) ) Finito = Who; // mossa vincente
      else if ( Nvuote == 0 )         Finito =  3;  // pareggio
      else Who ^= 3;                                // passa all'avversario
      Pedine(); // Visualizza le pedine sul campo di gioco
      textcolor(2); gotoxy(2,16); cprintf("%2d Caselle Vuote",Nvuote);
    }
  }

  textbackground(0); textcolor(12); gotoxy (30, 23);
  switch (Finito)
  { case  1: cprintf (" Vittoria al giocatore 1 \n"); break;
    case  2: cprintf (" Vittoria al giocatore 2 \n"); break;
    case  3: cprintf (" Partita pareggiata \n"); break;
    case 27: cprintf (" Conclusione per Abbandono \n"); break;
  }
  while (getch()!= 27); // ESC per uscire dal gioco
}

/*===========================================================================
 Funzione per la valutazione della mossa migliore in un dato stato 
 del gioco supponendo che ciascuno giochi 'al meglio':
 Utilizza le variabili globali
    int Tavola[24] come scacchiera di gioco.
    int Nvuote numero delle caselle vuote (valore 0)
--------------------------------------------------------------------------*/
void ValutaMossa
( int Who,          // giocatore che deve muovere: 1 o 2
  int Alfa,         // valori di taglio per l'Alpha-Beta pruning
  int Beta,
  int *DoveMeglio,  // casella della mossa migliore
  int *MaxVale      // valore della scacchiera vista da Who:
                    // -1 sconfitta, 0 pareggio, +1 vittoria.
)
{ int i, j, k,      // indice sulle caselle della scacchiera
  Ohw,              // avversario Ohw = 3^Who
  Dove,             // miglior contromossa dell'avversario
  Vale,             // valore della contromossa (vista da 3^Who)
  Mossa[24],        // elenco delle mosse possibili (indici su caselle)
  Punti[24],        // valore corrispondente
  Nmos;             // Numero delle caselle vuote su Tavola[]

  for (i=Nmos=0; i<24; i++)
  if (Tavola[i]==0) { Mossa [Nmos] = i;
                      Punti [Nmos++] = (*ValoreCasa[i])(Who);
                    }
  for (i=0; i<Nmos-1; i++) // ordinamento decrescente
    for (j=i+1; j<Nmos; j++)
      if (Punti[i] < Punti[j])
      { k = Punti[i]; Punti[i] = Punti[j]; Punti[j] = k;
        k = Mossa[i]; Mossa[i] = Mossa[j]; Mossa[j] = k;
      }
  // se esiste una mossa vincente, è al primo posto.
  if (Punti[0] >= 31) // mossa vincente
  { *MaxVale = +1; *DoveMeglio = Mossa[0];
  }
  else
  { // Esegue prima le mosse vantaggiose [0]....[Nmos-1]
    for (*MaxVale=Alfa, Ohw=Who^3, i=0; i<Nmos && *MaxVale<Beta; i++)
    { Tavola [ Mossa[i] ] = Who; // occupa la casella
      if (Nmos==1) // se Mossa[i] era l'unica casella vuota, pareggio
      { *MaxVale = 0; *DoveMeglio = Mossa[i];
      }
      // chiede il parere dell'avversario, e poi considera il suo
      // miglior punteggio (Vale) cambiato di segno (strategia NegMax)
      else if (Nmos==7) // ci sono solo 6 caselle vuote rimanenti
      { Valuta6vuote (Ohw, -Beta, -(*MaxVale), &Vale);
        if (-Vale > *MaxVale) *MaxVale = -Vale, *DoveMeglio = Mossa[i];
      }
      else
      { ValutaMossa (Ohw, -Beta, -(*MaxVale), &Dove, &Vale);
        if (-Vale > *MaxVale) *MaxVale = -Vale, *DoveMeglio = Mossa[i];
      }
      Tavola [ Mossa[i] ] = 0; // libera la casella
    }
  }
}

/*===========================================================================
  Funzione per la valutazione della mossa migliore a SEI mosse dalla fine
  Utilizza la variabile globale int Tavola[24]
--------------------------------------------------------------------------*/
void Valuta6vuote
( int Who,      // giocatore che deve muovere: 1 o 2
  int Alfa,     // valori di taglio per l'Alpha-Beta pruning
  int Beta,
  int *MaxVale  // valore della scacchiera vista da Who:
                // -1 sconfitta, 0 pareggio, +1 vittoria.
)
{ int i    ,        // indice sulle caselle della scacchiera
      M1, M2, M3,
      M4, M5, M6,   // mosse possibili (indici su caselle vuote)
      Vale,         // valore della contromossa (vista da 3^Who)
      Ohw;          // avversario Ohw = 3^Who

  // Dapprima cerca, tra tutte le mosse possibili, quelle vincenti
  for (i=0; Tavola[i]; i++); // si ferma sulla prima vuota
  if ( (*Vince[M1=i])(Who) ) *MaxVale = +1;
  else
  { for (i++; Tavola[i]; i++); // si ferma sulla seconda vuota
    if ( (*Vince[M2=i])(Who) ) *MaxVale = +1;
    else
    { for (i++; Tavola[i]; i++); // si ferma sulla terza vuota
      if ( (*Vince[M3=i])(Who) ) *MaxVale = +1;
      else
      { for (i++; Tavola[i]; i++); // si ferma sulla quarta vuota
        if ( (*Vince[M4=i])(Who) ) *MaxVale = +1;
        else
        { for (i++; Tavola[i]; i++); // si ferma sulla quinta vuota
          if ( (*Vince[M5=i])(Who) ) *MaxVale = +1;
          else
          { for (i++; Tavola[i]; i++); // si ferma sulla sesta vuota
            if ( (*Vince[M6=i])(Who) ) *MaxVale = +1;
            else
            // Senza una vincente, riprova ogni mossa con contromosse
            { *MaxVale = Alfa;
              Tavola [M1] = Who; // occupa la prima casella
              Valuta5vuote ( M2, M3, M4, M5, M6,
                             Ohw=Who^3, -Beta, -(*MaxVale), &Vale);
              if (-Vale > *MaxVale) *MaxVale = -Vale;
              Tavola [M1] = 0; // libera la casella

              if (*MaxVale < Beta)
              { Tavola [M2] = Who; // occupa seconda casella
                Valuta5vuote ( M1, M3, M4, M5, M6,
                               Ohw, -Beta, -(*MaxVale), &Vale);
                if (-Vale > *MaxVale) *MaxVale = -Vale;
                Tavola [M2] = 0; // libera la casella

                if (*MaxVale < Beta)
                { Tavola [M3] = Who; // occupa la terza
                  Valuta5vuote ( M1, M2, M4, M5, M6,
                                 Ohw, -Beta, -(*MaxVale), &Vale);
                  if (-Vale > *MaxVale) *MaxVale = -Vale;
                  Tavola [M3] = 0; // libera la casella

                  if (*MaxVale < Beta)
                  { Tavola [M4] = Who; // occupa la quarta
                    Valuta5vuote ( M1, M2, M3, M5, M6,
                                   Ohw, -Beta, -(*MaxVale), &Vale);
                    if (-Vale > *MaxVale) *MaxVale = -Vale;
                    Tavola [M4] = 0; // libera la casella

                    if (*MaxVale < Beta)
                    { Tavola [M5] = Who; // occupa la quinta
                      Valuta5vuote ( M1, M2, M3, M4, M6,
                                     Ohw, -Beta, -(*MaxVale), &Vale);
                      if (-Vale > *MaxVale) *MaxVale = -Vale;
                      Tavola [M5] = 0; // libera la casella

                      if (*MaxVale < Beta)
                      { Tavola [M6] = Who; // occupa la sesta
                        Valuta5vuote ( M1, M2, M3, M4, M5,
                                       Ohw, -Beta, -(*MaxVale), &Vale);
                        if (-Vale > *MaxVale) *MaxVale = -Vale;
                        Tavola [M6] = 0; // libera la casella
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

/*===========================================================================
 Funzione per la valutazione della mossa migliore a CINQUE mosse dalla fine
 Utilizza la variabile globale int Tavola[24]
--------------------------------------------------------------------------*/
void Valuta5vuote
( int M1,         // mosse possibili (indici su caselle vuote)
  int M2,
  int M3,
  int M4,
  int M5,
  int Who,        // giocatore che deve muovere: 1 o 2
  int Alfa,       // valori di taglio per l'Alpha-Beta pruning
  int Beta,
  int *MaxVale    // valore della scacchiera vista da Who:
                  // -1 sconfitta, 0 pareggio, +1 vittoria.
)
{ int Vale,       // valore della contromossa (vista da 3^Who)
      Ohw;        // avversario Ohw = 3^Who

  // Dapprima cerca, tra tutte le mosse possibili, quelle vincenti
  if ((*Vince[M1])(Who) || (*Vince[M2])(Who) ||
      (*Vince[M3])(Who) || (*Vince[M4])(Who) ||
      (*Vince[M5])(Who)                         ) *MaxVale = +1;

  else // Senza una vincente, riprova ogni mossa con le contromosse
  { *MaxVale = Alfa;
    Tavola [M1] = Who;                 // occupa la prima casella
    Valuta4vuote (M2, M3, M4, M5, Ohw=Who^3, -Beta, -(*MaxVale), &Vale);
    if (-Vale > *MaxVale) *MaxVale = -Vale;
    Tavola [M1] = 0;                  // libera la casella

    if (*MaxVale < Beta)
    { Tavola [M2] = Who;              // occupa la seconda casella
      Valuta4vuote (M1, M3, M4, M5, Ohw, -Beta, -(*MaxVale), &Vale);
      if (-Vale > *MaxVale) *MaxVale = -Vale;
      Tavola [M2] = 0;

      if (*MaxVale < Beta)
      { Tavola [M3] = Who; // occupa la terza casella
        Valuta4vuote (M1, M2, M4, M5, Ohw, -Beta, -(*MaxVale), &Vale);
        if (-Vale > *MaxVale) *MaxVale = -Vale;
        Tavola [M3] = 0;

        if (*MaxVale < Beta)
        { Tavola [M4] = Who;                // occupa la quarta casella
          Valuta4vuote (M1, M2, M3, M5, Ohw, -Beta, -(*MaxVale), &Vale);
          if (-Vale > *MaxVale) *MaxVale = -Vale;
          Tavola [M4] = 0;

          if (*MaxVale < Beta)
          { Tavola [M5] = Who;              // occupa la quinta casella
            Valuta4vuote (M1, M2, M3, M4, Ohw, -Beta, -(*MaxVale), &Vale);
            if (-Vale > *MaxVale) *MaxVale = -Vale;
            Tavola [M5] = 0;
          }
        }
      }
    }
  }
}

/*===========================================================================
Funzione per la valutazione della mossa migliore a QUATTRO mosse dalla fine
Utilizza la variabile globale int Tavola[24]
--------------------------------------------------------------------------*/
void Valuta4vuote
( int M1,        // mosse possibili (indici su caselle vuote)
  int M2,
  int M3,
  int M4,
  int Who,       // giocatore che deve muovere: 1 o 2
  int Alfa,      // valori di taglio per l'Alpha-Beta pruning
  int Beta,
  int *MaxVale   // valore della scacchiera vista da Who:
                 // -1 sconfitta, 0 pareggio, +1 vittoria.
)
{ int Vale,      // valore della contromossa (vista da 3^Who)
      Ohw;       // avversario Ohw = 3^Who

  // Dapprima cerca, tra tutte le mosse possibili, quelle vincenti
  if ((*Vince[M1])(Who) || (*Vince[M2])(Who) ||
      (*Vince[M3])(Who) || (*Vince[M4])(Who)   ) *MaxVale = +1;

  // Senza una vincente, riprova ogni mossa con le contromosse
  else
  { *MaxVale = Alfa;

    Tavola [M1] = Who; // occupa la prima casella
    Valuta3vuote (M2, M3, M4, Ohw=Who^3, -Beta, -(*MaxVale), &Vale);
    if (-Vale > *MaxVale) *MaxVale = -Vale;
    Tavola [M1] = 0; // libera la casella

    if (*MaxVale < Beta)
    { Tavola [M2] = Who; // occupa la seconda casella
      Valuta3vuote (M1, M3, M4, Ohw, -Beta, -(*MaxVale), &Vale);
      if (-Vale > *MaxVale) *MaxVale = -Vale;
      Tavola [M2] = 0;

      if (*MaxVale < Beta)
      { Tavola [M3] = Who; // occupa la terza casella
        Valuta3vuote (M1, M2, M4, Ohw, -Beta, -(*MaxVale), &Vale);
        if (-Vale > *MaxVale) *MaxVale = -Vale;
        Tavola [M3] = 0;

        if (*MaxVale < Beta)
        { Tavola [M4] = Who; // occupa la quarta casella
          Valuta3vuote (M1, M2, M3, Ohw, -Beta, -(*MaxVale), &Vale);
          if (-Vale > *MaxVale) *MaxVale = -Vale;
          Tavola [M4] = 0;
        }
      }
    }
  }
}

/*===========================================================================
Funzione per la valutazione della mossa migliore a TRE mosse dalla fine
Utilizza la variabile globale int Tavola[24]
--------------------------------------------------------------------------*/
void Valuta3vuote
( int M1,            // mosse possibili (indici su caselle vuote)
  int M2,
  int M3,
  int Who,           // giocatore che deve muovere: 1 o 2
  int Alfa,          // valori di taglio per l'Alpha-Beta pruning
  int Beta,
  int *MaxVale       // valore della scacchiera vista da Who:
                     // -1 sconfitta, 0 pareggio, +1 vittoria.
)
{ int Ohw;           // avversario Ohw = 3^Who

  // Dapprima cerca, tra tutte le mosse possibili, quelle vincenti
  if ( (*Vince[M1])(Who) || (*Vince[M2])(Who) || (*Vince[M3])(Who) )
    *MaxVale = +1;
  else // Se NON c'è una vincente, riprova ogni mossa con le contromosse
  { Ohw = Who^3;
    *MaxVale = Alfa; // *MaxVale = -1 o 0

    // Se l'avversario ha una contromossa vincente, la mossa di Who è
    // perdente e quindi non verrà presa in considerazione poiché‚ non
    // può certo migliorare il valore di *MaxVale.
    // Se Ohw non ha la mossa vincente, non l'avrà dopo la mossa di Who
    if ( !(*Vince[M2])(Ohw) && !(*Vince[M3])(Ohw) )
    { Tavola [M1] = Who;
      // Occupa la prima casella; la scacchiera cambia per Who che potrebbe
      // ora avere una mossa vincente, se Ohw non la blocca: la scacchiera
      // è quindi vincente solo se si sono formate due mosse vincenti.
      *MaxVale = (*Vince[M2])(Who) && (*Vince[M3])(Who);
      // Se M2 and M3 sono vincenti, M1 è vincente per Who, altrimenti pari
      Tavola [M1] = 0; // libera la casella
    }
    // Se non è stato superato il valore di taglio Beta, Who riprova M2 e M3
    if (*MaxVale < Beta)
    { if ( !(*Vince[M1])(Ohw) && !(*Vince[M3])(Ohw) )
      { Tavola [M2] = Who;
        *MaxVale = (*Vince[M1])(Who) && (*Vince[M3])(Who);
        Tavola [M2] = 0;
      }
      if (*MaxVale < Beta)
      { if ( !(*Vince[M1])(Ohw) && !(*Vince[M2])(Ohw) )
        { Tavola [M3] = Who;
          *MaxVale = (*Vince[M1])(Who) && (*Vince[M2])(Who);
          Tavola [M3] = 0;
        }
      }
    }
  }
}

/*===========================================================================
  Vettore di 24 funzioni per verificare la presenza di un Tris sul campo
  di gioco, solo sui due tratti adiacenti all'ultima mossa eseguita, che
  corrisponde al numero inserito nel nome stesso della subroutine.
  Gli indirizzi delle 24 Sub sono inseriti nel vettore
       int (*Vince[])( void ) = {......}
  Utilizza la variabile globale int Tavola[24]

  Input  = Who (1 o 2) chi dovrebbe fare la mossa nella casella
  Output = Who (1 o 2) se esiste un Tris. 0 se NON esiste un Tris.
--------------------------------------------------------------------------*/
int Win00 (int Who)
{ return ( Tavola[ 1] & Who & Tavola[ 2] | Tavola[ 9] & Who & Tavola[21] );
}
int Win01 (int Who)
{ return ( Tavola[ 0] & Who & Tavola[ 2] | Tavola[ 4] & Who & Tavola[ 7] );
}
int Win02 (int Who)
{ return ( Tavola[ 0] & Who & Tavola[ 1] | Tavola[14] & Who & Tavola[23] );
}
int Win03 (int Who)
{ return ( Tavola[ 4] & Who & Tavola[ 5] | Tavola[10] & Who & Tavola[18] );
}
int Win04 (int Who)
{ return ( Tavola[ 3] & Who & Tavola[ 5] | Tavola[ 1] & Who & Tavola[ 7] );
}
int Win05 (int Who)
{ return ( Tavola[ 3] & Who & Tavola[ 4] | Tavola[13] & Who & Tavola[20] );
}
int Win06 (int Who)
{ return ( Tavola[ 7] & Who & Tavola[ 8] | Tavola[11] & Who & Tavola[15] );
}
int Win07 (int Who)
{ return ( Tavola[ 6] & Who & Tavola[ 8] | Tavola[ 1] & Who & Tavola[ 4] );
}
int Win08 (int Who)
{ return ( Tavola[ 6] & Who & Tavola[ 7] | Tavola[12] & Who & Tavola[17] );
}
int Win09 (int Who)
{ return ( Tavola[10] & Who & Tavola[11] | Tavola[ 0] & Who & Tavola[21] );
}
int Win10 (int Who)
{ return ( Tavola[ 9] & Who & Tavola[11] | Tavola[ 3] & Who & Tavola[18] );
}
int Win11 (int Who)
{ return ( Tavola[ 9] & Who & Tavola[10] | Tavola[ 6] & Who & Tavola[15] );
}
int Win12 (int Who)
{ return ( Tavola[13] & Who & Tavola[14] | Tavola[ 8] & Who & Tavola[17] );
}
int Win13 (int Who)
{ return ( Tavola[12] & Who & Tavola[14] | Tavola[ 5] & Who & Tavola[20] );
}
int Win14 (int Who)
{ return ( Tavola[12] & Who & Tavola[13] | Tavola[ 2] & Who & Tavola[23] );
}
int Win15 (int Who)
{ return ( Tavola[16] & Who & Tavola[17] | Tavola[ 6] & Who & Tavola[11] );
}
int Win16 (int Who)
{ return ( Tavola[15] & Who & Tavola[17] | Tavola[19] & Who & Tavola[22] );
}
int Win17 (int Who)
{ return ( Tavola[15] & Who & Tavola[16] | Tavola[ 8] & Who & Tavola[12] );
}
int Win18 (int Who)
{ return ( Tavola[19] & Who & Tavola[20] | Tavola[ 3] & Who & Tavola[10] );
}
int Win19 (int Who)
{ return ( Tavola[18] & Who & Tavola[20] | Tavola[16] & Who & Tavola[22] );
}
int Win20 (int Who)
{ return ( Tavola[18] & Who & Tavola[19] | Tavola[ 5] & Who & Tavola[13] );
}
int Win21 (int Who)
{ return ( Tavola[22] & Who & Tavola[23] | Tavola[ 0] & Who & Tavola[ 9] );
}
int Win22 (int Who)
{ return ( Tavola[21] & Who & Tavola[23] | Tavola[16] & Who & Tavola[19] );
}
int Win23 (int Who)
{ return ( Tavola[21] & Who & Tavola[22] | Tavola[ 2] & Who & Tavola[14] );
}

/*===========================================================================
Vettore di 24 funzioni per valutazione euristica della mossa in ogni casella:
Utilizza le variabili globali Tavola[24] e PuntiMossa[]

Input  = Who (1 o 2) chi dovrebbe fare la mossa nella casella
Output = Valore della mossa in quellla casella (supposta vuota)
---------------------------------------------------------------------------*/
int Casa00 (int Who)
{ return ( PuntiMossa [(Who<<4)+(Tavola[ 1]<<2)+Tavola[ 2] ] +
           PuntiMossa [(Who<<4)+(Tavola[ 9]<<2)+Tavola[21] ] );
}
int Casa01 (int Who)
{ return ( PuntiMossa [(Who<<4)+(Tavola[ 0]<<2)+Tavola[ 2] ] +
           PuntiMossa [(Who<<4)+(Tavola[ 4]<<2)+Tavola[ 7] ] );
}
int Casa02(int Who)
{ return ( PuntiMossa [(Who<<4)+(Tavola[ 0]<<2)+Tavola[ 1] ] +
           PuntiMossa [(Who<<4)+(Tavola[14]<<2)+Tavola[23] ] );
}
int Casa03 (int Who)
{ return ( PuntiMossa [(Who<<4)+(Tavola[ 4]<<2)+Tavola[ 5] ] +
           PuntiMossa [(Who<<4)+(Tavola[10]<<2)+Tavola[18] ] );
}
int Casa04 (int Who)
{ return ( PuntiMossa [(Who<<4)+(Tavola[ 3]<<2)+Tavola[ 5] ] +
           PuntiMossa [(Who<<4)+(Tavola[ 1]<<2)+Tavola[ 7] ] );
}
int Casa05 (int Who)
{ return ( PuntiMossa [(Who<<4)+(Tavola[ 3]<<2)+Tavola[ 4] ] +
           PuntiMossa [(Who<<4)+(Tavola[13]<<2)+Tavola[20] ] );
}
int Casa06 (int Who)
{ return ( PuntiMossa [(Who<<4)+(Tavola[ 7]<<2)+Tavola[ 8] ] +
           PuntiMossa [(Who<<4)+(Tavola[11]<<2)+Tavola[15] ] );
}
int Casa07 (int Who)
{ return ( PuntiMossa [(Who<<4)+(Tavola[ 6]<<2)+Tavola[ 8] ] +
           PuntiMossa [(Who<<4)+(Tavola[ 1]<<2)+Tavola[ 4] ] );
}
int Casa08 (int Who)
{ return ( PuntiMossa [(Who<<4)+(Tavola[ 6]<<2)+Tavola[ 7] ] +
           PuntiMossa [(Who<<4)+(Tavola[12]<<2)+Tavola[17] ] );
}
int Casa09 (int Who)
{ return ( PuntiMossa [(Who<<4)+(Tavola[10]<<2)+Tavola[11] ] +
           PuntiMossa [(Who<<4)+(Tavola[ 0]<<2)+Tavola[21] ] );
}
int Casa10 (int Who)
{ return ( PuntiMossa [(Who<<4)+(Tavola[ 9]<<2)+Tavola[11] ] +
           PuntiMossa [(Who<<4)+(Tavola[ 3]<<2)+Tavola[18] ] );
}
int Casa11 (int Who)
{ return ( PuntiMossa [(Who<<4)+(Tavola[ 9]<<2)+Tavola[10] ] +
           PuntiMossa [(Who<<4)+(Tavola[ 6]<<2)+Tavola[15] ] );
}
int Casa12 (int Who)
{ return ( PuntiMossa [(Who<<4)+(Tavola[13]<<2)+Tavola[14] ] +
           PuntiMossa [(Who<<4)+(Tavola[ 8]<<2)+Tavola[17] ] );
}
int Casa13 (int Who)
{ return ( PuntiMossa [(Who<<4)+(Tavola[12]<<2)+Tavola[14] ] +
           PuntiMossa [(Who<<4)+(Tavola[ 5]<<2)+Tavola[20] ] );
}
int Casa14 (int Who)
{ return ( PuntiMossa [(Who<<4)+(Tavola[12]<<2)+Tavola[13] ] +
           PuntiMossa [(Who<<4)+(Tavola[ 2]<<2)+Tavola[23] ] );
}
int Casa15 (int Who)
{ return ( PuntiMossa [(Who<<4)+(Tavola[16]<<2)+Tavola[17] ] +
           PuntiMossa [(Who<<4)+(Tavola[ 6]<<2)+Tavola[11] ] );
}
int Casa16 (int Who)
{ return ( PuntiMossa [(Who<<4)+(Tavola[15]<<2)+Tavola[17] ] +
           PuntiMossa [(Who<<4)+(Tavola[19]<<2)+Tavola[22] ] );
}
int Casa17 (int Who)
{ return ( PuntiMossa [(Who<<4)+(Tavola[15]<<2)+Tavola[16] ] +
           PuntiMossa [(Who<<4)+(Tavola[ 8]<<2)+Tavola[12] ] );
}
int Casa18 (int Who)
{ return ( PuntiMossa [(Who<<4)+(Tavola[19]<<2)+Tavola[20] ] +
           PuntiMossa [(Who<<4)+(Tavola[ 3]<<2)+Tavola[10] ] );
}
int Casa19 (int Who)
{ return ( PuntiMossa [(Who<<4)+(Tavola[18]<<2)+Tavola[20] ] +
           PuntiMossa [(Who<<4)+(Tavola[16]<<2)+Tavola[22] ] );
}
int Casa20 (int Who)
{ return ( PuntiMossa [(Who<<4)+(Tavola[18]<<2)+Tavola[19] ] +
           PuntiMossa [(Who<<4)+(Tavola[ 5]<<2)+Tavola[13] ] );
}
int Casa21 (int Who)
{ return ( PuntiMossa [(Who<<4)+(Tavola[22]<<2)+Tavola[23] ] +
           PuntiMossa [(Who<<4)+(Tavola[ 0]<<2)+Tavola[ 9] ] );
}
int Casa22 (int Who)
{ return ( PuntiMossa [(Who<<4)+(Tavola[21]<<2)+Tavola[23] ] +
           PuntiMossa [(Who<<4)+(Tavola[16]<<2)+Tavola[19] ] );
}
int Casa23 (int Who)
{ return ( PuntiMossa [(Who<<4)+(Tavola[21]<<2)+Tavola[22] ] +
           PuntiMossa [(Who<<4)+(Tavola[ 2]<<2)+Tavola[14] ] );
}

/*===========================================================================
  Lettura del Timer di sistema all'indirizzo RAM 0046Ch, aggiornato dal PIT,
  tramite l'IRQ0, 18.2 volte al secondo
--------------------------------------------------------------------------*/
int LeggiClock (void)
{ asm { push Es
        xor Ax, Ax
        mov Es, Ax
        mov Ax, Es:[0x046c]
        pop Es
      }
  return _AX;
}

/*===========================================================================
  Visualizza le Pedine sul campo di gioco
--------------------------------------------------------------------------*/
void Pedine (void)
{ int i;

  for (i=0; i<24; i++)
    if (Tavola[i])
    { switch (i)
      { case 0: gotoxy (44, 6); break; // A B C
        case 1: gotoxy (59, 6); break;
        case 2: gotoxy (74, 6); break;
        case 3: gotoxy (49, 8); break; // D E F
        case 4: gotoxy (59, 8); break;
        case 5: gotoxy (69, 8); break;
        case 6: gotoxy (54, 10); break; // G H I
        case 7: gotoxy (59, 10); break;
        case 8: gotoxy (64, 10); break;
        case 9: gotoxy (44, 12); break; // J K L M N O
        case 10: gotoxy (49, 12); break;
        case 11: gotoxy (54, 12); break;
        case 12: gotoxy (64, 12); break;
        case 13: gotoxy (69, 12); break;
        case 14: gotoxy (74, 12); break;
        case 15: gotoxy (54, 14); break; // P Q R
        case 16: gotoxy (59, 14); break;
        case 17: gotoxy (64, 14); break;
        case 18: gotoxy (49, 16); break; // S T U
        case 19: gotoxy (59, 16); break;
        case 20: gotoxy (69, 16); break;
        case 21: gotoxy (44, 18); break; // V W X
        case 22: gotoxy (59, 18); break;
        case 23: gotoxy (74, 18);
      }
      textcolor(13+Tavola[i]); cprintf ("%c", Tavola[i]+48 );
    }
}

/*===========================================================================
  Maschera di gioco
--------------------------------------------------------------------------*/
void Maschera
( int Gioc  // -1 maschera per la configurazione iniziale
            //  0 maschera gioco Umano - Umano
            //  1 maschera gioco Computer - Umano
            //  2 maschera gioco Umano - Computer
)
{ int i;

  clrscr();
  textbackground(4); textcolor(0);
  gotoxy( 2, 1); for(i=2;i<=79;cprintf(" "),i++);
  gotoxy(35, 1); cprintf("F I L E T T O");
  gotoxy ( 2,25); for(i=2;i<=79;cprintf(" "),i++);
  gotoxy(58,25); cprintf("di Luigi Lamberti");

  textbackground(0); textcolor(2);
  gotoxy(44, 6); cprintf("A--------------B--------------C");
  gotoxy(44, 7); cprintf("|              |              |");
  gotoxy(44, 8); cprintf("|    D---------E---------F    |");
  gotoxy(44, 9); cprintf("|    |         |         |    |");
  gotoxy(44,10); cprintf("|    |    G----H----I    |    |");
  gotoxy(44,11); cprintf("|    |    |         |    |    |");
  gotoxy(44,12); cprintf("J----K----L         M----N----O");
  gotoxy(44,13); cprintf("|    |    |         |    |    |");
  gotoxy(44,14); cprintf("|    |    P----Q----R    |    |");
  gotoxy(44,15); cprintf("|    |         |         |    |");
  gotoxy(44,16); cprintf("|    S---------T---------U    |");
  gotoxy(44,17); cprintf("|              |              |");
  gotoxy(44,18); cprintf("V--------------W--------------X");

  if (Gioc == -1)
  { textcolor(11);
    gotoxy( 2, 3); cprintf("F1       : Umano - Umano");
    gotoxy( 2, 5); cprintf("F2       : Computer - Umano");
    gotoxy( 2, 7); cprintf("F3       : Umano - Computer");
    gotoxy( 2,13); cprintf("ESC      : interrompe gioco");
    textcolor(1);
    gotoxy( 2, 9); cprintf("F5       : help mossa migliore");
    gotoxy( 2,11); cprintf("ABCD..WX : inserisci mossa");
  }
  else
  { textcolor(1);
    gotoxy( 2, 3); cprintf("F1       : Umano - Umano");
    gotoxy( 2, 5); cprintf("F2       : Computer - Umano");
    gotoxy( 2, 7); cprintf("F3       : Umano - Computer"); 
    textcolor(11);
    gotoxy( 2, 9); cprintf("F5       : help mossa migliore");
    gotoxy( 2,11); cprintf("ABCD..WX : inserisci mossa");
    gotoxy( 2,13); cprintf("ESC      : interrompe gioco");
    switch (Gioc)
    { case 0: gotoxy(13, 3); cprintf("Umano - Umano"); break;
      case 1: gotoxy(13, 5); cprintf("Computer - Umano"); break;
      case 2: gotoxy(13, 7); cprintf("Umano - Computer");
    }
  }
}

/*============================================================= InKey ======
Lettura di un carattere da tastiera: attende che venga battuto;
OUT: Il codice Ascii oppure, il codice del tasto speciale:
Return:13  Esc:27  F1:315  F2:316  F3:317  F5:319  ecc... -------------------------------------------------------------------------*/
int InKey (void)
{ int Tast; // codice numerico del tasto premuto;

  Tast = getch();
  if (Tast == 0) Tast = getch() + 256;

  return ( Tast );
}