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: 17 años, 4 meses
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(0, count($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(1, 2, 3, 4, 5, 6, 7, 8, 9);
        
$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(1, 28);
        }
        
$arrPosiciones=array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81);
        
$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(1, 2, 3, 4, 5, 6, 7, 8, 9);
        
$cols=array(1=>1, 2=>2, 3=>3, 4=>4, 5=>5, 6=>6, 7=>7, 8=>8, 0=>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(1, 2, 3, 10, 11, 12, 19, 20, 21),
            
'B'=>array(4, 5, 6, 13, 14, 15, 22, 23, 24),
            
'C'=>array(7, 8, 9, 16, 17, 18, 25, 26, 27),
            
'D'=>array(28, 29, 30, 37, 38, 39, 46, 47, 48),
            
'E'=>array(31, 32, 33, 40, 41, 42, 49, 50, 51),
            
'F'=>array(34, 35, 36, 43, 44, 45, 52, 53, 54),
            
'G'=>array(55, 56, 57, 64, 65, 66, 73, 74, 75),
            
'H'=>array(58, 59, 60, 67, 68, 69, 76, 77, 78),
            
'I'=>array(61, 62, 63, 70, 71, 72, 79, 80, 81)
        );
    
        
$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