Foro de elhacker.net

Programación => Java => Mensaje iniciado por: Editame en 28 Julio 2017, 22:27 pm



Título: Codigo para crear SUDOKUS
Publicado por: Editame en 28 Julio 2017, 22:27 pm
Hola amigos que tal, bueno soy nuevo por aca y no se si este en el lugar equivocado y si es asi pido disculpas a los moderadores y pido redireccionamiento del tema al hilo indicado donde pueda encontrar la ayuda que necesito.

Bueno mi inconveniente es el siguiente:
- Estoy realizando un sudoku parte de un proyecto de la Universidad y necesito ayuda con el codigo que genera la matriz aleatoriamente, he creado tres funciones para verificar si existe el dato en la fila, columna o cuadrante al parecer todo esta bien pero al correrlo entra en un bucle infinito, al realizar algunas pruebas de escritorio me encontre que sin tener error en el codigo llega a un punto que en la inserccion de los datos no se da ya que no encuentra ningun numero valido a ingresar, en fin dejo el codigo y ya sabran de lo que le hablo


adjunto una imagen en una prueba de escritorio que iba haciendo tomado de la consola y muestra hasta donde llega la matriz y que en los valores validos a ingresar no se puede por esa razon sigue evaluando infinitamente

(https://www.dropbox.com/s/7us5q8gd4pc79rn/error.PNG?dl=0)

Código:
package Clases;
import java.util.Random;
public class Metodos {
    static Random ran = new Random();
    static int matriz [][] = new int [9][9];

    public static void main(String[] args) {
        generadorAleatorio();
    }
    
    public static void generadorAleatorio (){
        int i=0,j;
        
        while (i < 9){
            System.out.println("fila:  " + i);
            j = 0;
            while (j < 9){
                System.out.println("Columna" + j);
                int numero = 1 + ran.nextInt(9);
                System.out.println(numero);
                System.out.println(busquedaFilas(numero, i));
                if (busquedaFilas(numero, i).equalsIgnoreCase("no")) {
                    
                    System.out.println(busquedaColumnas(numero, j));
                    if (busquedaColumnas(numero, j).equalsIgnoreCase("no")) {
                        
                        System.out.println(busquedaCaja(numero, i, j));
                        if (busquedaCaja(numero, i, j).equalsIgnoreCase("no")) {
                            
                            matriz[i][j] = numero;
                            System.out.println(numero + "Valido");
                            j++;
                        }
                    }
                }
            }
            i++;
        }
        for (int k = 0; k < 9; k++) {
            System.out.println("");
            for (int l = 0; l < 9; l++) {
                System.out.print(matriz[k][l] + "\t");
            }
        }
        
    }
    
    public static String busquedaFilas (int valor, int filas) {
        
        String resultado = "no";
        for (int i = 0; i < 9; i++) {
            if (valor == matriz[filas][i]) {
                resultado = "si";
                break;
            }
        }
        return resultado;
    }
    
    public static String busquedaColumnas (int valor, int columnas) {
        
        String resultado = "no";
        for (int i = 0; i < 9; i++) {
            if (valor == matriz[i][columnas]) {
                resultado = "si";
                break;
            }
        }
        return resultado;
    }
    
    public static String busquedaCaja (int valor, int filas, int columnas) {
        
        int minfila, maxfila;
        int mincolum, maxcolum;
        
        if (filas >= 0 && filas < 3) {
            minfila = 0;
            maxfila = 2;
        }else if (filas >= 3 && filas < 6) {
            minfila = 3;
            maxfila = 5;
        }else {
            minfila = 6;
            maxfila = 8;
        }    
        
        if (columnas >= 0 && columnas < 3) {
            mincolum = 0;
            maxcolum = 2;
        }else if (columnas >=3 && columnas <6) {
            mincolum = 3;
            maxcolum = 5;
        }else{
            mincolum = 6;
            maxcolum = 8;
        }
              
        String resultado = "no";
        
        for (int i = minfila; i <= maxfila ; i++) {
            for (int j = mincolum; j <= maxcolum; j++) {
                if (valor == matriz[i][j]) {
                    resultado = "si";
                    break;
                }
            }
        }
        return resultado;
    }
}


Título: Re: Ayuda con codigo en java
Publicado por: footer en 30 Julio 2017, 19:55 pm
Hola amigo estuve revisando tu codigo y despues de un largo rato llegue a la respuesta:
te aclaro que no tengo la solucoin pero tengo la causa del problema. Lo que hice fue escribir tu codigo nuevamente paso a paso e ir verificandolo de a poco, y le puse para que solo me mostrara por consola cuando un numero es valido, sin importarme si ese numero estaba en la fila o no que solo mostrar los numeros validos y me devolvio esto:

8 Valido
1 Valido
7 Valido
3 Valido
4 Valido
6 Valido
2 Valido
5 Valido
9Valido

3 Valido
2 Valido
6 Valido
5 Valido
1 Valido
7 Valido
4 Valido
8 Valido

Si acomodas los numeros para formar el sudoku queda asi:

|817|346|259|
|326|517|48?|

Miralo detenidamente... ningun numero se repita horizontalmente, ni verticalmente. Pero falta uno, que es justamente el que causa el bucle infinito.

El la primera fila estan todos del 1 al 9 siendo este ultimo el ultimo de la fila, y el la segunda fila estan del 1 al 8, menos el 9... entonces en ese ? solo podria ir el 9 por que los otros ya estan acomodados en la fila, pero eso no puede pasar por que conincidiria con un numero verticalmente, entonces el programa descartara el nueve y sorteara otro numero pero no importa que numero diferente de nueve salga sorteado sea cual sea coincidira con numeros de la fila, conclusion el bucle se produce por un error logico. donde no importa que numero saldra sorteado nunca sera valido. Espero haberme explicado.

Mira este otro ejemplo:

2Valido
8Valido
7Valido
3Valido
4Valido
6Valido
5Valido
9Valido
1Valido

4Valido
5Valido
6Valido
7Valido
2Valido
1Valido
8Valido
3Valido

|287|346|591|
|456|721|83?|

Aqui el numero que falta cumple es el 9 si sale sorteado ese numero cumple la condicion de que no exista en la fila y no exista en la columna pero no cumple la condicion de que no exista en el cuadrado de 3x3, es decir numero sortedo < 9 --> se repite en fila asi que se descarta; numero sorteado = 9 se repite en cuadrado 3x3; esto genera error logico.

Ultimo ejemplo:

5Valido
8Valido
9Valido
6Valido
4Valido
1Valido
3Valido
2Valido
7Valido

4Valido
3Valido
2Valido
7Valido
9Valido
8Valido
1Valido
5Valido
6Valido

7Valido
6Valido
1Valido
5Valido
2Valido
3Valido
8Valido
4Valido
9Valido

3Valido
5Valido
4Valido
1Valido
7Valido
6Valido
9Valido
8Valido
2Valido

6Valido
1Valido
8Valido
2Valido
3Valido
9Valido
7Valido

Esta vez me devolvio varias filas

|589|641|327|
|432|798|156|
|761|523|849|
|354|176|982|
|618|239|7??|


Faltan el 4 y el 5, esta vez el problema esta en la posicion 8 de la ultima fila, si pone un 4 se repite en la columna y si pone un 5 tambien lo hara y si pone cualquier otro numero se repetira en la fila.

Lo que podrias hacer es un algoritmo que detecte cuando se producen estos errores y hacer que intente generarlo desde cero hasta q en algun momento haga 9 filas, yo en varios intentos a mano logre que generara 4 filas tal vez en x intentos logre 9 :)


Aqui te dejo el link de descarga del codigo que hice que es identico al tuyo xD pero le cambio algunos nombre a las variables para no perderme en los bucles y el array.

link= https://drive.google.com/open?id=0B1i-JNEuRD1zTFlOZzdNMWJMSTA


Título: Re: Ayuda con codigo en java
Publicado por: Serapis en 30 Julio 2017, 23:20 pm
Sin revisar el código a fondo, parece que el problema del bucle infinito es porque en efecto trata de elegir 'al azar' un número donde solo existe una posibilidad de elección y resulta que esa elección ya está presente. Tal y como te comenta footer.

De entrada, no hace falta que busques el 9º número al azar, busca solo los 8 primeros, el 9º será el número que reste de la serie, así evitas el bucle infinito.
Y ahora que termina la segunda fila (y siguientes, pero no para la primera) debes verificar si verticalmente también existe conincidencia (y en cada uno de los 3 bloques implicados) en cuyo caso descarta de nuevo la fila actual y la regeneras al azar hasta que se valide, así vas avanzando con cada fila....

--------------------
Sin embargo el método, no es adecuado, vas a tirar mucho de azar para lograr cada Sudoku...
Un modo más inteligente es mantener con claridad 3 arrays para decidir entre qué números debe elegirse al azar.
tú ahora estás en la casilla x,y, pués rellenas 3 arrays (que serían Fila(), Columna(), Bloque()... (ver más abajo el pseudocódigo para la función de ejemplo para obtener el array de Fila: GetValoresEnFila))
Código:
TmpFila = GetValoresEnFila(Entero Y)  //solo pongo el psedocodigo para esta función, comprendiendo ésta es fácil deducir como han de ser las otras dos funciones...
TmpColumna = GetValoresEnColumna(Entero X)
TmpBloque = GetValoresEnBloque(Entero X, Entero Y)

