Advertisement
Trollkemada

Untitled

May 11th, 2011
147
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 17.96 KB | None | 0 0
  1. /*
  2.  
  3. Autor: trollkemada (trollkemada@gmail.com)
  4.  
  5. Comenzado: 27/04/2011
  6. Terminado: 01/05/2011
  7.  
  8. Falta bastante por mejorar en eficiencia
  9. */
  10.  
  11. #include <iostream>
  12. #include <fstream>
  13. #include <string.h>
  14.  
  15. using namespace std;
  16.  
  17. struct sudoku
  18. {
  19.        int valor[9][9]; //Almacena el valor de esa casilla (cuando es definitivo)
  20.        bool pvalor[9][9][10]; //Almacena si cada posible valor de una casilla es realmente posible o no (si otra casilla lo impide)
  21.        //El pvalor[i][j][0] almacena si el valor es dado por el usuario
  22.        bool calculado[9][9]; //almacena si el valor ha sido calculado
  23. };
  24.  
  25. // Acciones basicas del struct sudoku
  26. void iniciarSudoku(sudoku &s);
  27. void escribir(sudoku s);
  28. void escribirFichero(sudoku s, int n, char nombre[]);
  29. void leer(sudoku &s);
  30. void leerFichero(sudoku &s,char nombre[]);
  31. bool igual(sudoku s,sudoku t);
  32. bool irresoluble(sudoku s);
  33. int soluciones(sudoku s);
  34. void debug(sudoku s);
  35.  
  36. // Acciones para resolver un sudoku.
  37. void actualizarEntradas(sudoku &s,int i,int j);
  38. void rellenarEliminacion(sudoku &s);
  39. void resolver(sudoku &s);
  40.  
  41. // Acciones para completar partes de un sudoku
  42. void completarTodo(sudoku &s);
  43. bool completarfila(sudoku &s, int fila, int valor);
  44. bool completarcolumna(sudoku &s,int columna,int valor);
  45. bool completarCuadrado(sudoku &s,int c, int valor);
  46.  
  47. // Acciones para encontrar recursivamente todas las solcuiones de un sudoku
  48. bool encontrarPosible(sudoku s,int &i, int &j, int &k);
  49. bool resolverVarios(sudoku &s, int &n);
  50.  
  51.  
  52.  
  53. int main()
  54. {
  55.     int n=0,sol;
  56.     char nombre[63];
  57.     sudoku s;
  58.     iniciarSudoku(s);
  59.     while (n!=1 && n!=2)
  60.     {
  61.           cout<<"1- Leer sudoku desde teclado"<<endl;
  62.           cout<<"2- Leer sudoku desde archivo"<<endl;
  63.           cout<<"Eliga opcion: ";
  64.           cin>>n;
  65.     }
  66.     if (n==1) leer(s);
  67.     else
  68.     {
  69.         cout<<endl<<"El fichero ha de tener el siguiente formato: ";
  70.         cout<<endl<<"- Ha de estar en texto plano (.txt)";
  71.         cout<<endl<<"- Ha de tener un 0 en las entradas desconocidas";
  72.         cout<<endl<<"- Ha de tener una cifra en las entradas conocidas";
  73.         cout<<endl<<"- Cada cifra debe estar separada de la anterior mediante un espacio o un salto de línea";
  74.         cout<<endl<<endl;
  75.         cout<<endl<<"Nombre del fichero (por defecto sudoku.txt) :";
  76.         fflush(stdin);
  77.         gets(nombre);
  78.         if (nombre[0]=='\0') strcpy(nombre,"sudoku.txt");
  79.         leerFichero(s,nombre);      
  80.     }
  81.     sol=soluciones(s);
  82.     if (sol==0)
  83.     {
  84.                cout<<endl<<"El sudoku no tiene solución";
  85.                cout<<endl<<"Pulse una tecla para finalizar el programa";
  86.                getchar();
  87.                return 0;
  88.     }
  89.     else if (sol==1)
  90.     {
  91.          cout<<endl<<"Sudoku leido: ";
  92.          escribir(s);
  93.          cout<<endl<<"Solucion: ";
  94.          resolver(s);
  95.          escribir(s);
  96.          cout<<endl<<"Pulse una tecla para finalizar el programa";
  97.          getchar();
  98.          return 0;
  99.     }
  100.     else
  101.     {
  102.           cout<<endl<<"Sudoku leido: ";
  103.           escribir(s);
  104.           cout<<endl<<endl<<"Calculando soluciones y escribiendolas a respuestas.txt ..."<<endl<<endl;
  105.           resolverVarios(s,n);
  106.           getchar();
  107.     }
  108. }
  109.  
  110.  
  111. /*Inicializa un sudoku dejando todas sus entradas como posibles valores, y ningun valor como dado por el usuario
  112.  y con valor 0 */
  113. void iniciarSudoku(sudoku &s)
  114. {
  115.      int i,j,k;
  116.      for(i=0;i<9;i++)
  117.      {
  118.                      for (j=0;j<9;j++)
  119.                      {
  120.                          s.valor[i][j]=0;
  121.                          s.pvalor[i][j][0]=false;
  122.                          for (k=1;k<10;k++) s.pvalor[i][j][k]=true;
  123.                          s.calculado[i][j]=false;
  124.                      }
  125.      }
  126. }
  127.  
  128. /* Escribe con formato un sudoku por pantalla  */
  129. void escribir(sudoku s)
  130. {
  131.      int i,j;
  132.      cout<<endl<<endl;
  133.      for (i=0;i<9;i++)
  134.      {
  135.          if(i%3==0) cout<<"-------------------------"<<endl;
  136.          for(j=0;j<9;j++)
  137.          {
  138.                          if(j%3==0) cout<<"| ";
  139.                          if(j==8) cout<<s.valor[i][j]<<" |";
  140.                          else cout<<s.valor[i][j]<<" ";
  141.                          
  142.          }
  143.          cout<<endl;
  144.      }
  145.      cout<<"-------------------------";
  146. }
  147.  
  148. /* Dado un sudoku con una unica solucion, un numero n y el nombre de un fichoer, escribe la soluciones enesima, s, en el fichero nombre */
  149. void escribirFichero(sudoku s, int n, char nombre[])
  150. {
  151.      ofstream f;
  152.      int i,j;
  153.      resolver(s);
  154.      f.open(nombre,ios::app);
  155.      if (!f)
  156.      {
  157.             cout<<"Imposible escribir la solucion en un fichero de texto.";
  158.             getchar();
  159.      }
  160.      else
  161.      {
  162.          
  163.          f<<endl<<"Solucion "<<n<<endl;
  164.          for (i=0;i<9;i++)
  165.          {
  166.              if(i%3==0) f<<"-------------------------"<<endl;
  167.              for(j=0;j<9;j++)
  168.              {
  169.                          if(j%3==0) f<<"| ";
  170.                          if(j==8) f<<s.valor[i][j]<<" |";
  171.                          else f<<s.valor[i][j]<<" ";
  172.                          
  173.              }
  174.          f<<endl;
  175.          }
  176.          f<<"-------------------------";
  177.          f.close();
  178.      }
  179. }
  180.  
  181. // Lee un sudoku entrada por entrada desde teclado.
  182. void leer(sudoku &s)
  183. {
  184.      int i,j,k,v;
  185.      cout<<endl<<"Leyendo sudoku:"<<endl;
  186.      cout<<"Fila (introduce 0 para terminar) (Introducir rango 1-9): ";
  187.      do { cin>>i;} while (i<1 || i>9);
  188.      i--; //El usuario mete entradas 1-9 pero se almacenan 0-8
  189.      while (i!=-1)
  190.      {
  191.            cout<<"Columna (1-9): ";
  192.            do { cin>>j;} while (j<1 || j>9);
  193.            j--;
  194.            cout<<"Valor: (1-9)";
  195.            do { cin>>v;} while (v<1 || v>9);
  196.            if (s.pvalor[i][j][0]) cout<<"Ya se ha introducido ese valor !!";
  197.            else if (!s.pvalor[i][j][v]) cout<<"Ese valor no puede ir en esa casilla !!";
  198.            else
  199.            {
  200.            for(k=1;k<10;k++) if (k!=v) s.pvalor[i][j][k]=false; //Marcamos todos los posibles valores de la casilla como invalidos
  201.            s.valor[i][j]=v; //Asignamos el valor introducido a la casilla que corresponde
  202.            s.pvalor[i][j][v]=true; // Su valor sí es un posible valor de la casilla
  203.            s.pvalor[i][j][0]=true; // Fijamos el valor
  204.            
  205.            // Actualizamos el sudoku, el resto de entradas del mismo cuadrado,fila y columna no podran tener ese numero
  206.            actualizarEntradas(s,i,j);
  207.            }
  208.            cout<<endl<<endl;
  209.            cout<<"Fila (introduce 0 para terminar): ";
  210.            cin>>i;
  211.            i--;          
  212.      }
  213. }          
  214.  
  215. //Lee un sudoku desde un fichero (que tenga el formato adecuado)
  216. void leerFichero(sudoku &s,char nombre[])
  217. {
  218.      int i,j,k;
  219.      char v;
  220.      fstream f;
  221.      f.open(nombre,ios::in);
  222.      if (!f) cout<<"Error al abrir el archivo";
  223.      else
  224.      {
  225.          f>>v;
  226.          // Analogo a leer desde teclado, el valor es int(v) - int('0')
  227.          for (i=0;i<9;i++) for (j=0;j<9;j++)
  228.          {
  229.            if (v!='0')
  230.            {
  231.               for(k=1;k<10;k++) if (k!=int(v)-int('0')) s.pvalor[i][j][k]=false;
  232.               s.pvalor[i][j][int(v)-int('0')]=true;
  233.               s.pvalor[i][j][0]=true;
  234.               s.valor[i][j]=int(v) - int('0');
  235.               actualizarEntradas(s,i,j);
  236.            }
  237.          f>>v;
  238.          }
  239.      }
  240.      f.close();  
  241. }  
  242.  
  243. /* Devuelve true si dos sudokus son iguales completamente, y false en otro caso */
  244. bool igual(sudoku s,sudoku t)
  245. {
  246.      int i,j,k;
  247.      for(i=0;i<9;i++) for(j=0;j<9;j++)
  248.      {
  249.          if (s.valor[i][j]!=t.valor[i][j]) return false;
  250.          for (k=0;k<10;k++) if (s.pvalor[i][j][k]!=t.pvalor[i][j][k]) return false;
  251.          if (s.calculado[i][j]!=t.calculado[i][j]) return false;
  252.      }
  253.      return true;
  254. }
  255.  
  256. /* Devuelve true si un sudoku no tiene soluciones y false en otro caso */
  257. bool irresoluble(sudoku s)
  258. {
  259.      int i,j,k,c;
  260.      resolver(s);
  261.      // Buscamos alguna casilla sin valores posibles
  262.      for (i=0;i<9;i++) for (j=0;j<9;j++)
  263.      {
  264.          c=0;
  265.          for(k=1;k<10;k++) if(s.pvalor[i][j][k]) c++;
  266.          if (c==0) return true;
  267.      }
  268.      return false;
  269.      
  270. }
  271. /* Devuelve el numero de soluciones de un sudoku:
  272.             - 0 si no tiene soluciones
  273.             - 1 si tiene una solucion
  274.             - 2 si tiene más de una soluciones
  275. */
  276. int soluciones(sudoku s)
  277. {
  278.     int i,j,k,c;
  279.     if (irresoluble(s)) return 0;
  280.     resolver(s);
  281.     // Buscamos alguna casilla que tenga más de un posible valor
  282.     for (i=0;i<9;i++) for (j=0;j<9;j++)
  283.     {
  284.         c=0;
  285.         for (k=1;k<10;k++) if (s.pvalor[i][j][k]) c++;
  286.         if (c>1)
  287.         {
  288.                  return 2;
  289.         }
  290.     }
  291.     return 1;
  292. }
  293.  
  294. /* Escribe con formato el sudoku, y luego, con más detalle, toda su estructura, entrada por entrada. */
  295. void debug(sudoku s)
  296. {
  297.      int i,j,k;
  298.      cout<<endl<<endl<<endl;
  299.      for(i=0;i<9;i++) for(j=0;j<9;j++)
  300.      {
  301.          cout<<"("<<i+1<<","<<j+1<<") --> ";
  302.          if (s.pvalor[i][j][0]) cout<<"[E] ";
  303.          else if (s.calculado[i][j]) cout<<"[C] ";
  304.          else cout<<"    ";
  305.          for(k=1;k<10;k++) if (s.pvalor[i][j][k]) cout<<"["<<k<<"] "; else cout<<"    ";
  306.          cout<<endl;
  307.      }
  308.      escribir(s);
  309. }
  310.  
  311.  
  312. void actualizarEntradas(sudoku &s,int i,int j)
  313. {
  314.      int fila,columna,cuadrado,lim_fila,lim_columna;
  315.      //Recorremos las filas: Si la casilla no es de entrada, marcamos el valor s.valor[i][j] como FALSE ya que comparten fila
  316.      for(fila=0;fila<9;fila++) if (!s.pvalor[i][fila][0] && !s.calculado[i][fila]) s.pvalor[i][fila][s.valor[i][j]]=false;    
  317.      //analogo para columna  
  318.      for(columna=0;columna<9;columna++) if (!s.pvalor[columna][j][0] && !s.calculado[columna][j]) s.pvalor[columna][j][s.valor[i][j]]=false;
  319.  
  320.     // Calculamos a qué subcuadrado 3x3 pertenece (i,j). Numerados de arriba abajo, de izquierda a derecha
  321.     // y del 0 al 8
  322.     if (j<3) cuadrado=0;
  323.     else if (j<6) cuadrado=1;
  324.     else if (j<9) cuadrado=2;
  325.     if (i<3) cuadrado=cuadrado;
  326.     else if (i<6) cuadrado=cuadrado+3;
  327.     else if(i<9) cuadrado=cuadrado+6;
  328.      
  329.      // Asignamos las coordenadas del vértice inferior derecho a los limites (que dependen de c, obviamente)
  330.      lim_fila=3*(cuadrado/3)+3;
  331.      lim_columna=3*(cuadrado%3)+3;    
  332.      //Con estos bucles recorremos el cuadrado c. Empezamos en el vértice superior izquierdo, y vamos sumando
  333.      //filas y columnas hasta terminar en el vertice inferior derecho del cuadrado.
  334.      //Si la casilla no es de entrada, marcamos el valor s.valor[i][j] como FALSE ya que comparten cuadrado
  335.      for(fila=3*(cuadrado/3);fila<lim_fila;fila++) for(columna=3*(cuadrado%3);columna<lim_columna;columna++) if (!s.pvalor[fila][columna][0] && !s.calculado[fila][columna]) s.pvalor[fila][columna][s.valor[i][j]]=false;
  336.  
  337. }
  338.  
  339. /* Rellenar por eliminacion todas las casillas del sudoku, es decir, comprueba si alguna casilla solo tiene un posible valor
  340.  y de ser asi, se lo asigna */    
  341. void rellenarEliminacion(sudoku &s)
  342. {
  343.      int i,j,k,contador;
  344.      for (i=0;i<9;i++) for (j=0;j<9;j++) if (!s.pvalor[i][j][0] && !s.calculado)
  345.      {
  346.           contador=0;
  347.           for(k=1;k<10;k++) if (s.pvalor[i][j][k]) contador++;
  348.           if (contador==1) for (k=1;k<10;k++) if (s.pvalor[i][j][k]) s.valor[i][j]=k;
  349.      }
  350. }
  351.  
  352. /* dado un sudoku, intenta resolverlo y lo devuelve con el maximo posible de valores calculados */
  353. void resolver(sudoku &s)
  354. {
  355.      int i,j;
  356.      sudoku s_copia;
  357.      rellenarEliminacion(s);
  358.      completarTodo(s);    
  359.      for (i=0;i<9;i++) for (j=0;j<9;j++) actualizarEntradas(s,i,j);
  360.      while (!igual(s,s_copia))
  361.      {
  362.            s_copia=s;
  363.            rellenarEliminacion(s);
  364.            completarTodo(s);          
  365.            for (i=0;i<9;i++) for (j=0;j<9;j++) actualizarEntradas(s,i,j);
  366.      }
  367. }  
  368.  
  369. /* Dado un sudoku s, completa todos los valores que puede llamando a las funciones completar fila, columan y cuadrado.*/
  370. void completarTodo(sudoku &s)
  371. {
  372.      int i,valor;
  373.      for(i=0;i<9;i++) for (valor=1;valor<10;valor++)
  374.      {
  375.                       completarfila(s,i,valor);
  376.                       completarcolumna(s,i,valor);
  377.                       completarCuadrado(s,i,valor);
  378.      }
  379. }
  380.  
  381. /* Dado un sudoku, un valor, y una fila, intenta encontrar la unica casilla (si la hay) de la fila en la que pueda
  382. ir el valor, si la encuentra, le asigna el valor
  383. Devuelve true si la encuentra y false en otro caso */
  384. bool completarfila(sudoku &s, int fila, int valor)
  385. {
  386.      int columna,k,contador=0;
  387.      for (columna=0;columna<9;columna++) if (s.pvalor[fila][columna][valor]) contador++;
  388.      
  389.      if (contador==1)
  390.      {
  391.                      for (columna=0;columna<9;columna++) if (s.pvalor[fila][columna][valor] && !s.pvalor[fila][columna][0] && s.valor[fila][columna]!=valor)
  392.                      {
  393.                          s.valor[fila][columna]=valor;
  394.                          for (k=1;k<10;k++) s.pvalor[fila][columna][k]=false;
  395.                          s.calculado[fila][columna]=true;
  396.                          s.pvalor[fila][columna][valor]=true;
  397.                          return true;
  398.                          
  399.                      }
  400.                      
  401.      }
  402.      return false;
  403. }
  404.                      
  405. /* Analoga a la anterior */    
  406. bool completarcolumna(sudoku &s,int columna,int valor)
  407. {
  408.      int fila,k,contador=0;
  409.      for (fila=0;fila<9;fila++) if (s.pvalor[fila][columna][valor]) contador++;
  410.      if (contador==1)
  411.      {
  412.                      for (fila=0;fila<9;fila++)  if (s.pvalor[fila][columna][valor] && !s.pvalor[fila][columna][0] && s.valor[fila][columna]!=valor)
  413.                      {
  414.                          s.valor[fila][columna]=valor;
  415.                          for (k=1;k<10;k++) s.pvalor[fila][columna][k]=false;
  416.                          s.calculado[fila][columna]=true;
  417.                          s.pvalor[fila][columna][valor]=true;
  418.                          return true;
  419.                          
  420.                      }
  421.      }
  422.      return false;
  423. }
  424.  
  425. /* Analoga a la anterior */
  426. bool completarCuadrado(sudoku &s,int c, int valor)
  427. {
  428.      int i,j,li,lj,k,contador=0;
  429.      // Asignamos las coordenadas del vértice inferior derecho a los limites (que dependen de c, obviamente)
  430.      li=3*(c/3)+3;
  431.      lj=3*(c%3)+3;    
  432.      //Con estos bucles recorremos el cuadrado c. Empezamos en el vértice superior izquierdo, y vamos sumando
  433.      //filas y columnas hasta terminar en el vertice inferior derecho del cuadrado.
  434.      for(i=3*(c/3);i<li;i++) for(j=3*(c%3);j<lj;j++) if (s.pvalor[i][j][valor]) contador++;
  435.      if (contador==1) for(i=3*(c/3);i<li;i++) for(j=3*(c%3);j<lj;j++) if (s.pvalor[i][j][valor] && !s.pvalor[i][j][0] && s.valor[i][j]!=valor)
  436.      {
  437.            s.valor[i][j]=valor;
  438.            for (k=1;k<10;k++) if (!s.pvalor[i][j][0] && !s.calculado[i][j]) s.pvalor[i][j][k]=false;
  439.            s.calculado[i][j]=true;
  440.            s.pvalor[i][j][valor]=true;
  441.            return true;
  442.                          
  443.      }
  444.      return false;
  445. }
  446.  
  447.  
  448. /* Dado un sudoku, devuelve true si puede encontrar un valor k para la casilla (i,j) del sudoku, y false en otro caso.
  449. En caso de que lo encuentre, también devuelve i,j, y k */
  450. bool encontrarPosible(sudoku s,int &i, int &j, int &k)
  451. {
  452.      int fila,columna,valor;
  453.      // Recorremos todas las casillas y todos los valores, hasta encontrar alguno.
  454.      for (fila=0;fila<9;fila++) for (columna=0;columna<9;columna++) if (!s.pvalor[fila][columna][0]) for (valor=1;valor<10;valor++) if (s.pvalor[fila][columna][valor])
  455.      {
  456.             i=fila;
  457.             j=columna;
  458.             k=valor;
  459.             return true;
  460.      }
  461.      return false;
  462. }
  463.  
  464. /* Dado un sudoku con más de una solucion, escribe (resolviendo recursivamente) todas sus soluciones en "respuestas.txt" */
  465. bool resolverVarios(sudoku &s, int &n)
  466. {
  467.      sudoku copia;
  468.      int i,j,k,valor;
  469.      
  470.      // Aunque esta funcion no deberia ser llamada con sudokus que solo tengan una solucion, prevenimos errores.
  471.      // Sólo la primera llamada podria entrar en este if, ya que el resto de llamadas recursivas solo se llaman
  472.      // con sudokus de al menos 2 soluciónes.
  473.      if (soluciones(s)==1) escribirFichero(s,n,"respuestas.txt");  
  474.      
  475.      // El sudoku tiene más de una solucion (ver llamada recursiva)
  476.      else
  477.      {
  478.           copia=s;
  479.           // Mientras se pueda suponer un valor por valido...
  480.           while (encontrarPosible(s,i,j,k))
  481.               {
  482.                  // ... suponemos dicho valor
  483.                  for(valor=1;valor<10;valor++) s.pvalor[i][j][valor]=false;
  484.                  s.valor[i][j]=k;
  485.                  s.pvalor[i][j][k]=true;
  486.                  s.pvalor[i][j][0]=true;
  487.                  actualizarEntradas(s,i,j);
  488.                  // Y vemos qué pasa con el sudoku:
  489.                      
  490.                  // si tiene una solucion, la escribimos
  491.                  if (soluciones(s)==1)
  492.                  {
  493.                           n++;
  494.                           if (n-10000==0) cout<<endl<<"Calculadas las 10.000 primeras soluciones, se ira mostrando el progreso..."<<endl<<endl;
  495.                           if (n%10000==0) cout<<endl<<n;  
  496.                           escribirFichero(s,n,"respuestas.txt");              
  497.                           resolver(s);
  498.                           s=copia;
  499.                           s.pvalor[i][j][k]=false;
  500.                           copia=s;
  501.                           return false;                      
  502.                  }
  503.                  
  504.                  // Si no tiene ninguna solucion, hemos descubierto que ese valor no es una posibilidad
  505.                  else if (irresoluble(s))
  506.                  {
  507.                                  s=copia;
  508.                                  s.pvalor[i][j][k]=false;
  509.                                  copia=s;
  510.                                  return false;
  511.                  }
  512.                  // Y si tiene más de una solucion, llamamos recursivamente a la funcion.
  513.                   resolverVarios(s,n);
  514.               }
  515.      }
  516.      
  517. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement