Mientras el script anterior me genera una pagina asi:
He conseguido crear esto:
A simple vista no tiene mucha diferencia. Pero en cuanto a programación sí. Éste ya diferencia los cuadros de 3x3, y además no deja utilizar el mismo numero en el mismo cuadrante. La piedra angular consiste en la creación del array. En vez de dos dimensiones, el array sodoku tiene
cuatro dimensiones. Es decir, dos pares de coordenadas.
sodoku[caja_fila][caja_columna][celda_fila][celda_columna]
Asi es mas facil controlar en qué cuadrante nos encontramos.
Como sé que a nadie le apetece leerse un script de 500 paginas, lo he partido en cachitos mas entendibles:
Código PHP:
<style>
.fila_celdas {
height:20px;
clear:both;
}
.fila_cuadrantes {
height:62px;
clear:both;
text-align:center;
}
.celda {
border: solid 1px black;
text-align:center;
width: 20px; height:20px;
font-size:10px;
font-family:tahoma;
float:left;
margin:0px;
}
.caja {
width: 75px; height:75px;
float:left;
text-align:center;
margin:0px;
}
</style>
La declaración de estilo CSS:
Es más engorrosa, pero define todo lo necesario para que queden formateados los divs sin necesidad de HTML de más. 'fila_cuadrantes' contiene un fila de 'caja', y 'caja' contiene 3 capas de 'fila_celdas', y 'fila_celdas' contiene a su vez 3 divs de 'celda'; creando asi la estructura deseada.
Código PHP:
var X=9; // celdas de lado
//INICIALIZACION DEL ARRAY SODOKU (Array de 4 dimensiones)
var sodoku=new Array(); //contiene todas las cajas (X cajas)
for(var x=0;x<X/3;x++) { //cajaX
sodoku[x]=new Array(X/3);
for(var y=0;y<X/3;y++) { //cajaY
sodoku[x][y]=new Array(X/3);
for(var i=0, n=0;i<3;i++) { //celdaX
sodoku[x][y][i]=new Array(3);
for(var j=0;j<3;j++) { //celdaY
sodoku[x][y][i][j]=new Array(3);
sodoku[x][y][i][j]= -1//(n++)+x+y;
}
}
}
}
// asi el array queda sodoku[cajaX][cajaY][celdaX][celdaY]
//funcion document.write, no tan engorrosa y con opcion de salto <br />
function e(q,salto) { document.write(q); if(salto) document.write("<br />"); }
// imprimimos la estructura HTML de divs para luego solo tener que poner los valores
for(var x=0; x<X/3; x++) { //cajaX
e('<div class="fila_cuadrantes">');
for(var y=0; y<X/3; y++) { //cajaY
e('<div class="caja" id="caja_'+x+'_'+y+'">');
for(var i=0;i<3;i++) { //celdaX
e('<div class="fila_cajas">');
for(var j=0;j<3;j++) { //celdaY
e('<div class="celda" id="sodoku_'+x+'_'+y+'_'+i+'_'+j+'"></div>');
}
e('</div>');
}
e('</div>');
}
e('</div>');
}
e(" ",1);
//actualiza los valores del array sodoku en la estructura de divs
function imprime_sodoku() {
for(var x=0;x<X/3;x++) //cajaX
for(var y=0;y<X/3;y++) //cajaY
for(var i=0;i<3;i++) //celdaX
for(var j=0;j<3;j++) //celdaY
document.getElementById("sodoku_"+x+"_"+y+"_"+i+"_"+j).innerHTML=sodoku[x][y][i][j];
}
Inicialización, estructura HTML y funciones básicas:
Inicializa las variables y el array multidimensional 'sodoku'. Crea el HTML necesario (un par de divs) sin contenido. Define la funcion 'e' (para comodidad solamente (debug)), y la funcion 'imprime_sodoku' que se encarga de rellenar la estructura.
Código PHP:
/**************************************************************************/
// FUNCIONES GET_____
//nos devuelve un array con todos los elementos de una fila respecto a una celda
function getFila(x,y,i,j) {
var dev=new Array();
for(_y=0; _y<X/3; _y++) //fila de cajas
for(_j=0; _j<X/3; _j++)
dev.splice(dev.length, 0, sodoku[x][_y][i][_j]); //cogemos la fila entera de celdas
return dev;
}
//nos devuelve un array con todos los elementos de una columna respecto a una celda
function getColumna(x,y,i,j) {
var dev=new Array();
for(_x=0; _x<X/3; _x++) //columna de cajas
for(_i=0; _i<3; _i++) // cada celda en la columna _j
dev.splice(dev.length, 0, sodoku[_x][y][_i][j]);
return dev;
}
//nos devuelve un solo array con la caja de la celda dada (solo tiene una dimension)
function getCaja(x,y) {
var dev=new Array();
for(_i=0; _i<3; _i++)
for(_j=0; _j<X/3; _j++)
dev.splice(dev.length, 0, sodoku[x][y][_i][_j]);
return dev;
}
Funciones get___:
Las funciones get___ devuelven un array unidimensional de lo que se le pida. Asi es mas facil trabajar con los numeros que debemos excluir a la hora de colocarlos aleatoriamente en la estructura.
Código PHP:
/**************************************************************************/
// RELLENAR EL SODOKU
var nums_posibles=new Array(X);
for(var a=0;a<X;a++) nums_posibles[a]=a;
//busca un numero dentro de un array de numero
// y devuelve su indice. Si no lo encuentra devuelve -1
function numAt(arr,num) {
for(var a=0; a<arr.length; a++)
if( arr[a]==num )
return a;
return -1;
}
//elimina del array 'total' todos los numeros del array 'posibilidades', y devuelve el nuevo 'total'
function eliminaPosibilidades(total, posibilidades) {
for(var a=0; a<posibilidades.length; a++) {
var esta=numAt(total,posibilidades[a])
if( esta!=-1)
total.splice(esta,1);
}
return total;
}
//copia un array y lo devuelve
function copia(arr) {
var dev=new Array();
for(var a=0;a<arr.length; a++)
dev[dev.length]=arr[a];
return dev;
}
//rellenamos celda a celda
for(var x=0;x<X/3;x++) //cajaX
for(var y=0;y<X/3;y++) //cajaY
for(var i=0;i<3;i++) //celdaX
for(var j=0;j<3;j++) { //celdaY
e('sodoku['+x+']['+y+']['+i+']['+j+']: ');
var nums=copia(nums_posibles);
nums=eliminaPosibilidades(nums, getFila(x,y,i,j) );
nums=eliminaPosibilidades(nums, getColumna(x,y,i,j) );
nums=eliminaPosibilidades(nums, getCaja(x,y) );
if(nums.length!=0) //nos hemos quedado sin numeros para poder poner
sodoku[x][y][i][j]=nums[ parseInt(Math.random()*nums.length) ];
else
sodoku[x][y][i][j]=-1;
e("Posibilidades: "+nums+" --> <b>"+sodoku[x][y][i][j]+"</b>",1);
}
Relleno aleatorio:
Como antes, nums_posibles es una matriz con todos los numeros del 0 al 9. La funcion 'numAt' es la que busca un numero en un array y devuelve su indice si lo encuentra. 'eliminaPosibilidades' borra del array total todos los elementos de 'posibilidades' si los encuentra (para excluir numeros posibles). La funcion 'copia' devuelve una copia del array pasado por argumento.
Después, [b]rellenamos[b]: Esto se hace mas legible que antes: Por cada celda se dan todas las posibilidades. A estas posibilidades iremos quitando los numeros que encontremos en su fila, su columna, y su cuadrante. Si nos quedamos sin numero por poner, colocamos el dichoso "-1".
Con un
Código PHP:
imprime_sodoku();
podremos ver el sodoku en pantalla, y ademas si hacemos al final
Código PHP:
//en rojo los "-1"
for(var x=0;x<X/3;x++) //cajaX
for(var y=0;y<X/3;y++) //cajaY
for(var i=0;i<3;i++) //celdaX
for(var j=0;j<3;j++) //celdaY
if(sodoku[x][y][i][j]==-1)
document.getElementById("sodoku_"+x+"_"+y+"_"+i+"_"+j).style.backgroundColor="red";
colorearemos de rojo los divs que contengan -1 para "cazarlos" mejor.
Bueno, el resultado lo he puesto antes:
Ahora me queda arreglar el "-1", que creo que lo voy a intentar por atributos HTML. A ver si me sale y lo puedo postear completo.