| 
 #include <stdio.h> 
#include <conio.h>
 
int  CercaCertezze (int Tav[][9][10], int *Nvuote           ); 
int  CercaSudoku   (int Tav[][9][10], int Nvuote            ); 
int  Congruenza    (int Tav[][9][10]                        ); 
void CopiaTavola   (int Source[][9][10], int Destin[][9][10]); 
void InitTavola    (int Tav[][9][10], int *Nvuote           ); 
void LeggiTavola   (int Tav[][9][10], int *Nvuote           ); 
void ScriviCella   (int Tav[][9][10], int r, int c, int n, int *Nvuote); 
void StampaTavola  (int Tav[][9][10], int Nvuote            ); 
 
/*============================================================================= 
             S U - D O K U 
            ^^^^^^^^^^^^^^^  
  Un Sudoku è una griglia quadrata di 81 celle: 9 righe orizzontali per 9  
  colonne verticali; inoltre, la griglia è divisa in 9 riquadri 3x3 (gruppi,  
  col bordo più spesso) di 9 celle ciascuno.  
 
  Ciascuna riga orizzontale, colonna verticale e riquadro di 3x3 celle  
  contiene una sola volta tutti i numeri da 1 a 9; pertanto in nessuna riga,  
  colonna e riquadro può esserci un numero ripetuto.  
 
  TAVOLA DI GIOCO 
  ^^^^^^^^^^^^^^^     0   1   2  
3   4   5   6   7   8  
                 
*===*===*===*===*===*===*===*===*===* 
               
0  H   |   |   H   |   |  
H   |   |   H 
                 
*---+---+---*---+---+---*---+---+---* 
               
1  H   |     |     H     |     |     H     |     |  
H 
                 
*---+---+---*---+---+---*---+---+---* 
               
2 H   |     |     H     |     |     H     |     |  
H 
                 
*===*===*===*===*===*===*===*===*===* 
               
3  H   |     |     H     |     |     H     |     |  
H 
                 
*---+---+---*---+---+---*---+---+---*  
               
4  H   |     |     H     |     |     H     |     |  
H 
                 
*---+---+---*---+---+---*---+---+---*  
               
5  H   |     |     H     |     |     H     |     |  
H 
                 
*===*===*===*===*===*===*===*===*===* 
               
6 H   |     |     H     |     |     H     |     |  
H 
                 
*---+---+---*---+---+---*---+---+---*  
               
7  H   |     |     H     |     |     H     |     |  
H 
                 
*---+---+---*---+---+---*---+---+---*  
               
8  H   |     |     H     |     |     H     |     |  
H 
                 
*===*===*===*===*===*===*===*===*===* 
 
  CELLA 
  ^^^^^  Ogni Cella della Tavola di gioco è un array di 10 caselle 
      *---+---+---+---+---+---+---+---+---+---+ 
      |   |   |   |  
|   |   |   |   |   |  
|  
      *---+---+---+---+---+---+---+---+---+---+ 
        0   1   2  
3   4   5   6   7   8  
9 
  La casella 0 indica se la cella è libera (0) o occupata (1..9). 
  Le nove caselle successive indicano ciascuna la possibilità di inserire  
  nella cella il valore corrispondente (Flag 1=inserimento possibile). 
 
  GRUPPI 
  ^^^^^^ 
  Chiameremo Gruppi i 9 Riquadri 3x3 interni.  
  Detta (i,j) una cella della Tavola, le coordinate della cella in alto a  
  sinistra del suo gruppo di appartenenza saranno: 
         ig = (i / 3) * 3 = i - i % 3 
         jg = (j / 3) * 3 = j - j % 3 
  Il gruppo sarà composto dalle nove celle (y,x) con  
         ig <= y <= ig+2   e   jg <= x <= jg+2  
----------------------------------------------------------------- 9.10.2005 -*/  
void main (void) 
{ 
  int  Tav  [9][9][10],  // 1° riga, 2° colonna, 3° campi della cella 
      Nvuote;        
// Numero di caselle vuote nella tavola  
 
  InitTavola    (Tav, &Nvuote); 
  LeggiTavola   (Tav, &Nvuote); 
  StampaTavola  (Tav, Nvuote); 
  printf("\nbatti un tasto per iniziare l'analisi ...\n"); _getch(); 
 
  // Dapprima cerca di risolvere il gioco con posizioni certe 
  while ( CercaCertezze (Tav, &Nvuote) );  
  StampaTavola  (Tav, Nvuote); 
 
  // In seconda battuta esegue una ricerca combinatoria ricorsiva 
  if ( ! Nvuote ) 
    printf ("\nSoluzione trovata.\n"); 
  else  
  { printf("\nbatti un tasto per la ricerca combinatoria ...\n");  
    _getch(); 
    if ( CercaSudoku(Tav,Nvuote) )  
    { StampaTavola (Tav, 0); 
      printf ("\nSoluzione trovata.\n"); 
    }  
    else 
      printf("\nNON esistono soluzioni\n");  
  }
 
  _getch(); 
} 
/*============================================================================= 
 Cerca di completare la tavola da gioco, ALMENO con una cella vuota, provando  
 ad inserire un valore in una cella vuota, ove il valore sia possibile. 
 Se non sorgono incongruenze  
   se esitono altre caselle vuote, chiama ricorsivamente se stessa  
   se sono finite le caselle vuote, trovata una soluzione. 
 Se non è stata trovata una soluzione, prova con un altro valore nella stessa  
 cella. Al termine dei valori possibili, senza successo, restituisce 0:  
 ( è inutile ricominciare con un'altra cella ! ) 
 
 OUTPUT: 1 soluzione trovata e copiata sulla Tavola da gioco 
         0 nessuna soluzione 
-----------------------------------------------------------------------------*/ 
int CercaSudoku 
( int  Tav[][9][10],  
  int  Nvuote           // Numero di caselle vuote nella tavola  
) 
{ int  r, c,            // riga e colonna della cella da occupare  
      N,              
// valore da inserire  
      Tav2 [9][9][10],  // Tavola di appoggio  
      Nv2,            
// numero delle caselle vuote da riempire  
      i, j, 
      Trovato;        
// 0 nessuna soluzione possibile;  
                      
// 1 soluzione trovata e copiata su Tav  
 
  for (i=9; i; )       // cerca una cella vuota, che CERTAMENTE ESISTE 
    for (i--, j=9; j; )  
      if ( ! Tav[i][--j][0] ) r=i, c=j; 
 
  for (N=9, Trovato=0; N && !Trovato; N--) 
  if ( Tav[r][c][N] )  // se è possibile inserire il valore N  
  {  
    CopiaTavola (Tav, Tav2); 
    Nv2 = Nvuote; 
    ScriviCella(Tav2, r, c, N, &Nv2);  
    while ( CercaCertezze(Tav2, &Nv2) ); 
 
    if ( Congruenza(Tav2) ) 
    { Trovato = Nv2 ? CercaSudoku (Tav2, Nv2) : 1; 
      if (Trovato) CopiaTavola (Tav2, Tav);  //copia la soluzione 
    }  
  } 
  return Trovato; 
} 
/*============================================================================= 
 Cerca i valori CERTI da inserire sulla tavola di gioco, esaminando le Flag  
 "possibilità" delle celle:  
 -) se una cella vuota possiede una sola flag==1, inseriamo quel valore; 
 -) per ogni riga, colonna e gruppo, se un valore è disponibile in una sola  
 posizione vuota, inseriamo il valore. 
 
 OUTPUT: quantità dei valori inseriti 
------------------------------------------------------------------------------*/ 
int CercaCertezze 
( int  Tav[][9][10], 
  int  *Nvuote  
) 
{ int  i, j, k,  
      r, c,       // riga e colonna della cella da occupare  
      rg, cg,     // angolo in alto a sinistra del gruppo di appartenenza  
      N,         
// valore da inserire  
      Flag,       // numero di Flag alte per ciascuna cella.  
      Tot;       
// Totale dei numeri inseriti nella sessione  
 
  Tot = 0; 
  for (i=0; i<9; i++)        // ricerca ed analisi delle celle vuote  
    for (j=0; j<9; j++)  
      if (! Tav [i][j][0])                      // se Cella vuota 
      {	for (Flag=0, k=9; k; k--)  
          if (Tav[i][j][k]) Flag++, N=k;       // conta Flag possibilità 
        if (Flag == 1)  
          ScriviCella(Tav, i, j, N, Nvuote), Tot ++;   // se unico possibile 
      } 
  for (N=9; N; N--)      // Ricerca per ogni valore da inserire 
  {  
    for (i=0; i<9; i++)     // esamina ciascuna riga della tavola  
    { for (Flag= j= 0; j<9; j++)  
        if (Tav[i][j][N]) Flag++, c=j;          // conta Flag possibilità 
      if (Flag==1 && !Tav[i][c][0])   
// se unico possibile e cella vuota 
        ScriviCella(Tav, i, c, N, Nvuote), Tot ++;  
    } 
    for (j=0; j<9; j++)    // esamina ciascuna colonna della tavola  
    { for (Flag= i= 0; i<9; i++)  
        if (Tav[i][j][N]) Flag++, r=i;   // conta Flag
possibilità 
      if (Flag==1 && !Tav[r][j][0])   
// se unico possibile e cella vuota 
        ScriviCella(Tav, r, j, N, Nvuote), Tot ++;  
    } 
    for (rg=0; rg<9; rg+=3)        // esamina ciascun riquadro della tavola  
      for (cg=0; cg<9; cg+=3)  
      { for (Flag= i= 0; i<3; i++)  
          for (j=0; j<3; j++)  
            if (Tav[rg+i][cg+j][N]) Flag++, r=rg+i, c=cg+j;
  // conta Flag 
        if (Flag==1 && !Tav[r][c][0]) 
// se unico possibile e cella vuota 
          ScriviCella(Tav, r, c, N, Nvuote), Tot ++;  
      } 
  } 
  return Tot; 
} 
/*============================================================================= 
 Valuta la congruenza di uno schema di gioco: per ogni riga, ogni colonna e 
 ogni riquadro ciascun valore da 1 a 9 deve essere o già presente o possibile 
 in almeno una cella.  
 Poiché i valori inseriti conservano la flag di possibilità, è sufficiente 
 esaminare le caselle delle flag possibilità. 
 
 OUTPUT: 0 la tavola è inconguente e NON è possibile trovare una soluzione 
         1 il gioco può proseguire alla ricerca di soluzioni. 
-----------------------------------------------------------------------------*/ 
int Congruenza 
( int  Tav[][9][10] 
) 
{ int  i, j, 
      N,        
// valore da inserire  
      Flag,     
// numero di flag == 1  
      rg, cg,    // angolo in alto a sinistra del gruppo di appartenenza  
      Congrua;   // 0 = tavola inconguente 
 
  Congrua = 1; 
                              
// ogni valore da inserire deve essere o già 
  for (N=9; N && Congrua; N--)    // presente o possibile in almeno una cella 
  { 
    for (i=0; i<9; i++)       
// esamina ciascuna riga della tavola  
    { for (Flag= j= 0; j<9; Flag += Tav[i][j++][N]);  // conta le flag alte 
      if (! Flag) Congrua = 0; 
    } 
    for (j=0; j<9 && Congrua; j++)  // esamina ciascuna colonna della tavola  
    { for (Flag= i= 0; i<9; Flag += Tav[i++][j][N]); // conta le flag alte 
      if (! Flag) Congrua = 0; 
    } 
    for (rg=0; rg<9 && Congrua; rg+=3)     // esamina ciascun riquadro  
      for (cg=0; cg<9 && Congrua; cg+=3) 
      { for (Flag= i= 0; i<3; i++) 
          for (j=0; j<3; Flag += Tav[rg+i][cg+j][N], j++); 
        if (! Flag) Congrua = 0; 
      } 
  } 
  return Congrua; 
} 
/*============================================================================= 
 Duplica una tavola da gioco. 
-----------------------------------------------------------------------------*/ 
void CopiaTavola 
( int Source[][9][10],  
  int Destin[][9][10]   
) 
{ int i, j, k;  
 
  for (i=9; i; ) 
    for (i--, j=9; j; )  
      for (j--, k=10; k; k--, Destin[i][j][k] = Source[i][j][k]); 
} 
/*============================================================================= 
 Inizializza la Tavola di gioco del Sudoku, svuotando le celle e  
 rendendo potenzialmente inseribili tutti i valori da 1 a 9. 
-----------------------------------------------------------------------------*/ 
void InitTavola 
( int  Tav[][9][10], 
  int  *Nvuote        
// Numero di caselle vuote nella tavola  
) 
{ int  i, j, k; 
  
  for (*Nvuote = 81, i=0; i<9; i++)  
    for (j=0; j<9; j++)  
    { Tav [i][j][0] = 0; 
      for (k=9; k; Tav [i][j][k--] = 1 ); 
    }  
} 
/*============================================================================= 
 Carica un gioco da risolvere (sodoku parziale) dal file  Sudoku.txt 
 Saranno esaminati solo i primi 9 records del file e, di questi, solo i  
 primi 9 caratteri: il resto del file può essere occupato da commenti. 
 Tutti i caratteri diversi da 1,2,3,4,5,6,7,8 e 9, sono considerati Spazi. 
 ...7..4.. 
 .3..9..2. 
 4....5... 
 ..8.....5 
 .9..3..7. 
 6.....3.. 
 ...4....1 
 .7..2..9. 
 ..5..8... 
-----------------------------------------------------------------------------*/ 
void LeggiTavola 
( int  Tav[][9][10],  
  int  *Nvuote 
) 
{ int  i, j; 
  FILE *Pf; 
  char Buf[200]; 
 
  Pf = fopen ("Sudoku.txt", "r"); 
  if (Pf) 
  { for (*Nvuote=81, i=0; i<9; i++) 
    { fscanf(Pf,"%s",Buf); 
      for (j=0; j<9; j++)  
        if (Buf[j]>=49 && Buf[j]<=57)  
          ScriviCella (Tav, i, j, Buf[j]-48, Nvuote); 
    }  
    fclose (Pf); 
  }  
} 
/*============================================================================= 
 Inserisce un valore da 1 a 9 in una cella vuota. 
 Tutte le celle della stessa riga, stessa colonna e stesso gruppo (riquardo) 
 perdono la possibilità di ricevere quel valore. 
-----------------------------------------------------------------------------*/ 
void ScriviCella 
( int  Tav[][9][10],  // Tavola di gioco 
  int  r,            
// riga dell'inserimento 
  int  c,            
// colonna dell'inserimento 
  int  n,            
// numero da inserire: 1 <= n <= 9 
  int  *Nvuote       
// Numero di caselle vuote nella tavola  
) 
{ int  i, j, k, 
      rg, cg;       
// angolo in alto a sinistra del gruppo di appartenenza  
 
  (*Nvuote) --; 
  Tav [r][c][0] = n;                
// inserisce il numero 
  for (k=9; k; Tav [r][c][k--] = 0);   // ovviamente, esclude tutti gli altri 
 
  for (j=9; j; Tav [r][--j][n] = 0);   // elimina flag dalle celle della
riga 
  for (i=9; i; Tav [--i][c][n] = 0);   // elimina flag dalle celle della
colonna 
 
  rg = (r / 3) * 3;                 
// angolo in alto a sinistra del gruppo  
  cg = (c / 3) * 3; 
  for (i=0; i<3; i++)               
// elimina flag dalle celle del gruppo 
    for (j=0; j<3; j++)  
      Tav [rg+i][cg+j][n] = 0; 
 
  Tav [r][c][n] = 1;                
// conferma la flag sulla stessa cella  
} 
/*============================================================================= 
 Visualizza la matrice del campo di gioco. 
-----------------------------------------------------------------------------*/ 
void StampaTavola 
( int  Tav[][9][10],  
  int  Nvuote 
) 
{ int  i, j; 
 
  for (i=0; i<9; i++)  
  { if (i%3) printf ("\n       +---+---+---H---+---+---H---+---+---+\n       |"); 
    else     printf ("\n       *===========H===========H===========*\n       |"); 
    for (j=0; j<9; j++)  
    { if (Tav [i][j][0]) printf (" %d ",Tav [i][j][0]); 
      else              
printf ("   ");  
      if (j==2 || j==5)  printf ("H");  
      else              
printf ("|");  
    }  
  } 
  printf ("\n       *===========H===========H===========*  Vuote = %d\n", Nvuote); 
}
        |