Esos 3 arrays con los valores actuales en la fila, columna y bloque (si un valor no está tendrán valor 0), se deben luego unificar en uno solo array resumen donde aparezcan cada valor existente una sola vez
Ver más abajo la función (aquí la llamada con los 3 arrays como parámetros y la devolución de uno resumido:
Código:
Tmp = UnificarCubiculos(TmpFila, TmpColumna, TmpBloque)

Entonces llamas a una función preguntan do para ser rellenado con los valores ausentes, pasándole como entrada ese array unificado:
Presentes, es el array resultado de 'unificarCubiculos'...
Código:
Array Byte = Funcion TomarAusentes(Array Byte Presentes(), Out Entero NumAusentes)
    Array tipo Byte V(0 a c_Ocho)
    Entero k

    NumAusentes=0
    Bucle para k desde 1 a c_Nueve
        Si (Presentes(k) = 0) luego   // El valor está vacío como casilla, en fila, columna y bloque... se añade
            V(NumAusentes) = k
            NumAusentes +=1
        Fin si
    Fin Bucle

    Devolver V        
Fin Funcion


Código:
Array Byte Sudoku(0 a 80)  //es el array que mantiene internamente los valores.

Devuelve un array con los valores de la fila recibida.
Código:
Array Byte = Funcion GetValoresEnFila(Entero n)
    Array tipo Byte V(0 a c_Ocho)
    Entero Index, k

    Index= (n * c_Nueve)
    n = 0 // Reutilizamos n (se recibe por valor)
    Bucle para k desde Index a (Index + c_Ocho)
        V(n) = Sudoku(k)  //Aray que contiene los valores
        n +=1
    Fin Bucle
  
    Devolver V
Fin Funcion

l array 'resumen', simplemente toma todos los valores distintos presentes, sin repetición...
Unificando así los 3 arrays en uno de resumen...
Código:
Array Byte = Funcion UnificarCubiculos(Array Byte Fila(), Array Byte Columna(), Array Byte Bloque())
    Array tipo Byte V(0 a c_Nueve)

    // contar el número de presencias de cada valor...
    Bucle para k desde 0 a c_Ocho
        Si (Fila(k) > 0) luego   // Si no está vacía la casilla...
            V(Fila(k)) += 1
        fin si
        Si Columna(k) > 0 luego   // Si no está vacía la casilla...
            V(Columna(k)) += 1
        fin si
        Si (Bloque(k) > 0) luego   // Si no está vacía la casilla...
            V(Bloque(k)) += 1
        fin si
    Fin Bucle
  
    // Ahora se reagrupan arriba en el array (las ausencias (valor 0), quedan 'huecas' en la parte alta del array.
    V(0) = 0 //Realmente no es necesario, ya que no llevó la cuenta de 'ceros'
    Bucle para k desde 1 a c_Nueve
        Si (V(k) > 0) luego
            V(k) = k            
        Fin si
    Fin Bucle

    Devolver V        
Fin Funcion


Así el orden de estas funciones para tomar UN VALOR al azar sería, la siguiente función:
X,Y representan la casilla donde deseamos poner el valor
  no se verifica que x e y estén en el rango correcto, se supone que son correctos,
  que fueron verificados, antes de llamar aqui
Código:
Byte = funcion SeleccionarValorAzar(Entero X, Entero Y)
    Array tipo Byte TmpFila()
    Array tipo Byte TmpColumna()
    Array tipo Byte TmpBloque()
    Array tipo Byte Tmp()
    Array tipo Byte Azar()

    // Primero consultamos que tenemos, en la 'vecindad' de esa casilla.
    //      Puede optimizarse si se mantienen en memoria 9 arrays de filas, 9 de columnas y los 9 de bloques y se actualizan convenientemente. Será mas veloz, pero más complejo y másgasto de memoria... Hacerlo, queda a tu esfuerzo si te interesa.
    // Recuérdese que las casillas 'vacías', tienen valor 0
    TmpFila = GetValoresEnFila(Entero Y)
    TmpColumna = GetValoresEnColumna(Entero X)
    TmpBloque = GetValoresEnBloque(Entero X, Entero Y)

    // Ya tenemos, los 3 cubículos con los que comparar el valor al azar... pero...
    // ya dije que no vamos a comparar, en su defecto, integraremos los 3 en 1 ( a modo de resumen, que simplica
    // por completo la verificación a un simple bucle).
    Tmp = UnificarCubiculos(TmpFila, TmpColumna, TmpBloque)

    // Ahora rellenamos otro array con los valores ausentes en el array resumen unificado.
    Byte n
    Azar = TomarAusentes(Tmp, n)

    // OJO: si el array queda vacío implica que hay que desecha los valores actuales de la fila y volver a reconstruirla entera
    Si (n=0) luego devolver 0

    // Finalmente se toma un valor al azar entre 0 y n-1, que representa el indice del array Azar. Este array tiene exclusivamente los números que no aparecen ni en la fila, ni en columna, ni en bloque.
    k = Aleatorio( entre 0 y n-1)

    Devolver Azar(k)
Fin Funcion

La función que rellena el sudoku entero sería algo como esto:
Código:
Funcion RellenarSudokuAlAzar()    
    Entero Fila, columna
    Byte Valor

    Fila=0 // la primera fila, la podrías obtener al azar completamente en ese caso marcar aquí 1, para comenzar en la fila 1, la 0 no va a requerir todas las comprobaciones que pueden requerir las siguientes.
    Hacer  '// esto es fila, puede ser un bucle que va de 0 a 8
        Columna = 0
        Hacer    
            Valor = SeleccionarValorAzar(Columna, Fila)  //la función que obtiene un valor de cada vez.
            Si (Valor>0) luego
                Sudoku((Fila * c_Nueve) + Columna) = valor //Sudoku() es el array que mantiene internamente los valores.    
                // Si el array es bidimensional se pondría así...    
                //Sudoku(Columna, Fila) = valor    
                Columna +=1
            Si no
                // Borra los valores de la fila actual
                Bucle para k desde 0 a columna
                    Sudoku((Fila * c_Nueve) + k) = 0
                Fin bucle
                Columna = 0
            Fin si
        Repetir Mientras (Columna <9)
        Fila +=1
    Repetir Mientra (Fila<9)
Fin Funcion

c_Ocho, c_Nueve son constantes con esos valores que en este juego se van a usar muy a menudo. Igualmente constantes para 2 y 3 podrían ser usadas, para las consultas en los bloques.



--------------------------------------------------------------------------------------------------------------
p.d.: Actualizo la funcion para rellenar el Sudoku, para salir del bache ante bloqueos...
Fijarse en los cambios añadidos para Intentos, cuando el valor devuelto es 0.
Si se va dibujando desde esta función cuando sale un valor y se borra cuando se anulan los valores, se ve sobre la marcha como opera , se detiene y rada un poco en algunas filas, y a veces borra también la previa y luego sale del bache y lo completa siempre...

La función que rellena el sudoku entero sería algo como esto:
Código:
Funcion RellenarSudokuAlAzar()   
    Entero Fila, columna
    Byte Valor, Intentos

    Fila=0 // la primera fila, la podrías obtener al azar completamente en ese caso marcar aquí 1, para comenzar en la fila 1, la 0 no va a requerir todas las comprobaciones que pueden requerir las siguientes.
    Hacer  '// esto es fila, puede ser un bucle que va de 0 a 8
        Intentos = 0
        Columna = 0
        Hacer   
            Valor = SeleccionarValorAzar(Columna, Fila)  //la función que obtiene un valor de cada vez.
            Si (Valor>0) luego
                Sudoku((Fila * c_Nueve) + Columna) = valor   //Sudoku() es el array que mantiene internamente los valores.             
                Columna +=1
            Si no
                // Borra los valores de la fila actual
                Bucle para k desde 0 a columna
                    Sudoku((Fila * c_Nueve) + k) = 0
                Fin bucle

                // Tras 10 intentos en la misma fila, borramos también la fila previa
                Intentos += 1
                Si (Intentos = 10) luego
                    Si (Fila > 0) luego  // no podemos retroceder a filas más atrás que la primera.
                        Fila = (Fila - 1) // Borramos también la fila anterior (y si sucede otra vez, la previa, etc...)
                        Bucle para k desde 0 To c_Ocho
                            Sudoku((Fila * c_Nueve) + k) = 0                           
                        Fin Bucle
                    Fin si
                    Intentos = 0
                Fin si
                Columna = 0
            Fin si
        Repetir Mientras (Columna <9)
        Fila +=1
    Repetir Mientra (Fila<9)
Fin Funcion
// Al término de esta función se podría dibujar los valores en el tablero para verificar visualmente el resultado.


Título: Re: Ayuda con codigo en java
Publicado por: Editame en 31 Julio 2017, 06:31 am
Hola amigos como estan ?, espero que bien.

Bueno primero que todo quiero agradecerles el tiempo que dedicaron ambos compañeros para revisar el codigo y ayudarme, de verdad les agradezco mucho. Pero retomando el tema NEBIRE la verdad no entiendo mucho tu logica, intento comprender  lo que me dices, pero no lo logro primero me dices que cree numeros del 1 al 8  y calcule la ultima posicion por fila, columna o caja buscando la que falte, eso por un lado, luego hablas de crear 3 arrays distintos para para hallar valores entre los cuales debo obetener los que faltan (Es lo que entiendo) osea estando en tal posicion que cree una fila una columna y un bloque ??? .... y me perdi  ;D ;D no se de verdad hay muchas cosas que no entiendo de tu codigo, podrias por favor intentar enseñarme tu logica con palabras o pasos mas simples no se como decirte, pero como dice mi profesor de programacion "formas de programar hay muchas", tal vez yo no lo veo como tu no lo entiendo por que esta es tu forma pero intenta explicarme tu logica (asi sea sin codigo solo la logica) que si entiendo la logica ya vere de que manera lo programo..

No se si entiendas el punto no quiero tener que hacer algo como tu jajaj si no poder aprender de ti...

te agradezco muchisimo a ti a todos los que puedan participar

cuidense y espero sus respuestas.


Título: Re: Ayuda con codigo en java
Publicado por: Serapis en 31 Julio 2017, 15:19 pm
Ok, te lo explicaré más sencillo, con palabras ..y dibujitos, pero entonces será a la tarde, ahora(después de comer, tengo el tiempo muy justo) no tengo tiempo para hacer los dibujitos y escribir las explicaciones.


Título: Re: Ayuda con codigo en java
Publicado por: Serapis en 31 Julio 2017, 22:21 pm
Una imagen para hacernos una idea de qué hablamos...
(https://i.imgur.com/JS1tetD.png)

En la imagen puedes apreciar:
A - Una fila
B - Una columna
C - Un bloque

Hay 9 filas, 9 columnas y 9 bloques, es fácil contrarlos.
Cuando digo que necesitamos 3 arrays, son uno para guardar los valores de una fila dada, otro para una columna dada y otro para un bloque dado... los 3 son de 9 elementos, porque 9 son las casillas que tienen, aunque el array va del 0 al 8.
------------------------------

Así cuando digo este pseudocodigo:
Código:
TmpFila = GetValoresEnFila(Entero Y)  
TmpColumna = GetValoresEnColumna(Entero X)
TmpBloque = GetValoresEnBloque(Entero X, Entero Y)

Me estoy refiriendo a 3 funciones distintas que reciben uno o dos parámetros y devuelven un array... en la siguiente imagen vemos que datos deberían devolver estas 3 funciones, con más claridad.

(https://i.imgur.com/cqgz0k9.png)
He marcado un circulito en la casilla que queremos rellenar, al caso es la posición:
X= 5
Y = 5

- Bien si llamo a la función GetvaloresEnFila (x), me debe devolver un array con los valores en la fila x (fila 5), el array siempre será de 9 elementos, y los valores (en este orden) serán: 3,7,8,1,4,0,0,0,0 y se almacena en el array tmpFila
- Cuando llame a la función GetValoresEncolumna(y), me debe devolver un array con los valores en la columna y (columna 5), el array siempre será de 9 elementos, y los valores (también en el orden en que aparecen) serán: 9,4,5,3,7,0,0,0,0 y se almacena en el array tmpColumna
- Finalmente cuando llame a la función GetValoresEnBloque(x,y), me debe devolver un array con los valores que contiene el bloque que contiene la casilla que le paso. La casilla puede ser cualquiera en el bloque. La función debe calcular cual es la posición dx y dy donde se localiza la primera casilla de dicho bloque, a partir de ahí lee 3 casillas, aumenta una fila y lee otras 3 aumenta otra fila y lee las 3 últimas... el bloque se compone de 3 filas de las cuales toma 3 columnas. Así los valores que devuelve en orden serán: 9,8,3,  6,2,7,  1,4,0 y se almacenan en el array tmpBloque

En la imagen he seleccionado, la fila, columna y bloques afectados, por tanto un modo de ver que las funciones operan bien es verificar que en efecto devuelven correctamente esos valores.  Nota también como los valores de las casillas vacías devuelve un 0, es la forma de identificar que una casilla está libre.
Lógicamente todos los valores que vamos alamcenando van a para a un array de 81 elementos (9x9), un array unidimensional, pero podrías hacerlo bidimensional (aunque las explicaciones del pseudocódigo dado están pensadas para un array unidimensional. al caso es lo mismo. Uno debe ser capaz de traducir de un array unidimensional a uno bidimensional y viceversa, son matemáticas de suma, resta, multiplicación y división, además de módulo.

Y para qué necesitamos estos arrays de valores. Bueno tu eliges al azar un valor del 1 al 9, y luego verificas que no esté en la fila, la columna y el bloque, pero las más de las veces ya estará, así que de nuevo tendrás que pedir otro valor al azar entre 1 y 9 y será muy lento, tanto más cuanto más cerca de estar completo esté el sudoku.

Aquí la forma de ser más inteligentes es primero recoger qué valores están... (ya lo hemos hecho con esas 3 funciones en sendos arrays), lo siguiente es unificar los 3 arrays en uno solo... es decir eliminar los valores repetidos, así la función UnificarCubiculos, hace esto mismo.
Y cómo lo hace. básicamente se crea un array cuyos índices 1,2,3,4,5,6,7,8,9 serán contadores del valor cuyo índice son. es decir cuando en uno de los arrays aparezca por ejemplo tmpFila(3) = 9 entonces en el unificado se hsumará uno al índice 9 tmpUnificado(9) +=1 pero no podemos poner directamente 9, ya que dicho valor está contenido en el array, o lo pasamosa  una variable:
v = tmpfila(3)  // 'v' vale 9 en este caso
tmpUnificado(v) +=1
o bien lo hacemos directamente sin una varible auxiliar:
tmpUnificado(tmpFila(3)) +=1
Haciendo lo mismo con todo el array tmpFila, tmpColumna, tmpBloque tendremos al final el array con estos valores de cuenta (valores reales obtenidos de la imagen):
tmp(1) = 2
tmp(2) = 1
tmp(3) = 3
tmp(4) = 3 //aparece 3 veces, una en la fila, otra en la columna y otra en el bloque.
tmp(5) = 1
tmp(6) = 1
tmp(7) = 3
tmp(8) = 2
tmp(9) = 2
Obviamente algunos están contados más de una vez, según que formen parte 8por ejemplo) de una fila y una columna, o una columna y un bloque o un bloque y la fila, o incluso de los 3 arrays. No importa, queremos saber cuales aparecen y si hay más de 1 vez aparecen.
Luego este array lo simplificamos para que no sea el índice, si no el valor quien refleje su presencia (al final el valor estará el el mismo índice, pero eso no nos importará luego).
Por eso se hace un bucle de reasignaciónde valores:
Código:
bucle para k desde 1 a 9
  si tmp(k) Es mayor que 0 luego
     tmp(k) = k // tmp(1) = 1 .... tmp(5)= 5 ... tmp(9) = 9
  fin si
fin bucle
Esta parte no es estrictamente necesaria, pero es buena práctica a la hora de optimizar, uno puede hacer luego algo de 'código espagueti' siempre y cuando lo entienda... el array de salida, nos sería válido tanto antes como después de este último bcle, solo sería cuestión de en la siguiente función interpretarlo correctamente, para evitar equívocos, hacemos que el valor sea lo importante... por so el bucle final.

Ahora ya hemos únificado los 3 arrays en 1 sólo. y el resumen es que el array contiene todos los valores que están presentes en la fila, columna o bloque a la que la casilla x,y hace referencia.

Lo siguiente entonces es generar un array con los valores que faltan. Para ello con el array de salida de la función UnificarCubiculos (tu ponle el nombre que te dé la gana, siempre que te oriente con su significado), es el parámetro de entrada para la función: TomarAusentes
Da la casulaidad de que en este punto hemos llegado a una situación de bloqueo. Luego te explico por qué...

Ahora mismo tengo que hacer unas cosas, así que envío esto aunque no esté terminado y luego (2-3 horas) pongo otra imagen sin bloqueo y sigo explicando (a partir de ella) y detrás la situación de bloqueo, por qué se produce y la solución para salir adelante...


Editado para reponer las imágenes que parece que la página web las ha eliminado... (afortunadamente las guardaba en la misma carpeta donde hice el programa).


Título: Re: Ayuda con codigo en java
Publicado por: Serapis en 1 Agosto 2017, 03:23 am
Continuamos, ahora con la siguiente imagen... como puede verse, el contenido es casi el mismo que la vez anterior, solo ha cambiado el contenido de la última fila... (y con ello del bloque, pero se mantiene el de la columna.

Actualizo los datos que debieran devolver los 3 arrays conforme a la nueva imagen:
- función GetvaloresEnFila (x), serán: 3,7,8,5,4,0,0,0,0 en el array tmpFila
- función GetValoresEncolumna(y), serán: 9,4,5,3,7,0,0,0,0 en el array tmpColumna
- función GetValoresEnBloque(x,y), serán: 9,8,3,  6,2,7,  5,4,0 en el array tmpBloque
(https://i.imgur.com/TuRKflb.png)

Ahora al unificar los 3 arrays en 1, obtenemos (en el primer paso):
 0  1  3  3  3  1  3  2  2
tmp(1) = 0
tmp(2) = 1
tmp(3) = 3
tmp(4) = 3 //aparece 3 veces, una en la fila, otra en la columna y otra en el bloque.
tmp(5) = 3
tmp(6) = 1
tmp(7) = 3
tmp(8) = 2
tmp(9) = 2
Esto es, la cuenta de cuantas veces aparece cada valor. el valor referenciado por el índice. Así el 9 aparece 2 veces, una vez en la columna y otra en el bloque.
Ahora terminamos la unificación, como ya dije para tener como valor no la cuenta si no contancia de la 'presencia'.
Lo previo se puede considerar una tabla de apariciones, donde se cuenta cuantas veces aparece cada valor (en este caso de los 3 arrays).
La siguiente es una tabal de presencia, donde se constar que valores aparecen, sin importar el número de veces, y como dije el código encargado de ello es el que ya puse:
Código:
bucle para k desde 1 a 9
  si tmp(k) Es mayor que 0 luego
     tmp(k) = k // tmp(1) = 1 .... tmp(5)= 5 ... tmp(9) = 9
  fin si
fin bucle
Y el resultado del array será:
tmp(1) = 0
tmp(2) = 2
tmp(3) = 3
tmp(4) = 4 //aparece 3 veces, una en la fila, otra en la columna y otra en el bloque.
tmp(5) = 5
tmp(6) = 6
tmp(7) = 7
tmp(8) = 8
tmp(9) = 9
Nótese que en esta función es la única que construye un array de 9 valores (10 elementos), porque el índice 9, ha de contener cuantas veces aparece el 9.
Finalmente llegamos a la siguiente función que nos entregará un array con todos los ítems que no aparecen, para ello recibe como parámetro 'éste array'...

Función: TomarAusentes
Este array hace algo opuesto a la última parte de la fase anterior. de hecho se podría haber remplazado esa fase con lo que hace esta función, si se quiere optimizar, sin embargo resultaría un código más oscuro de cara a entenderlo...
Código:
Array Byte = Funcion TomarAusentes(Array Byte Presentes(), Out Entero NumAusentes)
    Array tipo Byte V(0 a c_Ocho)
    Entero k

    NumAusentes=0
    Bucle para k desde 1 a c_Nueve
        Si (Presentes(k) = 0) luego   // El valor está vacío como casilla, en fila, columna y bloque... se añade
            V(NumAusentes) = k
            NumAusentes +=1
        Fin si
    Fin Bucle

    Devolver V        
Fin Funcion
Nótese que como el array de entrada tiene 10 elementos, el bucle termina en el índice 9, y comienza en el 1, porque no nos interesan los 0 (los valores del sudoku van del 1 al 9).
Cada vez que se encuentra que un valor no aparece se añade al array y se aumenta el índice. Casualmente solo hay un valor que no aparece en el array el '1', luego cuando se elija al azar de este array devolverá el índice 0 con contenido 1...
Que será el valor a consignar en la casilla x,y.
En la siguiente casilla nos encontramos de nuevo que solo qeueda un valor elegible, el 2...
Pero en la siguiente casilla (penúltima de la fila), da dos opciones, veamos el resultado que arroja el array tras la llamada a 'UnificarCubiculos' (el indice del 0, lo pongo con guión, señalando con ello que no importa):
array tmp:  -,1,2,3,4,5,0,7,8,0
Como se ve ya mismo hay ausentes el 6 y el 9, que es lo que nos debe arrojar la función 'TomarAusentes':
tmp(0) = 6
tmp(1) = 9
Lo siguiente en el código es elegir al azar entre el 0 y el 1, para devolver justo el valor del elemento en el índice 'azaroso'. en mi caso mi equipo ha seleccionado el '0' que crresponde al valor 6, luego si no se da situación de bloqueo en la siguiente columna, allí quedará por consignar el 9... La columna admitiría más valores que ese,  pero la fila y el bloque lo impiden, solo les falta el 9 a ambos.


Vamos a mostrar algo más interesante de modo que haya más elementos ausentes tras la unificación de los arrays... seguramente nos suceda al comenzar la siguiente fila, pués también se comienza el bloque y solo existen 'presentes' los valores que tiene la columna '0' al caso pongo un nuevo dibujo actualizado.
(https://i.imgur.com/KKU4aiN.png)
El resultado de los 3 arrays... para la ca:
tmpFila:  0,0,0,0,0,0,0,0,0  porque está vacía.
tmpColumna:  7,8,9,4,5,3,0,0,0
tmpBloque: 0,0,0,0,0,0,0,0,0  porque está vacío.
Y pasamos al resultado de reunificar los tres arrays, y ya en la devolución, no en pasos intermedios, también por brevedad, los pondré en fila:
tmp:  -,0,0,3,4,5,0,7,8,9
Y ahora el array de ausentes La misma función devuelve por referencias cuantos elementos son válidos en el array al caso 3 (el array sigue teneiendo 9 elementos):
tmp:  1,2,6
Esto nos indica que al azar debemos elegir entre 0 y 2, que son los índices válidos.. sea cual sea el elegido (al caso me sale el índice 1), se entrwega el valor cuyo índice ha salido:
Código:
   k = Aleatorio( entre 0 y n-1) //n es aquí el valor devuelto por referencia de la cantidad de 'valores válidos' en el array.
    Devolver Azar(k)

En resumen es más inteligente, porque no elegimos a al azar un valor a ciegas entre 0 y 9, y luego comprobamos que no exista en fila, columna ni bloque y si está vuelta a elegir y vuelta a comprobar y así hasta que no esté. Es más inteligente orque esa comprobación se hace una sola vez al inicio y así cuando elegimos ala azar elegimos solo entre los valores que no constan ya.

Todavía se puede ir más lejos y crear una función (con parte de la que existe en 'SeleccionarValorAzar'), para que cuando el usuario pretenda meter un valor verifique si ese valor es válido para la casilla o no...
Y para optimizarlo, dicha función podría partirse en dos, una hasta obtener el array de ausentes y otra para de entre esos ausentes elegir el valor al azar y luego cuando el usuario quiera poner un valor, llamamos igualmente a esa primera función para entregar el array de ausentes y creamos una segunda para con ese array ver si contiene el valor que el usuario pretende introducir, devolviendo un buleano de 'existe'...

Desmontando la función como he dicho (esta ahora llama a dos, cuyo contenido se repartió entre ellas):
Cuando se va a rellenar el Sudoku:
Código:
Byte = funcion SeleccionarValorAzar(Entero X, Entero Y)
    Array tipo Byte Tmp()
    Byte n
    
    Tmp = GetArrayAusentes(X, Y)
    Si (n>0) luego
        n = DevolverValorAzar(Tmp, n)
    Fin si
    Devolver n
Fin Funcion

Código:
Array byte = GetArrayAusentes(Entero X, Entero Y,  Out Entero NumAusentes)
    Array tipo Byte TmpFila()
    Array tipo Byte TmpColumna()
    Array tipo Byte TmpBloque()
    Array tipo Byte Tmp()
    Array tipo Byte Azar()

    // Primero consultamos que tenemos, en la 'vecindad' de esa casilla.
    //      Puede optimizarse si se mantienen en memoria 9 arrays de filas, 9 de columnas y los 9 de bloques y se actualizan convenientemente. Será mas veloz, pero más complejo y másgasto de memoria... Hacerlo, queda a tu esfuerzo si te interesa.
    // Recuérdese que las casillas 'vacías', tienen valor 0
    TmpFila = GetValoresEnFila(Entero Y)
    TmpColumna = GetValoresEnColumna(Entero X)
    TmpBloque = GetValoresEnBloque(Entero X, Entero Y)

    // Ya tenemos, los 3 cubículos con los que comparar el valor al azar... pero...
    // ya dije que no vamos a comparar, en su defecto, integraremos los 3 en 1 ( a modo de resumen, que simplica
    // por completo la verificación a un simple bucle).
    Tmp = UnificarCubiculos(TmpFila, TmpColumna, TmpBloque)

    // Ahora rellenamos otro array con los valores ausentes en el array resumen unificado.
    
    Devolver = TomarAusentes(Tmp, NumAusentes)
Fin Funcion

Se toma un valor al azar entre 0 y Cantidad-1, que representa el indice del array Azar. Este array tiene exclusivamente los números que no aparecen ni en la fila, ni en columna, ni en bloque.
Código:
Byte = DevolverValorAzar(Array byte Ausentes(), Byte Cantidad)
    byte k
    
    k = Aleatorio( entre 0 y Cantidad-1)
    Devolver Ausentes(k)
Fin Funcion


Cuando se va a verificar si el valor que introduce el usuario es correcto:
Será válido si está ausente en Fila, Columna y bloque que refiere la casilla...
Código:
Buleano = funcion ValorEsAdmisible(Entero X, Entero Y, Byte ValorUser)
    Array tipo Byte Tmp()
    Byte n
    
    Tmp = GetArrayAusentes(X, Y)
    Si (n>0) luego
        Devolver ExisteValorEnAusentes(Tmp, n, ValorUser)
    Si no
        Devolver FALSE
    Fin si
    Devolver n
Fin Funcion

Código:
Buleano = ExisteValorEnAusentes(Array byte Ausentes(), Byte Cantidad, byte ValorUser)
    byte k
    
    Bucle para k desde 0 a Cantidad-1
        Si (Ausentes(k) = ValorUser) luego
            Devolver TRUE
        Fin si
    Fin Bucle
Fin Funcion

Me falta explicarte solamente un poco más lo de los bloqueos, asíq eu seré breve y si no lo entiendes me lo dices...

El bloqueo se produce cuando tanto en la fila como en la columna como en el bloque ya hay puesto (al menos entre todos ellos (valores unificados)), todos los 9 valores, y en consecuencia no existe posibilidad de elgir uno que no esté... en tu caso (me refiero a tu código) elijas el que elijas, ya está, por tanto da igual que elijas 1000 veces como está la comprobación forzará a elegir otra vez...

En mi código, en el mensaje de ayer, al final puse un cambio para salir del bloqueo, y consiste en que cuando se alcance un bloqueo, se elimine por completo esa fila y se recomience d enuevo la fila, y si tras 10 intentos sigue sin poderse completar la fila, borra también la anterior (yaq que es posible que e la actual no haya solución, porque con la anterior ya cais no deja opciones). en teoría es posible que si tras borra rla actual y la prevuia aparecieren al recrear la previa 10 bloqueos seguidos, borrara también la anterior... en fin, en cualquier caso cuantos menos filas haya más difícil que se dé una situación de bloqueo, por eso suele basta con borrar la fila actual...
Pongo el código que se ocupa de esa parte (que corresponde a la función 'RellenarSudokuAlAzar'), para refrescar la memoria:
Código:
.... //código previo
            Valor = SeleccionarValorAzar(Columna, Fila)  //la función que obtiene un valor de cada vez.
            Si (Valor>0) luego
                Sudoku((Fila * c_Nueve) + Columna) = valor   //Sudoku() es el array que mantiene internamente los valores.            
                Columna +=1
            Si no
                // Borra los valores de la fila actual
                Bucle para k desde 0 a columna
                    Sudoku((Fila * c_Nueve) + k) = 0
                Fin bucle

                // Tras 10 intentos en la misma fila, borramos también la fila previa
                Intentos += 1
                Si (Intentos = 10) luego
                    Si (Fila > 0) luego  // no podemos retroceder a filas más atrás que la primera.
                        Fila = (Fila - 1) // Borramos también la fila anterior (y si sucede otra vez, la previa, etc...)
                        Bucle para k desde 0 To c_Ocho
                            Sudoku((Fila * c_Nueve) + k) = 0                            
                        Fin Bucle
                    Fin si
                    Intentos = 0
                Fin si
                Columna = 0
            Fin si
.... // código después...


-------------
p.d.: Puedes modificar el tema del hilo para que refleje lo que realmente es, y así si alguien utiliza el buscador pueda encontrarlo?. Nadie pone a buscar "necesito ayuda" ni "ayuda con mi código", ....pero alguien sí buscaría algo como: "sudoku"...

Así te reclamo que cambies el título del tema a algo más acorde como: "Código para Sudoku"

Editado para reponer las imágenes...


Título: Re: Codigo para crear SUDOKUS
Publicado por: Editame en 1 Agosto 2017, 08:34 am
Hola NEBIRE que tal,

Ya esta mucho mejor esto ya puedo decir que comprendo muchisimo mas tu logica solo me queda ponerlo en practica y mirar hasta donde llego, cualquier inquietud o ayuda que necesite te la estare comunicando muchisimas gracias por tu colaboracion hasta el momento, espero poder seguir contando contigo jajajaj

Bendiciones Saludos a todos


Título: Re: Codigo para crear SUDOKUS
Publicado por: Editame en 3 Agosto 2017, 04:08 am
Nebire amigo tengo problemas al unificar los tres arrays en uno no se como pasarlos como parametros a la funcion Unificado.

solo llevo las tres funciones que obtienen los arrays de fila, columna y caja
me podrias ayudar.

Código:
public static int [] obtenerFila (int matriz[][], int filas, int columnas){
        int renglon[] = new int[9];
        for (int i = 0; i < 9; i++) {
            renglon[i]=matriz[i][columnas];
        }
        return renglon;
    }
   
    public static int [] obtenerColumna (int matriz[][], int filas, int columnas){
        int colum[] = new int[9];
        for (int i = 0; i < 9; i++) {
            colum[i]=matriz[filas][i];
        }
        return colum;
    }
   
    public static int [] obtenerCaja (int matriz[][], int filas, int columnas){
       
        int minfila, maxfila;
        int mincolum, maxcolum;
       
        if (filas >= 0 && filas < 3) {
            minfila = 0;
            maxfila = 2;
        }else if (filas >= 3 && filas < 6) {
            minfila = 3;
            maxfila = 5;
        }else {
            minfila = 6;
            maxfila = 8;
        }     
       
        if (columnas >= 0 && columnas < 3) {
            mincolum = 0;
            maxcolum = 2;
        }else if (columnas >=3 && columnas <6) {
            mincolum = 3;
            maxcolum = 5;
        }else{
            mincolum = 6;
            maxcolum = 8;
        }
       
        int k=0;
        int caja[] = new int[9];
        for (int i = minfila; i < maxfila; i++) {
            for (int j = mincolum; j < maxcolum; j++) {
                caja[k]=matriz[i][j];
                k++;
            }
        }
        return caja;
    }


Título: Re: Codigo para crear SUDOKUS
Publicado por: Serapis en 3 Agosto 2017, 06:44 am
Nebire amigo tengo problemas al unificar los tres arrays en uno no se como pasarlos como parametros a la funcion Unificado.
mmmm... y cómo has pasado el array que contiene todo el sudoku???. Yo veo en tu código una función así:
Código:
public static int [] obtenerFila (int matriz[][], int filas, int columnas){ ...


 
 Y bueno, en esta función...   
Código:
    public static int [] obtenerCaja (int matriz[][], int filas, int columnas){

Esta parte se puede simplificar y mejorar mucho:
 
 
Código:
     
        if (filas >= 0 && filas < 3) {
            minfila = 0;
            maxfila = 2;
        }else if (filas >= 3 && filas < 6) {
            minfila = 3;
            maxfila = 5;
        }else {
            minfila = 6;
            maxfila = 8;
        }     
       
        if (columnas >= 0 && columnas < 3) {
            mincolum = 0;
            maxcolum = 2;
        }else if (columnas >=3 && columnas <6) {
            mincolum = 3;
            maxcolum = 5;
        }else{
            mincolum = 6;
            maxcolum = 8;
        }

Mira, yo lo tengo así de simple:
Código:
bX = ((X \ c_Tres) * c_Tres)
bY = ((Y \ c_Tres) * c_Tres)
X,Y son las cordenadas de la casilla sobre la que estamos operando.
bX y bY, serían el X e Y de bloques, que en efecto serán 0,3 ó 6
Y en efecto, si haces la cuenta, para todas ellas del 0 al 8:

bX = ((0\3)*3) = 0
bX = ((1\3)*3) = 0
bX = ((2\3)*3) = 0

bX = ((3\3)*3) = 3
bX = ((4\3)*3) = 3
bX = ((5\3)*3) = 3

bX = ((6\3)*3) = 6
bX = ((7\3)*3) = 6
bX = ((8\3)*3) = 6

Date cuenta que es una división entera...       

Por último, no pases parámetros a una función si no los necesita para nada. Por ejemplo si la función 'obtenerFila ' no usa 'filas', elimina ese parámetro. Si la función 'obtenerColumna' no utiliza para nada el parámetro 'columnas', retíralo de la función.
También sería más acorde llamar a esos parámetros 'X' e 'Y', 'Filas' y 'Columnas' dan sentido como nombre a una cantidad de filas y columnas, para una posición única al menos que sea singular.


Título: Re: Codigo para crear SUDOKUS
Publicado por: Editame en 3 Agosto 2017, 07:12 am
lo que hago para contar con la matriz en todo el codigo es declararla como static  como si fuera una variable global, eso mismo es lo que estaba intentando con los otros array ponerlos globales a ver si me funcionaba y ya habia corregido lo de los parametros solo pase los necesarios para cada funcion, solo seria optimizar el codigo de la caja como lo recomendaste.

Por otro lado hay algunas cosas que no entiendo de tu codigo pero lo estoy intentando a mi manera tratando de interpretar tu codigo.

A la hora de crear el unificado tengo problemas con el ciclo lo empiezo en 1 hasta <= 9 para que no tome los valores de 0 y me bota error, esto es lo que llevo hasta el momento no esta terminado ni depurado hay sobre la marcha me voy dando cuenta que me falta

Código:
package Clases;

import java.util.Random;

public class Tratando {

    static Random rand = new Random();

    static int matriz[][] = new int[9][9];
    static int filas[] = new int[9];
    static int columnas[] = new int[9];
    static int caja[] = new int[9];
    static int unificado[] = new int[9];
    static int ausentes[] = new int [9];
    public static void GeneradorAleatorio() {

        int numero;
        int em = 0;
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                numero = 1 + rand.nextInt(9);
                if (em == 0) {
                    matriz[i][j] = numero;
                    em++;
                }else{
                    if (NumeroPermitido(numero)) {
                        matriz[i][j] = numero;
                    }
                }
            }
        }
       
        for (int i = 0; i < 9; i++) {
            System.out.println("");
            for (int j = 0; j < 9; j++) {
                System.out.print(matriz[i][j] + "\t");
            }
        }
    }

    public static void GetFila(int fila) {

        for (int i = 0; i < 9; i++) {
            filas[i] = matriz[fila][i];
        }
    }

    public static void GetColumna(int columna) {

        for (int i = 0; i < 9; i++) {
            columnas[i] = matriz[i][columna];
        }
    }

    public static void GetCaja(int filas, int columnas) {

        int minfila, maxfila;
        int mincolum, maxcolum;

        if (filas >= 0 && filas < 3) {
            minfila = 0;
            maxfila = 2;
        } else if (filas >= 3 && filas < 6) {
            minfila = 3;
            maxfila = 5;
        } else {
            minfila = 6;
            maxfila = 8;
        }

        if (columnas >= 0 && columnas < 3) {
            mincolum = 0;
            maxcolum = 2;
        } else if (columnas >= 3 && columnas < 6) {
            mincolum = 3;
            maxcolum = 5;
        } else {
            mincolum = 6;
            maxcolum = 8;
        }

        int k = 0;

        for (int i = minfila; i < maxfila; i++) {
            for (int j = mincolum; j < maxcolum; j++) {
                caja[k] = matriz[i][j];
                k++;
            }
        }
    }

    public static void unificarArray() {

        for (int i = 0; i < 9; i++) {
            unificado[filas[i]] = unificado[filas[i]] + 1;
            unificado[columnas[i]] = unificado[columnas[i]] + 1;
            unificado[caja[i]] = unificado[caja[i]] + 1;
        }

        for (int i = 0; i < 9; i++) {
            System.out.print(unificado[i] + "\t");
        }
    }
   
    public static void TomarAusentes (){
       
       
        int numeros;
        for (int i = 0; i < 10; i++) {
            if (unificado[i] == 0) {
                ausentes[i] = i;
               
            }
        }
    }
   
    public static boolean NumeroPermitido (int valor){
        boolean resultado = true;
        for (int i = 0; i < ausentes.length ; i++) {
            if (valor == ausentes[i]) {
                resultado = false;
                break;
            }
        }
        return resultado;
    }

    public static void main(String[] args) {

        GeneradorAleatorio();
       
    }
}


Título: Re: Codigo para crear SUDOKUS
Publicado por: Serapis en 3 Agosto 2017, 07:17 am
Tengo que irme, no he tenido tiempo de revisar tu código (el último)...
Pero si he alcanzado a ver que en las declaraciones de los arrays tienen todos 9 elementos... fíjate en mi código y verás que hay justo una que debe tener 10 elementos y adivina cual es...
En  mi pseudocódigo verás en casi todas partes
Array x (0 a c_Ocho) //c_ocho e suna contante cuyo valor es precisamente 8
pero en una de ellas verás que  en cambio pone:
Array x (0 a c_Nueve) <-----
Adivina cual de las funciones es ???

Citar
static int unificado[] = new int[9];
¿NUEVE??????

Revisa y si lo ves necesario contesta, a mediodía que vuelva, reviso tu código... y las dudas que te hayan surgido hasta entonces.


Título: Re: Codigo para crear SUDOKUS
Publicado por: Serapis en 3 Agosto 2017, 17:29 pm
lo que hago para contar con la matriz en todo el codigo es declararla como static  como si fuera una variable global, eso mismo es lo que estaba intentando con los otros array ponerlos globales a ver si me funcionaba
Bien. Cuando unos parámetros, en este caso arrays se usan para unas funciones que se usan masivamente, es preferible crear el array una sola vez y luego solo sobrescribirlos. Obviamente de cara a explicaciones, es preferible que cada función se acompañe de exactamente los parámetros que necesite o es más fácil perderse por no ver o saber de donde salen esas variables...
De hecho, de cara a optimizarlo (primero haz que funcione y funcione bien, siempre es lo primero, luego ya se optimizará), a veces un array puede ser reutilizado en más de una función (uno debe tener claro cuando esto es así, para no interferir en los valores y tenerlos sucios esperando unos valores que fueron cambiados por otra función).

Por otro lado hay algunas cosas que no entiendo de tu codigo pero lo estoy intentando a mi manera tratando de interpretar tu codigo.
Cuando suceda, lo remarcas y luego que sumes varias (si las hay), preguntas por esas dudas.


A la hora de crear el unificado tengo problemas con el ciclo lo empiezo en 1 hasta <= 9 para que no tome los valores de 0 y me bota error, esto es lo que llevo hasta el momento no esta terminado ni depurado hay sobre la marcha me voy dando cuenta que me falta

Código:
   static int unificado[] = new int[9];
  
    public static void unificarArray() {
        for (int i = 0; i < 9; i++) {
            unificado[filas[i]] = unificado[filas[i]] + 1;
            unificado[columnas[i]] = unificado[columnas[i]] + 1;
            unificado[caja[i]] = unificado[caja[i]] + 1;
        }
        for (int i = 0; i < 9; i++) {
            System.out.print(unificado[i] + "\t");
        }
    }
No es eso lo que veo en tu código es más, no se ajusta a mi descripción, copio y pego la mía y verás que no se ajusta...
Al caso he retirado los comentarios previos y añadido otros que es donde debes fijarte. También cambio las etiquetas de code por cita, para poner énfasis con negrita:

Citar
Array Byte = Funcion UnificarCubiculos(Array Byte Fila(), Array Byte Columna(), Array Byte Bloque())
    Array tipo Byte V(0 a c_Nueve)  // esto es, 10 ELEMENTOS. Este array es de 10 elementos

    // contar el número de presencias de cada valor...
    Bucle para k desde 0 a c_Ocho  // OJO: 0 a 8
        Si (Fila(k) > 0) luego   // Si no está vacía la casilla...
            V(Fila(k)) += 1
        fin si
        Si Columna(k) > 0 luego   // Si no está vacía la casilla...
            V(Columna(k)) += 1
        fin si
        Si (Bloque(k) > 0) luego   // Si no está vacía la casilla...
            V(Bloque(k)) += 1
        fin si
    Fin Bucle
  
    V(0) = 0 //Realmente no es necesario, ya que no llevó la cuenta de 'ceros'
    // Tu si llevas la cuenta al omitir, los condicionales d emás arriba, luego esto es aconsejable, no tanto como obligado 8más abajo mé extiendo sobre esto).


    // En tu versión, falta este bucle
    Bucle para k desde 1 a c_Nueve   //OJO: el bucle recorre desde 1 a 9
        Si (V(k) > 0) luego  //esto es imprescindible. Presencia, indica que aparece. Se consigna k, sólo si v(k) es mayor que 0, es decir si aparece.
            V(k) = k            
        Fin si
    Fin Bucle

    Devolver V        
Fin Funcion
En tu código también llevas la cuenta de 0, no importa, es más sencillo eliminar el condicional, pero en ese caso si será útil, al final la línea donde la comento como: " //Realmente no es necesario, ya que no llevó la cuenta de 'ceros'", como tu si has llevado la cuenta, ponlo a 0. Incluso aunque no se utilice ahora, un cambio a futuro, y que hayas olvidado que eso vale 0 podría darte dolores de cabeza intentando buscar el error. Es sólo una línea de código y evita problemas a futuro, es mejor ponerla.

Luego en mi 'versión' hay dos bucles, en uno genero la "tabla de conteo" de cada valor, pero eso es solo la primera parte, falta la segunda parte, donde en el otro la tabla de conteo se convierte en una "tabla de presencia".
En 'tu versión' el segundo bucle no existe, el que hay se remite al "System.out.print" que solo tiene efectos de verificación, pero le falta el 2º bucle que yo le pongo.

Ya he comentado que a efectos de optimización en ese segundo bucle se podría hacer la parte de la siguiente función, pero sería mucho más scuro, haciendo que cadas función haga una sola tarea (eso si, completa), queda perfectamente claro el propósito (único) de cada función...

- Una tabla de conteo: Es una tabla (array, unidimensional, bidimensional etc...) que lleva la cuenta de veces que aparece un determinado valor. Imagina un fichero de imagen, imagina que quieres obtener su histograma, necesitas contar cuantas veces aparece cada nivel de rojo, de verde y de azul en la imagen. Dando una imagen de 8bits por canal (un byte), se necesitará pués 3 arrays para contar los niveles de rojo, verde y azul. el array tendrá256 elementos por 256 son los niveles posibles para el rojo, verde y azul, es decir valores entrte 0 y 255...entonces leyendo la imagen con cada aparición haríamos algo como (para contarlos):
  arrRojo(Imagen.Rojo(n)) = arrRojo(imagen.Rojo(n)) +1
Que como se ve, no es distinto de nuestor caso, salvando el origen de los datos y el tamaño del array.
- Tabla de presencia: es una tabla donde lo único que necesitamos saber es que dicho valor aparece y nos da igual cuántas veces aparece... Esto puede hacerse directamente o a partir de la tabla anterior. De cara a entender, es preferible hacerlo indirectamente desde creando antes la tabla de conteo, así se vé con mucha claridad,  como se crea esta otra...
si arrRojo(nivel) > 0  luego
   arrRojo(nivel) = nivel
Fin si

Antes el array podía tener un valor elevado (más tratándose de una imagen si la imagen fuera casi toda blanca y tuviera pongamos un tamaño de 3500x2500 píxeles de ancho y alto (o al revés) tendríamos 8.750.000 píxeles en total, en total como solo hay 256 canales y lo son para el rojo, verde y azul, ni 8bits ni 16bits, nos valen para contener dicha cuenta, tendríamos que usar un array de 32 bits... Así es la tabla de conteno. En cambio la tabla de presencia basta que tenga como tipo de datos el más alto del valor que haya de contener, en este caso aún tratándose de colores, bastaría un array de bytes, porque los niveles solo van del 0 al 255. Luego es decisión de cada cual si aprovechas el mismo array para ambas tablas o no.

En el caso del sudoku, aunque lo has declarado integer y realmente nos basta con byte reutilizamos el array...

Para ver la diferencia entre ambas tablas, puedes imprimir el resultado de cada una al final de cada bucle. Verás que la tabla de conteo es equivalente a la tabla de presencia, la tabla de presencias, es también una tabla de ausencias, todos aquellos índices cuyo valor es 0, señala que no están ausentes. La tabla de ausencias que creamos luego es 'ordenada', y es básicamente mover al comienzo del array esos valores ausentes. Con el fin justamente de luego al usar una función random, elegir un índice al azar entre 0 el el último que porta un valor ausente. Al estar contiguos, eso es posible, si no habría que ver si el valor al azar entre el 0 y el 9, está ausente... pero si no lo está repetir todo el proceso se eterniza. Del modo en que procedemos se garantiza con una sola vez la elección de azar y una sola vez la
verificación (previa), sacar el siguiente número a consignar.

--------------------
P.d.:

En tu función de ausentes observo dos fallos:
Quito las etiquetas de code, para comentar encima con engrita.
Bueno al quirtar las etiquetas de code, como usas llaves con 'i', el codigo BBcode, lo interpreta como itálica, así que lo cambio, saco los comentarios y en su lugar dejo asteriscos

Código:
public static void TomarAusentes (){
        int numeros;  //no se usa...
        for (int i = 0; i < 10; i++) {  // **********01
            if (unificado[i] == 0) {
                ausentes[i] = i;  // **********02
            }
        }
    }

// **********01 Este bucle debe empezar en 1, no en 0. Los valores UTILES para el sudoku van del 1 al 9, el 0 no es un valor elegible, indica 'casilla vacía', 'casilla libre', 'casilla sin valor aún'

// **********02 NO: Este debe llevar su propio contador, no puede ser 'i'. Con cada aparición aumenta, si no, no estarían los valores contiguos...
// Imagina que te dicen aqui tienes una lista de alumnos. Todos los que tengan más de 18 años, los escribes en ESTA OTRA lista... acaso en esa nueva lista, no irían contiguos?. el primero hallado en la posición 0, el siguiente en la 1, el siguiente hallado en la 2, etc... sería absurdo que en esa nueva lista, aparezca un alumno en la posición 43, y en la nueva lista, tu lo consignes también en la posición 43... ¿Capisci, el significado de 'nueva lista' y 'valores contiguos'? . cuando se tenga esa lista de alumnos con más de 18 años quien la trate, la tratará contigua, imagina que entre ellos se va  ahacer un sorteo para ver una peli para mayor de 18 años, si en la lista hay inscritos 61 alumnos, se harían papeletas entre 1 y 61 (0 y 60 si lo consideramos técnicamente). Si la lista el último alumno se hubiera inscrito con su posición original pongamos 1563, sería complicado elegir al azar a un alumno, por número, se podría hacer por nombre, peor las matemáticas están para socorrernos, simplifiquemos cuando es posible. Entre 1 y 61 8ó 0 y 60), todos en una sala solitos, es más aislado que sortearlo entre los 1850 alumnos d ela escuela y luego preguntarle si tiene más de 18 años y si es que no, dejarle con un palmo de narices. Usando nombres, los que  son menores no entran en el sorteo, pero ven 'en directo' el sorteo saltando por encima de sus cabezas 'produciendo algo de envidia'  :laugh: :laugh: :laugh: :laugh:
Mejos con la lista aparte en otra función (una sala, se los llama ) y a puerta cerrada se hace el sorteo solo entre los implicados...

Bueno, cuando ya 'furrulen' estas dos funciones si tienes más dudas, pregunta.


Título: Re: Codigo para crear SUDOKUS
Publicado por: Editame en 5 Agosto 2017, 10:44 am
Hola NEBIRE que mas como etas espero que muy bien.

Bueno te comento ya hoy pude sentarme realmente a dedicarle tiempo a esto y creo que me fue super bien por que creo que adelante bastante y de la forma correcta, modifique cosas que para mi estaban demasiado enredadas y que no sabia si el codigo se estaba ejecutando de forma correcta pero llegue a un punto que no te entiendo y es la parte final de rellenar el sudoku como lo tienes en el siguiente codigo:

Código:
//código previo
            Valor = SeleccionarValorAzar(Columna, Fila)  //la función que obtiene un valor de cada vez.
            Si (Valor>0) luego
                Sudoku((Fila * c_Nueve) + Columna) = valor   //Sudoku() es el array que mantiene internamente los valores.             
                Columna +=1
            Si no
                // Borra los valores de la fila actual
                Bucle para k desde 0 a columna
                    Sudoku((Fila * c_Nueve) + k) = 0
                Fin bucle

                // Tras 10 intentos en la misma fila, borramos también la fila previa
                Intentos += 1
                Si (Intentos = 10) luego
                    Si (Fila > 0) luego  // no podemos retroceder a filas más atrás que la primera.
                        Fila = (Fila - 1) // Borramos también la fila anterior (y si sucede otra vez, la previa, etc...)
                        Bucle para k desde 0 To c_Ocho
                            Sudoku((Fila * c_Nueve) + k) = 0                           
                        Fin Bucle
                    Fin si
                    Intentos = 0
                Fin si
                Columna = 0
            Fin si
.... // código después...
aqui hay cosas obvias y otras no tanto.
1- cual es ese array sudoku y para que sirve ? no lo entiendo la verdad

2- yo estoy trabajando con una matriz bidimensional y en mi funcion generadoraleatorio() es donde supuestamente lo lleno(Segun mi forma de hacerlo) pero no se en que lugar estaria metiendo este codigo que te muestro arriba el tuyo, por que tu hablas de codigo previo y codigo despues ???

3- por otro lado tengo muchas dudas con la funcion de tomar ausentes por que pones como parametro un out NumAusentes

Código:
Array Byte = Funcion TomarAusentes(Array Byte Presentes(), Out Entero NumAusentes)
no entiendo por que pones ese valor ahi, o bueno creo saberlo, lo haces para tener el indice de ese vector pero lo que no se es por que tenerlo de parametro si al llamarlo de otra funcion como lo haces en
Código:
Array byte = GetArrayAusentes(Entero X, Entero Y,  Out Entero NumAusentes)

ese valor no lo utilizas de ninguna manera o por lo menos no lo veo que lo hagas para mi ese valor por parametro no sirve por que el dato que se utiliza es es que devuelve la funcion como tal.

La verdad no me queda muy claro eso voy a colocar el codigo que tengo solo para que me ayudes a depurar errores pero solo faltaria que me explicaras eso que te pido para poder hacer las funciones de valor azar y la de permitido o admisible no entiendo el por que tu tienes otras mas tampoco.
Código:
package Clases;

import java.util.Random;

public class Tratando {

    public static void GeneradorAleatorio() {
       
        int matriz[][] = new int[9][9];
               
        for (int i = 0; i < 9; i++) {
            System.out.println("");
            for (int j = 0; j < 9; j++) {
                System.out.print(matriz[i][j] + "\t");
            }
        }
    }

    public static int [] GetFila(int matriz[][], int fila) {
        int filas[] = new int[9];
        for (int i = 0; i < 9; i++) {
            filas[i] = matriz[fila][i];
        }
        return filas;
    }

    public static int [] GetColumna(int matriz [][], int columna) {
        int columnas[] = new int[9];
        for (int i = 0; i < 9; i++) {
            columnas[i] = matriz[i][columna];
        }
        return columnas;
    }

    public static int [] GetCaja(int matriz[][], int filas, int columnas) {

        int minfila, maxfila;
        int mincolum, maxcolum;

        if (filas >= 0 && filas < 3) {
            minfila = 0;
            maxfila = 2;
        } else if (filas >= 3 && filas < 6) {
            minfila = 3;
            maxfila = 5;
        } else {
            minfila = 6;
            maxfila = 8;
        }

        if (columnas >= 0 && columnas < 3) {
            mincolum = 0;
            maxcolum = 2;
        } else if (columnas >= 3 && columnas < 6) {
            mincolum = 3;
            maxcolum = 5;
        } else {
            mincolum = 6;
            maxcolum = 8;
        }
       
        int caja[] = new int[9];
        int k = 0;

        for (int i = minfila; i < maxfila; i++) {
            for (int j = mincolum; j < maxcolum; j++) {
                caja[k] = matriz[i][j];
                k++;
            }
        }
        return caja;
    }

    public static int[] unificarArray (int filas[], int columnas[], int caja[]) {
       
        int unificado[] = new int[10];
       
        for (int i = 0; i < 9; i++) {
            if (filas[i]>0) {
                unificado[filas[i]] += 1;
            }
            if (columnas[i]>0) {
                unificado[columnas[i]] += 1;
            }
            if (caja[i]>0) {
                unificado[caja[i]] += 1;
            }
        }
        unificado[0] = 0;
       
        for (int i = 1; i < 10; i++) {
            if (unificado[i]>0) {
                unificado[i] = i;
            }
        }
        return unificado;
    }
   
    public static int [] TomarAusentes (int unificado[]){
        int ausentes[] = new int [9];
        int k=0;
        for (int i = 1; i < 10; i++) {
            if (unificado[i] == 0) {
                ausentes[k] = i;
                k++;
            }
        }
        return ausentes;
    }
   
//    public static int ValorAZar (int matriz[][], int i, int j) {
//       
//        Random rand = new Random();
//       
//     
//        return azar[n];
//    }
//    public otra funcion (){
//        int tempfila[];
//        int tempcolum[];
//        int tempcaja[];
//        int tempo[];
//       
//          tempfila = GetFila(matriz, i);
//        tempcolum = GetColumna(matriz, j);
//        tempcaja = GetCaja(matriz, i, j);
//    }
   
    public static void main(String[] args) {

        GeneradorAleatorio();//
       
    }
}
La parte comentada es donde iria las funciones que me faltan por entender.


Título: Re: Codigo para crear SUDOKUS
Publicado por: Serapis en 5 Agosto 2017, 17:04 pm
... pero llegue a un punto que no te entiendo y es la parte final de rellenar el sudoku como lo tienes en el siguiente codigo:

...por que tu hablas de codigo previo y codigo despues ???

Código:
//código previo
           ....el código intermedio (omitido por brevedad)
.... // código después...
Puse 'código previo' y 'código después', para no volver a poner la función completa... En ese tramo, lo que te indicaba era que justo esa parte (de la función) es la que se encarga de que si la 'obtención' de valores llega a un punto donde se bloquea, esa parte CRUCIAL, es la que dando 1, ó 2 pasos atrás, permite salir del bloqueo:
1 paso atrás: elimina toda la fila actual y la rehace.
2 pasos atrás: deshace también la fila previa, si tras deshacer 10 veces la fila actual, no logra avanzar (salir del bloqueo)... un bloqueo 'persistente', se debe a que no deja muchas opciones para la línea actual.

1- cual es ese array sudoku y para que sirve ? no lo entiendo la verdad

2- yo estoy trabajando con una matriz bidimensional y en mi funcion generadoraleatorio() es donde supuestamente lo lleno(Segun mi forma de hacerlo) pero no se en que lugar estaria metiendo este codigo que te muestro arriba el tuyo,
1 - Es el nombre que yo le he dado al array que guarda los valores... tu lo llamas matriz[][] y lo usas de modo bidimensional (filas y columnas, 9x9), yo lo llamo sudoku y usa índices (0 a 80).

2 - Yo hice una función llamada RellenarSudokuAlAzar, que es función principal para generar el sudoku por completo, es desde aquí donde se llama a la segunda función principal (para un solo valor al azar) y en esa donde se llama al resto...

Repongo la función completa, esta función la puse en el 'Respùesta #2' de este hilo  (IMPORTANTE: lee los comentarios en el pseudocódigo):
Código:
Funcion RellenarSudokuAlAzar()    
    Entero Fila, columna
    Byte Valor, Intentos

    Fila=0 // la primera fila, la podrías obtener al azar completamente en ese caso marcar aquí 1, para comenzar en la fila 1, la 0 no va a requerir todas las comprobaciones que pueden requerir las siguientes.
    Hacer  '// esto es fila, puede ser un bucle que va de 0 a 8
        Intentos = 0
        Columna = 0
        Hacer    
            Valor = SeleccionarValorAzar(Columna, Fila)  //la función que obtiene un valor de cada vez.
            Si (Valor>0) luego
                Sudoku((Fila * c_Nueve) + Columna) = valor   //Sudoku() es el array que mantiene internamente los valores.            
                Columna +=1
            Si no
                // Borra los valores de la fila actual
                Bucle para k desde 0 a columna
                    Sudoku((Fila * c_Nueve) + k) = 0
                Fin bucle

                // Tras 10 intentos en la misma fila, borramos también la fila previa
                Intentos += 1
                Si (Intentos = 10) luego
                    Si (Fila > 0) luego  // no podemos retroceder a filas más atrás que la primera.
                        Fila = (Fila - 1) // Borramos también la fila anterior (y si sucede otra vez, la previa, etc...)
                        Bucle para k desde 0 To c_Ocho
                            Sudoku((Fila * c_Nueve) + k) = 0                            
                        Fin Bucle
                    Fin si
                    Intentos = 0
                Fin si
                Columna = 0
            Fin si
        Repetir Mientras (Columna <9)
        Fila +=1
    Repetir Mientra (Fila<9)
Fin Funcion
// Al término de esta función se podría dibujar los valores en el tablero para verificar visualmente el resultado.

3- por otro lado tengo muchas dudas con la funcion de tomar ausentes por que pones como parametro un out NumAusentes

Código:
Array Byte = Funcion TomarAusentes(Array Byte Presentes(), Out Entero NumAusentes)
no entiendo por que pones ese valor ahi, o bueno creo saberlo, lo haces para tener el indice de ese vector pero lo que no se es por que tenerlo de parametro si al llamarlo de otra funcion como lo haces en
Código:
Array byte = GetArrayAusentes(Entero X, Entero Y,  Out Entero NumAusentes)

ese valor no lo utilizas de ninguna manera o por lo menos no lo veo que lo hagas para mi ese valor por parametro no sirve por que el dato que se utiliza es es que devuelve la funcion como tal.
Te aclaro... esta función devuelve un array. El array tiene 9 elementos, pero necesitamos también devolver otro valor. el de cuantos valores en ese array son 'útiles' (detrás de esos valores útiles hay ceros, no nos interesan).
El parámetro es de salida, es decir es devuelve por referencia (por puntero, una dirección de memoria).

Un ejemplo: Imagina una lista de 9 alumnos para el carnet de conducir... se examinan y aprueban solo 3, se devuelve una lista, con sus nombres, pero es preciso saber cuantos son. La lista sigue teniendo 9 elementos, no viene a cuento crear una nueva lista con exactamente los conductores aprobados, la reutilizamos.
Si no sabes pasar un parámetro por referencia, todavía puedes solucionarlo en tu código, recorriendo el array hasta que se encuentre un valor vacío (cero).
Es decir había una lista de 9 alumnos inscritos, creamos otra del mismo tamaño 8por si todos aprobaban), pero luego resulta que aprueban 3, ó 5 o 6, o todos o ninguno)... entonces en la lista entregada leemos nombres, con cada uno leído sumamos 1, cuando no haya más en la lista de aprobados, sabemos ya CUANTOS alumnos aprobaron. 3,5,6,todos, ninguno, etc...

Y porqué necesitamos saber cuantos valores 'útiles' (valores ausentes) tiene la lista?. Pués porque ahora vamos a sortear entre ellos, el elegido será el que se ponga en la casilla.
Si hay 5 valores ausentes (útiles),  (similar a los alumnos aprobados) y ocupan los puestos del 0 al 4, nosotros luego vamos a elegir al azar entre 0 y 4.
SIIIIIIII... elegimos ún índice, porque las funciones aleatorias no saben elegir al azar un valor 2,5,6,9, solo saben elegir un valor dentro de un rango dado, y dentro de ese rango los valores contenidos son elegibles. Si el 3,4,7 y8 quedan fuera del sorteo, significa que no debn ser elegibles, luego toca asignarles un número a los que si optan y luego por ese número (índice en el array), sabemos que valor salió elegido.
Imagina que son esos alumnos, podríamos hacer papelitos con sus nombres, pero OH, nuestro sistemá es matemático (míralo como si tuvieras un bingo de juguete con 100 bolitas, sacas todas y dejas una por cada alumno aprobado) y a cada bola se le asigna un nombre: La bola 0, para Juan, la bola 1 para Luis, la bola 2 par aandrés,etc... entonces hhaces mover el bombo, extraes la bola y cantas la que sale: Bola 2.... a qui
én corresponde? a Andres.... luego Andres salió elegido al azar...

Justo eso esa parte final, es la que hacen las líneas tras la función Tomarausentes:

Este trozo de código es un extracto al final de la función: "SeleccionarValorAzar"
Código:
// OJO: si el array queda vacío <----------- HAY UN BLOQUEO.
    Si (n=0) luego devolver 0 //y salir de la función tras devolver

    // Finalmente se toma un valor al azar entre 0 y n-1, que representa el indice del array Azar. Este array tiene exclusivamente los números que no aparecen ni en la fila, ni en columna, ni en bloque.
    k = Aleatorio( entre 0 y n-1)

    Devolver Azar(k) //ha salido la bola K, devlver el valor contenido en ese índice (si fuera un alumno, sería su nombre).


La verdad no me queda muy claro eso voy a colocar el codigo que tengo solo para que me ayudes a depurar errores pero solo faltaria que me explicaras eso que te pido para poder hacer las funciones de valor azar y la de permitido o admisible no entiendo el por que tu tienes otras mas tampoco.
Creo que debería quedarte todo claro ya...

Verás tu función "GeneradorAleatorio" sería equivalente a la que yo llamo: "RellenarSudokuAlAzar"....
Debe tener 2 bucles, uno por filas y otro interno para columnas. Dentro de ese es que en cada cilo se invoca "SeleccionarValorAzar(fila, columna)" esperando que se le devuelva un valor.
Si es mayor que 0 se asigna al array que mantiene los valores (tu llamas 'Matriz' a tu array, yo le llamo directamente 'Sudoku' a mi array)
Pero si el valor obtenido de regreso es 0, significa que hay una situación de bloqueo. Hay que eliminar la fila actual completa (se suma un intento y si se alcanzan 10 antes de poder completar la fila, se elimina también la fila anterior).


----------------------------------------------
Te comento por encima si veo bien tus funciones, pero debes probarlas siempre. Yo solo reviso la lógica, que es la parte que el IDE (seguramente uses Eclipse), no puede decirte nada...
 
- GeneradorAleatorio: Llámala como prefieras, pero esta función, impleméntala tomando como referencia la que yo llamo "RellenarSudokuAlAzar". Justo te acabo de dar unas palabras al respecto... y el pseudocódigo de la misma te lo he vuelto a poner completo, también más arriba en este mensaje.
 
Citar
 public static void GeneradorAleatorio() {
   
- GetFila: OK
 
Citar
  public static int [] GetFila(int matriz[][], int fila) {
   
- GetColumna: OK
 
Citar
  public static int [] GetColumna(int matriz [][], int columna) {
   
- GetCaja: OK, pero puede optimizarse saber a qué bloque (caja), nos estamos refiriendo (ya te comenté)
  
Citar
 public static int [] GetCaja(int matriz[][], int filas, int columnas) {


- unificarArray: OK, ahora sí...
 
Citar
  public static int[] unificarArray (int filas[], int columnas[], int caja[]) {
   
- TomarAusentes: CASI, te falta devolver el valor de k (yo lo hago por referencia como un parámetro). Si no lo devuelves de ninguna manera, deberás volver a calcular dicho valor en un bucle tras esta función (más arriba ya te comenté esto)  
  
Citar
 public static int [] TomarAusentes (int unificado[]){
       
La parte comentada es donde iria las funciones que me faltan por entender.
OK, en otro mensaje (un poco más tarde, ahora tengo cosas que hacer), te desgrano ambas funciones (son dos, no?): SeleccionarValorAzar y RellenarSudokuAlAzar


Título: Re: Codigo para crear SUDOKUS
Publicado por: Editame en 13 Agosto 2017, 02:36 am
Hola nebire espero que estes bien ...

mira pido disculpas por no haberte comentado nada de hace tiempo pero no me encontraba en la ciudad y no habia podido continuar con este proyecto.

Bueno te comento que sigo un poco perdido con el tema del parametro que pasas donde tienes el out
Código:
Array Byte = Funcion TomarAusentes(Array Byte Presentes(), Out Entero NumAusentes)
entiendo que es el indice del vector ausentes pero no se manejarlo como tu lo haces por ende las ultimas funciones de devolverValorAzar no las hice si no que lo hice como yo pude, por otro lado el metodo generarSudoku ya lo hice si tenias razon era algo muy sencillo probe el codigo hasta donde me deviuelve los valores ausentes y todo esta correcto pero aun asi me sigue presentando el bloqueo y solo me llena aproximadamente unos 36 a 44 valores de ahi no me pasa y no se si es un error en la funcion que devuelve el valorAzar pero no me esta retrocediendo y me esta botando un error que traduce que debe ser positivo.

Te coloco el error completo
Código:
Exception in thread "main" java.lang.IllegalArgumentException: bound must be positive
at java.util.Random.nextInt(Random.java:388)
at Clases.Tratando.SeleccionarValorAzar(Tratando.java:199)
at Clases.Tratando.GeneradorAleatorio(Tratando.java:14)
at Clases.Tratando.main(Tratando.java:205)
C:\Users\Edilberto\AppData\Local\NetBeans\Cache\8.2\executor-snippets\run.xml:53: Java returned: 1
BUILD FAILED (total time: 0 seconds)

y te coloco el sodigo completo de lo que hice

Código:
package Clases;
import java.util.Random;
public class Tratando {

    public static void GeneradorAleatorio() {
       
        int matriz[][];
        int fila = 1, columna, intentos, valor;
        matriz = PrimeraFila();
        do {
            columna = 0;
            intentos = 0;
            do {
                valor  = SeleccionarValorAzar(matriz, fila, columna);
                if (valor > 0) {
                    matriz[fila][columna] = valor;
                    columna++;
                }else{
                    for (int i = 0; i < columna; i++) {
                        matriz[fila][i] = 0;
                    }
                    intentos++;
                    if (intentos == 5) {
                        System.out.println("intentos: " + intentos);
                        if (fila>0) {
                            fila = fila-1;
                            for (int i = 0; i < 8; i++) {
                                matriz[fila][i] = 0;
                            }
                        }
                        intentos = 0;
                    }
                    columna = 0;
                }
            } while (columna < 9);
            fila++;
        } while (fila < 9);
       
        for (int k = 0; k < 9; k++) {
            System.out.println("");
            for (int h = 0; h < 9; h++) {
                System.out.print(matriz[k][h] + "\t");
            }
        }
    }
   
    public static int [][] PrimeraFila() {
       
        int matriz[][] = new int[9][9];
        Random ran = new Random();
        int fila = 0;
        int numero;
        int em=0;
        int cont=0,j;
        int i = 0;
        while (i < 9) {
            numero = 1 + ran.nextInt(9);
            if (em == 0) {
                matriz[fila][i] = numero;
                em++;
            }else{
                cont = 0;
                j = 0;
                while (j < i) {
                    if (numero == matriz[fila][j]) {
                        cont++;
                        break;
                    }else{
                        matriz[fila][i] = numero;
                    }
                    j++;
                }
            }
            if (cont==0) {
                i++;
            }
        }
       
        return matriz;
    }

    public static int [] GetFila(int matriz[][], int fila) {
       
        int filas[] = new int[9];
        System.arraycopy(matriz[fila], 0, filas, 0, 9);
        return filas;
    }

    public static int [] GetColumna(int matriz [][], int columna) {
        int columnas[] = new int[9];
        for (int i = 0; i < 9; i++) {
            columnas[i] = matriz[i][columna];
        }
        return columnas;
    }

    public static int [] GetCaja(int matriz[][], int filas, int columnas) {

        int minfila = 0, maxfila = 0;
        int mincolum = 0, maxcolum = 0;

        if (filas >= 0 && filas < 3) {
            minfila = 0;
            maxfila = 2;
        } else if (filas >= 3 && filas < 6) {
            minfila = 3;
            maxfila = 5;
        } else if (filas >= 7 && filas < 9){
            minfila = 6;
            maxfila = 8;
        }

        if (columnas >= 0 && columnas < 3) {
            mincolum = 0;
            maxcolum = 2;
        } else if (columnas >= 3 && columnas < 6) {
            mincolum = 3;
            maxcolum = 5;
        } else if (columnas >= 7 && columnas < 9){
            mincolum = 6;
            maxcolum = 8;
        }
       
        int caja[] = new int[9];
        int k = 0;

        for (int i = minfila; i <= maxfila; i++) {
            for (int j = mincolum; j <= maxcolum; j++) {
                caja[k] = matriz[i][j];
                k++;
            }
        }
        return caja;
    }

    public static int[] unificarArray (int filas[], int columnas[], int caja[]) {
       
        int unificado[] = new int[10];
       
        for (int i = 0; i < 9; i++) {
            if (filas[i]>0) {
                unificado[filas[i]] += 1;
            }
            if (columnas[i]>0) {
                unificado[columnas[i]] += 1;
            }
            if (caja[i]>0) {
                unificado[caja[i]] += 1;
            }
        }
        unificado[0] = 0;
       
        for (int i = 1; i < 10; i++) {
            if (unificado[i] > 0) {
                unificado[i] = i;
            }
        }
        return unificado;
    }
   
    public static int [] TomarAusentes (int unificado[]){
        int cont = 0;
        for (int i = 1; i < 10; i++) {
            if (unificado[i] == 0) {
                cont++;
            }
        }
       
        int ausentes[] = new int [cont];
       
        int k=0;
        for (int j = 1; j < 10; j++) {
            if (unificado[j] == 0) {
                ausentes[k] = j;
                k++;
            }
        }
       
        return ausentes;
    }
   
    public static int [] GetArrayAusentes (int matriz [][], int x, int y){
        int tempfila[] = GetFila(matriz, x);
        int tempcolum[] = GetColumna(matriz, y);
        int tempcaja [] = GetCaja(matriz, x, y);
       
        int temp [] = unificarArray(tempfila, tempcolum, tempcaja);
       
        return TomarAusentes(temp);
    }
   
    public static int SeleccionarValorAzar (int matriz [][], int x, int y){
        int n;
        int temp[] = GetArrayAusentes(matriz, x, y);
        for (int i = 0; i < temp.length; i++) {
            System.out.print("\n"+temp[i]+"\t");
        }
        Random rand = new Random();
        n = + rand.nextInt(temp.length);
        System.out.println(":" + temp[n]);
        return temp[n];
    }
   
    public static void main(String[] args) {
        GeneradorAleatorio();
    }
}


Título: Re: Codigo para crear SUDOKUS
Publicado por: Editame en 13 Agosto 2017, 22:07 pm
Hola NEbire te doy mil gracias por la ayuda ya logre hacerlo solo me faltaba evaluar cuando el indice de ese arrayazar llegaba a 0 para que devolviera 0 como tu lo tenias,  para asi poder entrar en la parte que corrige el bloqueo, ya pude realizarlo mil gracias por todo.

ahora viene la parte grafica. cuando este terminado o necesite ayuda te comentare e igual lo publicare para que les sirva de guia a los que inicen algo similar


Título: Re: Codigo para crear SUDOKUS
Publicado por: Serapis en 14 Agosto 2017, 00:09 am
Vaya... me alegro, porque te estaba respondiendo y casi había terminado cuando me llamaron para ir a cenar fuera, y a la vuelta he acabado de terminar y enviaba respuesta... de todos modos, la publico...


Vamos por partes....
Citar
mira pido disculpas por no haberte comentado nada de hace tiempo pero no me encontraba en la ciudad y no habia podido continuar con este proyecto.
No te preocupes. Cada uno dispone del tiempo que dispone y nadie tiene derecho a reclamar nada al respecto.


-----------------------
El tema del parámetro de devolución...
Citar
Array Byte = Funcion TomarAusentes(Array Byte Presentes(), Out Entero NumAusentes)
entiendo que es el indice del vector ausentes pero no se manejarlo como tu lo haces
Bien, no importa si no sabes devolver un parámetro por referencia, se recalcula de nuevo, es muy simple...

Varíamos la función, seguimos devolviendo el array y solo el array...
Citar
Array Byte = Funcion TomarAusentes(Array Byte Presentes() )
voy a tu código, donde se llama a todas las funciones y finalmente a TomarAusentes:
Citar
int temp[] = GetArrayAusentes(matriz, x, y);
Ahora entonces hacemos un bucle para tomar el valor que no has sabido devolver:
Código:
Bucle para k desde 1 a 9
  si temp(k) es mayor que cero luego
     NumAusentes = k  // esto se puede hacer de diferentes maneras, esta es la mas sencilla, otra es saliendo del bucle cuando se encuentre un valor 0, etc...
     // se actualiza con cada ocasión que sea cierta la condición, ...no importa es un bucle pequeño.
  Fin si
Fin Bucle
Ya tenemos el valor de NumAusentes.

Ahora la funcion rand.nextInt debe devolver un valor al azar entre 1 y numausentes, pero solo si NumAusentes es mayor que cero
Código:
Si NumAusentes > 0 luego
   azar = rand.nextInt(entre 1 y NumAusentes)  
Si no
   // este es el caso de que no haya números ausentes, se devlvería 0.
Fin si

Cuando una función para devolver un número al azar, no permite especificar un rango, y siempre fuerza desde '0' hasta 'x', se puede truncar... veamos como:
Sea el rango entre 5 y 12, entonces en la función se toma el mismo espacio del rango pero empezando en 0, esto es, si empeiza en 0 y no en 5, es que (es como si) hemos restado 5, luego al valor mayor del rango también le restamos 5. Luego al valor que salga (que será: 0,1,2,3,4,5,6 ó 7), pués le sumamos 5 y efectivamente tendremos el valor en el rango 5-12 , la demostración sencilla sería: (0+5, 1+5, 2+5, 3+5, 4+5, 6+5 ó 7+5), que en efecto es entre 5 y 12
 n = ...rand.nextInt(12-5) + 5  

Unificando un poco el código de esta sección, sería más o menos así
Código:
SeleccionarValorAzar (matriz(), x, y)
        int n, Numausentes
        int temp[] = GetArrayAusentes(matriz, x, y)

        Bucle para i desde 1 a temp.length //OJO: desde 1, porque el indice 0, sabemos que SIEMPRE vale 0
            Si matriz(i) > 0 luego
                NumAusentes = i
            Fin si
        Fin bucle

        Si NumAusentes > 0 luego  //falta esta condición en tu código.
            Random rand = new Random()
            n =  rand.nextInt(Numausentes-1) +1
        
            System.out.println(":" + temp[n])
            return temp[n];
        Si no
            devolver 0
       Fin si
Fin Funcion

-----------------------
Siguiente el error: Si miras la cascada de llamadas hasta el error, (dentro del programa desde main) se llama inicialmente a la función 'GeneradorAleatorio', la cual llama a su vez a 'SeleccionarValorAzar' y en esta se invoca a la función: 'Random.nextInt', que verás que es la última función ejecutada (es la que origina el error)...
Citar
Exception in thread "main" java.lang.IllegalArgumentException: bound must be positive
   at java.util.Random.nextInt(Random.java:388)
Básicamente el error está generado por la elección del número al azar. En el caso de este juego, los valores deben estar comprendidos siempre entre 1 y 9, y específicamente en cada momento concreto entre 1 y 'numausentes'. Ya que lo que elegimos es el índice de aquel array de ausentes y devolvemos el valor contenido en ese indice del array.

Ahora miro el código, para ver por qué dicha función trata de elegir un número negativo.... bien pego la línea donde se origina el error:
Citar
n = + rand.nextInt(temp.length);
...de entrada, el valor pasado a rand.nextInt, no es correcto.
Sabemos que ese array tiene 10 elementos, porque procede de la función TomarAusentes, pero no son elegibles todos los índices, solo son elegibles desde el índice 1 hasta el índice de 'numausentes' (que algunas veces podrá ser 9). Justo lo acabo de explicar en el punto anterior.
Recuerda que el array de TomarAusentes, podría no arrojar valores, porque todos los valores estén ocupados; algunos en la fila, otros en la columna y otros en el bloque.

En ese caso, no hay que forzar a elegir un valor al azar, directamente la función SeleccionarValorAzar  (más arriba puse su pseudocódigo) devuelve 0. Y la función que recibe el resultado (GeneradorAleatorio), ya tiene previsto el caso para solucionar el bloqueo (ese '0', indica el bloqueo).

NOTA: que pongo parcialmente el código de la función (no conviene poner todo un libro, solo para citar 2 párrafos):
              
Código:
...  
                valor  = SeleccionarValorAzar(matriz, fila, columna);
                if (valor > 0) {
                    matriz[fila][columna] = valor;
                    columna++;
                }else{
                   //ResolverBloqueo
                fin si
...

Citar
...por otro lado el metodo 'generarSudoku' ya lo hice si tenias razon era algo muy sencillo probe el codigo hasta donde me devuelve los valores ausentes y todo esta correcto pero aun asi me sigue presentando el bloqueo y solo me llena aproximadamente unos 36 a 44 valores de ahi no me pasa...

Si, bueno, yo lo que veo es que has pueto el límite de intentos en 5, yo lo puse en 12 y luego lo bajé a 10... y lo pongo a generar sudokus (y al tiempo dibujar cada valor generado) durante una hora o algo más y tras 15500 sudokus calculados, lo he parado... es decir no se bloquea. Cambia el número de intentos a 10...

----------------

p.d.: Como ejercicio de optimización, te aclaro que todas las funciones de: getFila, getColumna, getBloque, UnificarArrays y TomarAusentes, puede ser muy optimizado en apenas 5 bucles (uno detrás del otro) usando siempre el mismo y único array, para los 3 get y otro para las otra dos secciones...


Título: Re: Codigo para crear SUDOKUS
Publicado por: Editame en 14 Agosto 2017, 01:13 am
Nebire amigo una pregunta

es correcto hacer esto

Código:
public static void GeneradorAleatorio() {
    .
    .
    .
 GeneradorDePistas(matriz);  // aqui invoco la funcion y le mando la matriz que ya tiene el sudoku resuelto
}

la idea es copiar esa matriz a una matriz2 para trabajar sobre ella lo de las pistas, es decir la cantidad de numeros que va a salir en el sudoku que vamos a resolver

Código:
public static void GeneradorDePistas(int matriz[][]){
        
        int matriz2 [][] = new int [9][9];
        
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                matriz[i][j] = matriz2[i][j];
            }
        }
        
        System.out.println("");
        System.out.println("");
        for (int i = 0; i < 9; i++) {
            System.out.println("");
            for (int j = 0; j < 9; j++) {
                System.out.print(matriz2[i][j] + "\t");
            }
        }
    }

al ejecutarlo de esta funcion no me imprime la copia si no una matriz de solo ceros


Título: Re: Codigo para crear SUDOKUS
Publicado por: Editame en 14 Agosto 2017, 02:04 am
olvida esa pregunta es algo muy tonto tenia que matriz[][] = matriz2[][] claro por eso me imprimia ceros le esta asignando valores de la segunda matriz q estaba vacia que tonteria ...


Título: Re: Codigo para crear SUDOKUS
Publicado por: Serapis en 14 Agosto 2017, 19:15 pm
Sobre las pistas, piensa que teniendo ya resuelto el sudoku, obtener las pistas es simplemente decidir que valores del sudoku dejar ó a la inersa cuales retirar, lo que resulte más breve.

También es preciso saber que si las pistas son menos del 20% de los valores, tiene múltiples soluciones.

Entonces:
- Si un sudoku, tiene una sola solución; la validación la harás con tu matriz del sudoku (resuelta). Comprobando en un bucle que el array Sudoku() (tu le llamas Matriz() ), coincide uno a uno con el array User(). El array User() inicialmente es copia del array Pistas() (por si decide restablecer, se copia de nuevo Pistas() en User()...)
- En cambio si tienes múltiples soluciones, la validación sería recurrir a 1 bucle donde reclamas los ausentes de cada fila, bloque y columna, será validado siempre que en todos los casos dé 0 ausentes.

Código:
Buleano = Funcion ValidarSudokuDeMultiplesSoluciones
    buleano ausentes

    Bucle para k desde 0 a 8
        ausentes = Ausencia (Presencia( GetFila(k) ))
        Si ausentes = false Devolver False //y salir de la función
               
        ausentes = Ausencia (Presencia( GetColumna(k) ))
        Si ausentes = false Devolver False //y salir de la función

        ausentes = Ausencia (Presencia( GetBloque(k) ))
        Si ausentes = false Devolver False //y salir de la función
    Fin bucle
    Devolver True // aparecen todos, una sola vez en fila, columna y bloque.
Fin funcion

NOTA que:
Citar
ausentes = Ausencia (Presencia( Getxxxx(k)))
es una llamada a otra función con la salida de la interna...
Es decir, primero se llama a 'GetXXXX(k) que nos devuelve el array solicitado del array User(). OJO: del array User, no del array Sudoku (Matriz, la llamas tu).
Luego que devuelve ese array es el parámetro de entrada para invocar a la función Presencia(array), y la salida de esta, que también devuelve un array pero de 10 elementos, es usada como la entrada de la función Ausencia(array) que devuelve finalmente un valor buleano.
Es equivalente a esto mismo (pero requiere entonces declarar un array dentro de la función, para recibir y pasar a la siguiente función y más líneas de código).
   
Citar
   array tipo byte Arr() // sería antes del bucle.

   Arr = GetFila(k)
   Arr = Presentes(arr)
   ausentes = Ausencia(arr)

   Si ausentes = false Devolver False //y salir de la función

Esta función ya la conoces, es equivalente a la segunda parte de unificar arrays:
Código:
Array byte = Funcion Presencia(array tipo byte Arr() )
    array tipo byte Tmp(0 a 9) // 10 elementos.

    Bucle para k = 0 a 8
        tmp( arr(k)) = arr(k)
    Fin Bucle
    Devolver Tmp
Fin Funcion

Esta función también la conoces, pero aquí en vez de devolver el array con los ausentes, devolvemos si hay o no ausentes (o la cantidad de ausentes y en destino convertirlo en False si es mayor que 0).
Código:
Buleano = Funcion Ausencia(array tipo byte Presentes() )
    Bucle para k desde 1 a 9 //OJO: 10 elementos, hasta 9
        Si (Presentes(k) <> k) luego
            Devolver FALSE //y salir de la función
        Fin si
    Fin bucle
    Devolver True
Fin funcion

Un último consejo... mira de optimizar el código una vez te funciones bien. Estas dos funciones, podrían llamar a otras que realicen el trabajo 8ya en el código previo) y  aquí solo evaluar el resultado y devolverlo...

No pongo el pseudocódigo de lo que sería la función: 'ValidarSudokuDeUnaSolaSolucion', porque es bastante sencilla.
Ya sabes que puedes ponerle el nombre que quieras a las funciones, siempre que el propio nombre revele su intencionalidad... sin necesidad de llegar a ser tan largo y explícito como: 'ValidarSudokuDeUnaSolaSolucion', que tiene por objeto además ser auto-explicativo... podría ser 'ValidarSolucionSimple' y el otro 'ValidarSolucionMultiple'...

Recuerda que deberás tener varios arrays, como mínimo estos 3:
- El de la Solución (que se genera cuando creas el sudoku).
- El de Pistas (que es una selección-extracción de la solución).
- Y el del Usuario (que inicialmente es copia del array Pistas), y que es donde el usuario va introduciendo los valores que él mismo decida.
Por tanto tras crear el Sudoku (la solución, el array Matriz) satisfactoriamente), tras ello invoca a sendas funciones para inicializar ambos arrays adicionales (pistas y User). Crear el de User también conviene que sea una función aparte, porque si el usuario reclama 'Resetear' la partida, entre otras cosas deberás volver a clonar el array Pistas() en User().


Título: Re: Codigo para crear SUDOKUS
Publicado por: Editame en 14 Agosto 2017, 20:38 pm
Hola amigo

Tenia pensado que solo fuera soluciones unicas por lo tanto el valor minimo de elementos que deben aparecer es de 17 pistas o valores para cada sudoku, si es menos que 17 ya seria de solucion multiple que por ahora no lo tengo comtemplado. por esta razon y tratando de adelantar habia pensado en la dificultad del juego asignado valores o pistas que mostrar para cada una. pero aun no tengo muy claro como hacer para mostrar dicha cantidad de valores de forma aleatoria en la matriz en esas estoy vamos a ver como me va cualquier cosa te sigo avisando.

Buen dia bendiciones.


Título: Re: Codigo para crear SUDOKUS
Publicado por: Serapis en 15 Agosto 2017, 05:49 am
Te respondo por aquí el mensaje privado (útil para todos).

Bien, las pistas pueden ir en efecto entre 17 y las que quieras.
Probablemente alguien que no sea muy entusiasta de las matemáticas y todo lo que sea pensar, necesite la mitad de las casilla como pistas, incluso alguna más...

Yo propondría un límite de 45 pistas como máximo y un mínimo de 17 (para que en efecto tenga una única solución).
Esto implica de alguna manera establecer niveles de dificultad. El nivel de dificultad, va a depender de 3 factores básicos:
A - Número de pistas (cuantas menos, más difícil).
B - Distribución en el 'mapa'.
C - Destribución de valores.

Lo básico es centrarse en el número de pistas, pero de soslayo miramos las otras dos posibilidades.

B - Supongamos que aportamos 27 pistas y que estas se colocan usando exactamente 3 bloques (el 1º, el 5º y el 9º)... esta distribución es algo distinta a si las colocamos de forma aleatoria.
C - Supongamos ahora que las pistas, nos centramos en que valores vamos a colocar (no importa dónde para este caso). Supongamos que sigue siendo 27 pistas, no es lo mismo proporcionar los nueves valores 2,3 y 4 que proporcionar 3 pistas de cada valor (111,222,333,444,555,666,777,888,999), y es disitnto de si los valores son elegidos al azar, puede que haya tres 9, y cuatro 1, pero solo un 5.

Estos dos casos (B y C) es para estudiarlos más a fondo. Su estudio exhaustivo escapa de la ayuda a proporcionar en el foro. A falta de ello es mejor dividirlo en 2 grupos, si son elegidos al azar les concedemos un valor de 'no difícil' y si los elegimos pensando en 'putear' al usuario, le concederíamos un valor de 'difícil'.

Queda por tratar el caso A (el número de pistas). hay que repartirlos en tantos grupos como niveles de dificultad. El reparto no debería ser 'fijo', es decir que aumente la misma cantidad de pistas a medida que baja la dificultad. Ya que esto sería una serie aritmética y es más razonable y ajustado a la realidad una serie serie geométrica.

En matemáticas, una serie se deifne por: un rango de valores llamados términos o medios interpolados, los valores extremos del rango, y la proporción entre cada elemento en el rango, llamada razón.
Si tienes oxidada tus matemáticas, repásalas... busca progresiones aritméticas y progresiones geométricas...

Entonces decidamos cuantos niveles de dificultad queremos tener?. ¿3, 4, 5, 6, 7?. Supongamos 5. Entonces lo primero es crear la serie. Luego esto se fija en un array. el array lo que va a contener será el número de pistas donde comienza ese nivel de dificultad...
Por ejemplo si la serie fuera aritmetica y la razón 5, el array NivDificultad podría tener estos valores.
NivDificultad(0) = 17
NivDificultad(1) = 23
NivDificultad(2) = 29
NivDificultad(3) = 35
NivDificultad(4) = 41
NivDificultad(5) = 47 // este no entra en nivel, es el punto límite.

Entonces si está en el nivel 0 (el más difícil, aunque puede invertirse el número y el más alto expresar más dificultad), se elige una cantidad entre:
NivDificultad(0) y NivDificultad(1)-1
...es decir si elige al azar un número entre 17 y 22
Si nivel 1 entre 23 y 28, etc...

pero... pero hemos elegido una progresión geométrica... Así que cada grupo no tendrá la misma cantidad de valores, pero el enfoque del array y su uso, es el mismo.

Código:
Array Byte = Funcion InterpolacionGeom(Niveles, Minimo, Maximo)
    Decimal Razon, n, p //números con decimales.
    Array Byte Im(0 a Niveles) //Uno más, para guardar el valor final

    razon = RazonGeometrica(Maximo, Minimo, Niveles-1)

    Im(k) = Minimo
    p = im(0)
    Bucle para k desde 1 hasta Niveles-1
       n = p   // Im(k-1) //ídem d elo que se comenta abajo, se pierde precisión y no se alcanza el valor máximo ni lo reparte bien.
       p = (n * razon)
       Im(k) = valor entero de p
       // im(k) = entero de (im(k - 1) * Razon)  
       //podría valer esto, que es una sola línea, pero perdemos precisión en cada iteración. El problema sería tanto mayor cuannto más ciclos tuviere el bucle.
    Fin bucle
    Im(Niveles) = Maximo  //si el código del bucle fue bien esta línea sería inenecesaria,
     //pero si los decimales varían uno arriba o abajo, esto lo fija al punto exacto.
    
    Devolver array Im
Fin Funcion

Generalmente, todos los lenguajes de programación disponen de raíz cuadrada, pero no de raíz cúbica, raíz cuarta ni raíz 125, etc...
Sin embargo, si poseen potenciación y la radicación se define como el inverso de las potencias, al igual que la división es el inverso de las multiplicaciones y la resta el inverso de la suma.
Esto es lo que hacemos aquí:
Código:
Decimal = Funcion RazonGeometrica(Maximo, minimo, Terminos) // terminos intermedios entre ambos extremos
   Devolver ((Maximo/Minimo) elevado a la (1/ (Terminos+1))
Fin Funcion

Una vez que imprimas el resultado del array devuelto, no te vas a sorprender mucho, porque son pocos niveles, también puedes fijar los valores del array 'manualmente', te evitas ambas funciones... pero dejas de aprender cosas.

Tu ya sabiendo que el usuario ha elegido x nivel, seleccionas al azar el número de pistas en cada partida:
NumPistas = Seleccional azar un valor entre( NivDificultad(Dificultad) y NivDificultad(Dificultad+1) -1 )

Y por hoy vale...

p.d.: Espón donde tengas dudas, para no dar vueltas a cosas que no pudierna interesarte e ir al grano.


Título: Re: Codigo para crear SUDOKUS
Publicado por: Serapis en 15 Agosto 2017, 17:36 pm
Tengo una mala noticia...

A pesar de que dicen que si hay más de x pistas, un sudoku solo tiene una solución, puedo demostrar que es falso... sin la necesidad de sesudas matemáticas, basta uno donde se demuestre que efectivamente tiene dos soluciones y x pistas.

En la siguiente imagen, se ve un sudoku correctamente resuelto:
Cada fila hay, bloque y columna cumple la condición. Sin embargo, no me lo da por bueno, si comparo el Sudoku que crea el usuario (en este caso yo), con la solución interna.

Marcado en rojo (y rodeado en azul a mano), las discrepancias que existen con la solución que se generó para el sudoku (en amarillo las pistas, que como se ve son 30ytantas.

En la solución 'real', donde pone 8 es 6 y donde pone 6 es 8 (en ambos casos). Sin embargo este mapa es legítimamente correcto, luego:
queda demostrado como falso
que exista una única solución posible,
cuando el número de pistas es superior a 17.


(http://i.imgur.com/9uHigx9.png)

En consecuencia, es razonable que la solución se verifique no por comparación de la solución almacenada, si no por comprobación de todas las filas, columnas y bloques.

En algún punto hay que poner alguna función que permita al usuario pasar los valores que va marcando y podría ser algo como esto (yo he preferido una propiedad)

Código:
Byte = Propiedad Leer Valor(X, Y)
   n = ((Y * c_Nueve) + X)
   Devolver User(n)
Fin Propiedad

Propiedad Escribir Valor(X, Y, V)
        byte n
        TiposDeValor  t  //una enumeración para indicar al dibujar que tipo de tinta usar
        
        n = ((Y * c_Nueve) + X)
        Si (Pistas(n) = 0) luego  //Si la casilla es una pista, no se toca
            Si (User(n) = 0) luego  //la casilla está ocupada ya?
                Si (v > 0) luego ' que se llena
                    Faltas = (Faltas - 1)  //Descontamos una falta cuando se ingresa un valor, si antes estaba vacía.
                    t = VALOR_TIPO_USER  //la casilla tendrá un valor (1-9)
                Sino
                    t = VALOR_TIPO_VACIO // la casilla se dejará libre.
                Fin si
            Sino  // la casilla ya está ocupada, aquí se cambiará valor o se borrará.
                Si (v = 0) luego
                    Faltas += 1 // antes había un valor, ahora se borra, aumentan las faltas uno más...
                    t = VALOR_TIPO_VACIO // la casilla se dejará libre.
                Sino
                    t = VALOR_TIPO_USER  // se remplaza el valor actual por otro.
                Fin si
            Fin si
            
            User(n) = v  //Asignamos el valor recibido
            
            //valor, casilla(x,y), tipo de tinta a usar
            Disparar Evento DibujarValor(v, X, Y, t)  
            
            Si (Faltas = 0) luego  // Solo se verifica el sudoku, cuando se hayan entrado todos los valores.
                Si (VerificarSudoku = True) luego                    
                    Disparar Evento FinDePartida(True) //True, porqueel mismo evento con False, puede usarse si el usuario decide Resetear la partida.
                Fin si
            Fin si
        Fin si
    Fin Propiedad



Ésta (la siguiente) es una función intermedia, que llama a una u otra para verificar si la solución es corecta, visto lo visto (verificado que NO SIEMPRE existe una UNICA solución), es preferible descartarla e  invocar siempre a  ValidarSolucionMultiple. Y en consecuencia no e spreciso mantener en memoria el array de la solución una vez generado y obtenido las pistas (dicho de otro modo, dicho array podría ser reutilizado para las pistas, eso al gusto)
Código:
Buleano = Funcion VerificarSudoku
    Si  (SolucionUnica = True) luego
        VerificarSudoku = ValidarSolucionSimple
    Sino
        VerificarSudoku = ValidarSolucionMultiple
    Fin si
Fin Funcion

Como decía más arriba:
En consecuencia, es razonable que la solución se verifique no por comparación de la solución almacenada, si no por comprobación de todas las filas, columnas y bloques.




Con ocasión de reponer las imágenes peridas a causa d ela web que las alojaba, aprovecho para editar este último mensaje y añadir aquellas imágenes de la interfaz que le hice... después de crearlas, pero que olvidé ponerlas...

El menú 'partida'...
(https://i.imgur.com/Q7AA2zc.png)


...permite jugar una partida introduciendo las pistas de un sudoku aparecido en otro lado...
En el menú al término (normal o forzado) de una partida, se elige introducir pistas, y luego basta pincha en una casilla en un valor y darle al botón introducir pista, para fijar dicho valor en la casilla seleccionada... cuando se hayan introducido todas, se pulsa en el menú 'fin pistas' y empieza la partida...
(https://i.imgur.com/3Xj0l9P.png)


El menú 'opciones' desplegado:
(https://i.imgur.com/lSaRThm.png)


El menú 'ayuda'... por supuesto, las pistas del sudoku, que aparece en las estadísticas, son reales... para hacer un sudoku.
(https://i.imgur.com/WdCpHCI.png)


Dos partidas en diferente estado, una más cerca del comienzo y otra casi al final:
(https://i.imgur.com/g93rFHk.png)