Ver Mensaje Individual
  #12 (permalink)  
Antiguo 27/01/2010, 09:09
Avatar de dggluz
dggluz
 
Fecha de Ingreso: abril-2009
Ubicación: Buenos Aires, Argentina
Mensajes: 525
Antigüedad: 15 años
Puntos: 50
Respuesta: [APORTE] Generador de sudokus sencillo y explicado

Debido a todas las idas y vueltas, dejo el script completo como quedó finalizado (tener en cuenta que no logra sudokus muy complicados, y si bien intenta llegar a la dificultad que se le pide, no siempre lo consigue):
Código PHP:
<?php
    
// Generador de sudokus. Versión original por dggluz (http://www.primolius.com/).
    // Enlace: 
    // De uso libre mientras se cite la fuente y no sea para fines comerciales.
    
    // Puede llegar a ocurrir que el script demore demasiado,
    // por eso ponemos un tiempo límite de 10 segundos.
    
set_time_limit(30);
    
    
    
// La función shuffle de PHP no tiene una buena aleatoriedad, 
    // por eso generé esta otra. El array resultante tiene índice numérico ordenado y consecutivo comenzando en 0.
    
function shuffle2(&$arr)
    {
        if(empty(
$arr))
        {
            return array();
        }
        
$arr2=array();
        while(
count($arr2)<count($arr))
        {
            
// Alimento (pongo la semillita :D) la aleatoriedad con un número 
            // que depende de los microsegundos del epoch
            
srand(ceil(999999999*microtime()));
            
$i=rand(0count($arr)-1);
            if(!
in_array($i$arr2))
            {
                
array_push($arr2$i);
            }
        }
        
$arr=array_combine($arr2$arr);
        
ksort($arr);
        
$arr=array_values($arr);
    }
    
    function 
completarMatrizSudoku()
    {
        
$A=array();
        
$B=array();
        
$C=array();
        
$D=array();
        
$E=array();
        
$F=array();
        
$G=array();
        
$H=array();
        
$I=array();
        
        
$_a=array();
        
$_b=array();
        
$_c=array();
        
$_d=array();
        
$_e=array();
        
$_f=array();
        
$_g=array();
        
$_h=array();
        
$_i=array();
        
        
$_1=array();
        
$_2=array();
        
$_3=array();
        
$_4=array();
        
$_5=array();
        
$_6=array();
        
$_7=array();
        
$_8=array();
        
$_9=array();
        
        
$j=0;
    
        
        
$original=array(123456789);
        
$letras=array(1=>'a'2=>'b'3=>'c'4=>'d'5=>'e'6=>'f'7=>'g'8=>'h'0=>'i');
        
$cuadrado=array(
             
1=>'A',  2=>'A',  3=>'A',  4=>'B',  5=>'B',  6=>'B',  7=>'C',  8=>'C',  9=>'C'
            
10=>'A'11=>'A'12=>'A'13=>'B'14=>'B'15=>'B'16=>'C'17=>'C'18=>'C'
            
19=>'A'20=>'A'21=>'A'22=>'B'23=>'B'24=>'B'25=>'C'26=>'C'27=>'C'
            
28=>'D'29=>'D'30=>'D'31=>'E'32=>'E'33=>'E'34=>'F'35=>'F'36=>'F'
            
37=>'D'38=>'D'39=>'D'40=>'E'41=>'E'42=>'E'43=>'F'44=>'F'45=>'F'
            
46=>'D'47=>'D'48=>'D'49=>'E'50=>'E'51=>'E'52=>'F'53=>'F'54=>'F'
            
55=>'G'56=>'G'57=>'G'58=>'H'59=>'H'60=>'H'61=>'I'62=>'I'63=>'I'
            
64=>'G'65=>'G'66=>'G'67=>'H'68=>'H'69=>'H'70=>'I'71=>'I'72=>'I'
            
73=>'G'74=>'G'75=>'G'76=>'H'77=>'H'78=>'H'79=>'I'80=>'I'81=>'I');
        
$resultado=array();
        
        
$i=1;
        while(
$i<=81)
        {
            
$idxLetra=$i&#37;9;
            
$letra='_'.$letras[$idxLetra];
            
$idxNro=ceil($i/9);
            
$nro='_'.$idxNro;
            
$cuadro=$cuadrado[$i];
            
            
// Si no sabes lo que significa $$letra, busca "variables variables PHP" en Google
            
$copia=array_diff($original, $$letra, $$nro, $$cuadro);
            
shuffle2($copia);
            
$valor=array_pop($copia);
            
array_push($$letra$valor);
            
array_push($$nro$valor);
            
array_push($$cuadro$valor);
            
$resultado[$i]=$valor;
            
            if(
$valor==NULL)
            {
                
// Si algo va saliendo mal, empezamos todo de nuevo
                
$i=1;
                
$j++;
                
$A=array();
                
$B=array();
                
$C=array();
                
$D=array();
                
$E=array();
                
$F=array();
                
$G=array();
                
$H=array();
                
$I=array();
                
                
$_a=array();
                
$_b=array();
                
$_c=array();
                
$_d=array();
                
$_e=array();
                
$_f=array();
                
$_g=array();
                
$_h=array();
                
$_i=array();
                
                
$_1=array();
                
$_2=array();
                
$_3=array();
                
$_4=array();
                
$_5=array();
                
$_6=array();
                
$_7=array();
                
$_8=array();
                
$_9=array();
            }
            else
            {
                
$i++;
            }
        }
#        echo "intentos: ".$j;
        
return $resultado;
    }
    
    function 
borrarCasilleros($sudokuOriginal$dificultad=NULL)
    {
        if(
$dificultad==NULL)
        {
            
srand(ceil(999999999*microtime()));
            
$dificultad=rand(128);
        }
        
$arrPosiciones=array(123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081);
        
$arrOrden=$arrPosiciones;
        
shuffle2($arrOrden);
        
$quitados=0;
        
$sudokuResultante=$sudokuOriginal;
        
$limite=$dificultad+35;
        
$i=1;
        while(
$quitados<$limite && $i<81)
        {
            
$sudokuAnt=$sudokuResultante;
            
$quitadosAnt=$quitados;
            
$idx=$arrOrden[$i];
            
$sudokuResultante[$idx]=NULL;
            if(!
solucionUnica($sudokuResultante$quitados$idx))
            {
                
$quitados=$quitadosAnt;
                
$sudokuResultante=$sudokuAnt;
            }
            
$i++;
        }
        
$dificultad=$quitados-35;
        echo 
"<br />Dificultad: $dificultad<br />";
        return 
$sudokuResultante;
    }
    
    function 
solucionUnica($sudoku, &$quitados$idx)
    {
        
$original=array(123456789);
        
$cols=array(1=>12=>23=>34=>45=>56=>67=>78=>80=>9);
        
$cuadrado=array(
             
1=>'A',  2=>'A',  3=>'A',  4=>'B',  5=>'B',  6=>'B',  7=>'C',  8=>'C',  9=>'C'
            
10=>'A'11=>'A'12=>'A'13=>'B'14=>'B'15=>'B'16=>'C'17=>'C'18=>'C'
            
19=>'A'20=>'A'21=>'A'22=>'B'23=>'B'24=>'B'25=>'C'26=>'C'27=>'C'
            
28=>'D'29=>'D'30=>'D'31=>'E'32=>'E'33=>'E'34=>'F'35=>'F'36=>'F'
            
37=>'D'38=>'D'39=>'D'40=>'E'41=>'E'42=>'E'43=>'F'44=>'F'45=>'F'
            
46=>'D'47=>'D'48=>'D'49=>'E'50=>'E'51=>'E'52=>'F'53=>'F'54=>'F'
            
55=>'G'56=>'G'57=>'G'58=>'H'59=>'H'60=>'H'61=>'I'62=>'I'63=>'I'
            
64=>'G'65=>'G'66=>'G'67=>'H'68=>'H'69=>'H'70=>'I'71=>'I'72=>'I'
            
73=>'G'74=>'G'75=>'G'76=>'H'77=>'H'78=>'H'79=>'I'80=>'I'81=>'I');
        
$cuadrados=array(
            
'A'=>array(123101112192021),
            
'B'=>array(456131415222324),
            
'C'=>array(789161718252627),
            
'D'=>array(282930373839464748),
            
'E'=>array(313233404142495051),
            
'F'=>array(343536434445525354),
            
'G'=>array(555657646566737475),
            
'H'=>array(585960676869767778),
            
'I'=>array(616263707172798081)
        );
    
        
$idxColumna=$cols[$idx%9];
        
$idxFila=ceil($idx/9);
        
$idxCuadrado=$cuadrado[$idx];
        
        
$idxsColumna=array();
        
$idxsFila=array();
        for(
$j=1$j<=9$j++)
        {
            
array_push($idxsColumna, ($idxColumna+9*($j-1)));
            
array_push($idxsFila, ($j+($idxFila-1)*9));
        }
        
$idxsCuadrado=$cuadrados[$idxCuadrado];
        
        
$columna=obtenerPorcion($sudoku$idxsColumna);
        
$fila=obtenerPorcion($sudoku$idxsFila);
        
$cuadro=obtenerPorcion($sudoku$idxsCuadrado);
        
        
$opciones=array_diff($original$columna$fila$cuadro);
        if(
count($opciones)==0)
        {
            echo 
"ERROR.";
        }
        elseif(
count($opciones)==1)
        {
            
$quitados++;
            return 
true;
        }
        else
        {
            return 
false;
        }
    }
    
    function 
obtenerPorcion($arrOriginal$arrIdx)
    {
        
$arr=array();
        foreach(
$arrIdx as $idx)
        {
            
array_push($arr$arrOriginal[$idx]);
        }
        return 
$arr;
    }
?>
En la respuesta siguiente está el resto del código del ejemplo completo (se puede probar la implementación de ese ejemplo en http://www.primolius.com.ar/sudoku.php.

Última edición por dggluz; 27/01/2010 a las 09:16