Como te decía buscando por Kuromaso (o Kurodoku) encontré incluso las reglas originales, ellos añaden dos reglas que francamente no veo de interés aunque si que (en principio, por intuición), parecen dejar menos opciones a múltiples posibles soluciones...
- Las fichas 'rojas' (las de bloqueo), no pueden tocarse sino solo diagonalmente.
- Todas las fichas 'azules' , deben estar conectadas entre sí (es decir impide un grupo aislado por su cuenta).
También utilizan la cuenta total de las fichas vecinas (incluyendo la afectada), pero vamos, respecto de esto es suficiente con que el jugador sepa cual es la cuenta (si se aclara en las normas, es suficiente). A cada cual le parece más natural una cifra o la otra... pero sin más importancia que saberlo para atenerse a ello, en el juego.
...éste juego fue publicado por la revista japonesa Nikoli dedicada a pasatiempos, puzzles... allá por el 1991... el nombre del juego traducido literalmente viene a decir: 'donde están las casillas negras' (ellos juegan con blancas y negras, algo razonable al ser una publicación en papel)...
https://www.nikoli.co.jp/en/puzzles/where_is_black_cells.htmlPero el juego no descarta que haya multiples soluciones... Naturalmente, si restringes como dices las fichas, no es que es sea más difícil, al contrario, es más fácil, porque las posiciones se pueden "deducir" ("forzar", en tus propios términos) y no especular.
Me parece bien que haya más de una solución... Y sí, mi interés viene dado en determinar si es factible fijar niveles de dificultad en base a ello.
Establecer niveles de dificultad en los juegos, suele ser a menudo quizás la parte más complicada de fijar de forma sólida y congruente en un juego, por ejemplo hace escaso días me descargué un juego de ajedrez para el móvil y la sensación clara es que la dificultad la basa en "dejarse comer piezas tontamente" durante el juego (movimientos que una persona no hace salvo un despiste fortuito).
El problema entonces, es que, jugando con las restricciones de las fichas azules, su posición y la aritmética, puedes llegar a restringirlo tanto QUE NO TENGA solución.
Bueno, esto depende de la implementación que se haga, la forma en que lo tengo planteado no se daría ese caso. Aunque sí que habría de requerir más código para suplir esas restricciones.
Tendré que diseñar un algoritmo de inteligencia artificial de expliración de estados (vamos, un backtraking de to la vida, que es cualquier cosa menos inteligente, es pura fuerza bruta) y exponer una combinación que tenga solución.
No lo veo necesario. Ni siquiera un backtracking...
Te expongo mi pseudocódigo...y mejor, también debajo un código que hice ayer en un rato partiendo del mismo (eso sí, en vb6, que es lo que me gusta usar para cositas así).
Paso 0: Establecer cantidades iniciales y el tamaño de los 2 arrays que se usarán...
Partiendo del tamaño del tablero (aunque por defecto sea cuadrado, nada impide que sea rectangular), se calcula la cantidad de bolas/piezas/fichas del tabero.
- Y también cuantas de ellas podrían ser Rojas: (de entrada para probar he puesto un valor elegible al azar entre la raíz cuadrada y 1/3 de la cantidad de piezas del tablero. Si el tablero es cuadrado, lógicamente la raízcuadrada = filas = columnas.
- Así por ejemplo, para un tablero de 6x6=36 bolas, las rojas serían entre 6 y 12... Si salieran 10, entonces las 26 restantes serían azules.
CantidadPiezas = (filas * columnas)
CantidadRojas = random (entre (sqr(Cantidadpiezas) y (Cantidadpiezas\3)) )
CantidadAzules = (CantidadPiezas - CantidadRojas)
// este array se declara del tipo de datos: 'integer' es suficiente.
array Bolas(CantidadPiezas) // unidimensional
// este array se declara del tipo de datos de la enumeración (que pongo) más abajo: ValorCasillas
array Mapa(filas, Columnas) // bidimensional
Paso 1: Llenar el 'bombo de la lotería con todas sus bolas'...Ahorra lleno un array (unidimensional), con todas las bolas que han de componer el tablero, es decir metemos en el saco todos los ingredientes en la cantidad que cada uno deba tener.
Si por ejemplo rojas= 10, entonces azules = 36-10 = 26
Luego el array primero se llena con las rojas en posiciones de 0 a 9, las azules desde 10 hasta 35
Enumeracion ValorCasillas
VACIA=0 // Casilla vacía, cambable por el jugador.
AZUL = 1 // Casilla Azul, cambiable por el jugador.
ROJA = 2 // Casilla Roja, cambiable por el jugador.
AZULFIJA = 3 // Casilla Azul fija (que mostrará el número de contiguas). No es cambiable por el jugador.
ROJAFIJA = 4 // Casilla Roja fija. No es cambiable por el jugador.
AZULFALLO = 5 // Casilla azul un valor transitorio, para indicar al jugador que falla la cuenta.
fin enumeracion
Array bolas(cantidadPiezas)
Bucle para desde 0 hasta Cantidadrojas -1
Bolas(k) = ROJA
siguiente
Bucle para desde Cantidadrojas hasta CantidadPiezas -1
Bolas(k) = AZUL
siguiente
Paso 2: Barajar las bolas del arrayYa están todas en el saco, pero estan ordenadas, así que toca barajarlas, lo hacemos una o mas veces con el algoritmo de Fisher-Yates-Durstenfeld
Para barajar más de 1 vez... basta meterlo dentro de otro bucle.
bucle para k desde (CantidadPiezas - 1) hasta 1 regresivamente
index = random (entre 1 y k)
tmp = Bolas(k): Bolas(k) = Bolas(index): Bolas(index) = tmp
Siguiente
Paso 3: Pasarlas al array bidimensional...Ya están barajadas, pero las tenemos en un array unidimensional, para el juego acomoda tenerlas en uno bidimensional, para no estar contínuamente convirtiendo fias y columnas a un indice absoluto... aunque aclaro que al final se mantienen ambos arrays, cada uno con su propósito (total son muy pequeños y el espacio ocupado es perfectamente asumible).
bucle para j desde 0 hasta filas-1
bucle para k desde 0 hasta columnas-1
Mapa(j, k) = Bolas(n)
n = (n + 1)
Siguiente
Siguiente
Paso 4: Calcular la 'contigüidad' del mapa...Una vez que se han pasado las piezas al array bidimensional se puede dibujar para ver como queda, y entender mejor el siguiente paso.
Ahora lo que vamos a hacer es contar las vecinas de cada azul, y el resultado se deja almacenado en el array unidimensional.
También calcula los puntos de la partida: Sería la suma dle valor que dan todas las casillas con pistas (tomar como puntuación la cantidad de casillas dle mapa, es algo soso).
n = 0: PuntosPartida = 0
Bucle para j desde 0 hasta filas - 1
bucle para k desde 0 hasta columnas-1
Si (Bolas(n) = AZUL)
cuenta = ContarVecinas(j, k) // esta es una función que se pone debajo seguido...
Si (cuenta = 0) // se trata de una bola azul aislada, se convierte a roja.
Mapa(j, k) = ROJA // de momento solo son rojas o azules, no hay fijas ni vacías.
fin si
Bolas(n) = cuenta
PuntosPartida = (PuntosPartida + cuenta)
Sino
Bolas(n) = 0
Fin si
n = (n + 1)
siguiente
Siguiente
La función contarvecinas, simplemente recibe como parámetros fila y columna para contar las azules contiguas a la casilla referida por la intersección de fila y columna.
El algoritmo puede hacerse recursivo, pero resulta más claro de asimilar dejando 4 secciones iterativas.
Cada sección recorre una dirección y sentido de los 4 puntos cardinales, no veo necesario crear una enumeración para esto, pero tampoco sobra si lo deja más claro.
Cada bucle acaba cuando la bola deje de ser 'pseudoAzul' (azul o azulFija) o cuando se alcance el tope del tablero (en la dirección de avance).
Forzamos la entrada en cada bucle, por lo que la casilla de referencia será contada 4 veces (por ello inicialmente la cuenta se establece a -4)
...pero así bastan las condiciones dentro del propio bucle para salir fuera (sin un condicional delante de cada bucle).
En lenguajes donde s epermite especificar límites inferoes a 0, dmensionar el array desde -1 a 1 más de la cantidad, simplifica los bucles, pués las condiciones pueden ponerse juntas al comienzo del bucle, ya que no incurriríamos en un error fuera de rango del array
// Propósito: Cuenta las 'bolas' azules vecinas en la fila y columna para la bola en dicha ubicación, lo que llaman 'visibilidad'...
entero = Funcion ContarVecinas(entero Fila, entero Columna)
entero k, limite, n
n = -4 // se descontará en cada bucle...hasta llegar a 0.
// ------------- Horizontales ----------------
k = Columna
limite = 0
Hacer // Contar vecinas a izquierda...
n = (n + 1)
k = (k - 1)
Si (k < limite) salir del bucle
Repetir Mientras (Mapa(Fila, k) And AZUL) // mientras bola sea azul o azulfija
k = Columna
limite = (Columnas - 1)
Hacer // Contar vecinas a derecha...
n = (n + 1)
k = (k + 1)
Si (k > limite) Salir del bucle
Repetir Mientras (Mapa(Fila, k) And AZUL)
// ------------ Verticales -------------------
k = Fila
limite = 0
Hacer // Contar vecinas hacia arriba...
n = (n + 1)
k = (k - 1)
Si (k < limite) salir del bucle
Repetir Mientras (Mapa(k, Columna) And AZUL)
k = Fila
limite = (Filas - 1)
Hacer // Contar vecinas hacia abajo...
n = (n + 1)
k = (k + 1)
Si (k > limite) salir del bucle
Repetir Mientras (Mapa(k, Columna) And AZUL)
Devolver n
Fin Funcion
El array 'Bolas' ahora tiene por contenido cuantas vecinas a la azul en dicha posición tiene el mapa a la hora de generarlo... y el array mapa, el valor de las casillas actual (roja/azul)
Paso 5: Decidir cuantas y cuales se hacen 'fijas'... El número de fijas (antes) era: entre 1/3 y 1/4 del total (rojas + azules). Cambiado ahora a un poquito más: ((1/4 y (1/3 + filas\2))
Ejemplos:
---- para 04x04= 1/4 = 004; 1/3 = 005, luego se elige un valor entre 004 y (005 + 2) bolas fijas.
---- para 06x06= 1/4 = 009; 1/3 = 012, luego se elige un valor entre 009 y (012 + 03) bolas fijas.
---- para 09x09= 1/4 = 020; 1/3 = 027, luego se elige un valor entre 020 y (027 + 04) bolas fijas.
---- para 25x25= 1/4 = 156; 1/3 = 218, luego se elige un valor entre 156 y (254 + 12) bolas fijas.
Las bolas a mantener fijas se eligen al azar, con las restricciones:
A - Si es azul, el valor de vecindad no puede ser 0 (se elige pués otra). No es preciso aplicarla (se deja comentada) porque en el paso anterior estas se forzaron a ROJA.
B - Si ya está marcada como fija, se elige otra.
C - Fijas azules debe ser mayor que fijas rojas (los tableros más pequeños pueden tener una proporción más similar entre ellas), y proporcionarían pocos datos (esta opción no se refleja en el pseudocódigo, peo si en el código en VB6 más abajo)
Elige al azar un valor entre 1/4 y 1/3. por ejemplo para 6x6= 1/4= 9; 1/3=12, luego se eleige un valor entre 9 y 12 bolas fijas.
Max = (Cantidad \ 3) // en el paso 1, ó 2 ya se calculó esto con el mismo valor.
Min = ((Cantidad \ 4) - 4)
NumPistas = Random (entre Min y Max) + Sqr(Cantidad)
n = 0
Hacer
Hacer
index = Random (entre 0 y Cantidad-1)
// pasar indice absoluto a fila y columna:
j = (index \ Columnas): k = (index Modulo Columnas)
color = s_Mapa(j, k)
Repetir Mientras (color >= AZULFIJA) // la condición B, anotada
// ó ((color = AZUL) y (Bolas(index) = 0)) // la condición A anotada
// Si es azul queda en azul fija, si es roja queda en rojafija
Mapa(j, k) = (Mapa(j, k) + 2)
n = (n + 1)
Repetir Mientras (n < NumPistas)
Paso 6 (y último): Borrar las no fijas del mapa.Ya casi está listo, solo falta borrar bolas para despejar el mapa con bolas vacías. Vacías son pués todas las que no sean fijas...
Los pasos 1 y a 5, son todos de la función MapaGenerar (tablero), este paso también puede ir dentro, pero si se deja fuera porque así puede ser reinvocado por el jugador para borrar todo de un plumazo y volverlo a intentar... por ello se describe como una función aparte:
// Propósito: Borra el estado actual del mapa y lo muestra como al inicio de la partida.
funcion MapaReset()
entero j, k, n
bucle para j desde 0 hasta filas - 1
bucle para k desde 0 hasta Columnas - 1
si (Mapa(j, k) < AZULFIJA) Then
Mapa(j, k) = VACIA
Bolas(n) = 0 // esto s epone a 0, para tolerar disferentes soluciones.
fin si
n = (n + 1)
Siguiente
Siguiente
NumVacias = (n - NumPistas)
llamada a MapaDibujar //ya se puede jugar...
fin funcion
Aclarar también que el código anterior al paso 0, puede dejarse aparte, pués el tamaño de los arrays y por tanto la cantidad de bolas, solo cambia cuando el jugador decide otro valor para filas y/o columnas.
El código es más 'breve' sin tantas explicaciones, claro...
' Crea las bolas, las baraja, las asigna al mapa,
' calcula los valores y decide cuales muestra (y borra el resto).
Private Sub MapaGenerar()
Dim j As Integer, k As Integer, n As Integer, t As Integer
Dim Cantidad As Integer, Max As Integer, Min As Integer
Dim col As ValorCasillas
Cantidad = (p_Columnas * p_Filas)
ReDim r_Bolas(0 To Cantidad - 1)
' 0-Decidir cuantas serán rojas (el resto azules).
Min = Int(Sqr(Cantidad) + 1): Max = (Cantidad / 3)
n = Int((Max - Min + 1) * Rnd + Min) - 1
' 1-Generar las bolas
For k = 0 To (n - 1)
r_Bolas(k) = CASILLA_ROJA ' al principio las las rojas.
Next
For k = n To (Cantidad - 1)
r_Bolas(k) = CASILLA_AZUL ' luego las azules.
Next
' 2-Barajar (2 veces):
For j = 0 To 1
For k = (Cantidad - 1) To 1 Step -1
t = Int((k + 1) * Rnd)
n = r_Bolas(k): r_Bolas(k) = r_Bolas(t): r_Bolas(t) = n
Next
Next
' 3-Pasarlas al mapa bidimensional...
n = 0
For j = 0 To p_Filas - 1
For k = 0 To p_Columnas - 1
s_Mapa(j, k) = r_Bolas(n)
n = (n + 1)
Next
Next
' para debug: ver el estado actual y compararlo una vez resuelto (haciendo captura de éste y aquel)
#If DebugOn = True Then
Call MapaDibujar: Me.Show
#End If
' 4-Calcular el mapa (los valores de suma se guardan en el array 'bolas')
' También calcula los puntos de la partida...
n = 0 ': p_PuntosPartida = 0
For j = 0 To p_Filas - 1
For k = 0 To p_Columnas - 1
If r_Bolas(n) = CASILLA_AZUL Then
t = ContarVecinas(j, k)
If (t = 0) Then ' se trata de una bola azul aislada, se convierte pués a roja.
s_Mapa(j, k) = CASILLA_ROJA
End If
r_Bolas(n) = t
' p_PuntosPartida = (p_PuntosPartida + t) ' si s eprefiere suma de valores más grandes por partida tomar este y comentar el siguiente.
Else
r_Bolas(n) = 0
End If
n = (n + 1)
Next
Next
' 5-Decidir cuantas y cuales se hacen 'fijas'...
Min = (Cantidad \ 4)
Max = ((Cantidad\3) + (Sqr(Cantidad) \ 2))
s_NumPistas = Int((Max - Min + 1) * Rnd + Min)
n = 0: rj=1: p_PuntosPartida = 0
Do
Do
t = Int(s_Cantidad * Rnd)
j = (t \ p_Columnas): k = (t Mod p_Columnas)
Color = s_Mapa(j, k)
Loop While ((Color >= CASILLA_AZUL_FIJA) Or ((Color = CASILLA_ROJA) And (az <= rj)))
' Or ((Color = CASILLA_AZUL) And (r_Bolas(t) = 0)) ' esto ya se garantiza por en un paso previo las azules de vecindad 0 se cambiaron a rojas.
s_Mapa(j, k) = (Color + 2) ' azul+2 = azulFija; roja+2 = rojafija
' Lleva la cuenta de fijas rojas y azules, si la proporción entre ellas no satisface (para la restriccción 'C' )
' Solo resulta de interés en tableros muy pequeños, donde la probabilidad de elgir al azar 4-6 fijas elija demasiadas rojas (nótese que rojas se establece a 1, aún cuando es 0.
' Así se evita que en un tablero de 4x4, salgan 4 fijas y 2 sean rojas).
If (Color = CASILLA_AZUL) Then
az = (az + 1)
Else
rj = (rj + 1)
End If
p_PuntosPartida = (p_PuntosPartida + r_Bolas(t))
n = (n + 1)
Loop While (n < s_NumPistas)
' 6-Borrar las no fijas del mapa.
Call MapaReset
End Sub
' Borra el estado actual del mapa y lo dibuja como al inicio de la partida.
' 6-Borrar las no fijas del mapa.
Private Sub MapaReset()
Dim j As Integer, k As Integer, n As Integer
For j = 0 To p_Filas - 1
For k = 0 To p_Columnas - 1
If (s_Mapa(j, k) < CASILLA_AZUL_FIJA) Then
s_Mapa(j, k) = CASILLA_VACIA
r_Bolas(n) = 0
End If
n = (n + 1)
Next
Next
s_NumVacias = (n - s_NumPistas)
Call MapaDibujar
End Sub
A medida que se pulsan las bolas, se descuentan las vacías, esto es, si una es roja al pulsar pasa a vacía, (sumamos 1 vacía) y al revés cuando es vacía al pulsar pasa a azul, restamos 1 vacía). Así solo se comprueba la solución si no quedan vacías.
Esta sería la función cuando se pulsa en el tablero...
Private Sub PicTablero_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
Dim Fila As Integer, Columna As Integer, color As ValorCasillas
If (s_Jugando = True) Then
Call VerificarBolaFallo // Si había una bola (azul) indicando fallo de suma, se redibuja normal...
Columna = (X \ SIZECASILLA) ' una constante que manrtiene cuantos píxeles ocupa una casilla.
Fila = (Y \ SIZECASILLA)
color = s_Mapa(Fila, Columna)
' vacía, roja y azul, pueden ser cambiadas.
If (color < CASILLA_AZUL_FIJA) Then
' Actualiza la cuenta de casillas vacías...
If (color = CASILLA_VACIA) Then
s_NumVacias = (s_NumVacias - 1)
ElseIf (color = CASILLA_ROJA) Then
s_NumVacias = (s_NumVacias + 1)
End If
color = ((color + 1) Mod 3)
s_Mapa(Fila, Columna) = color
Call DibujarBola(Fila, Columna, color )
Call MapaValidar // La validación solo se realizará si numvacias = 0
Else
Beep
End If
End If
End Sub
Validar si se cumple el mapa.
Aborta si el mapa no está completo aún...
Si llega al final de los bucles, quedó validado, la partida acaba y anota puntos.
Private Sub MapaValidar()
Dim j As Integer, k As Integer, n As Integer
' Es preferible validar solo cuando esté completo, para así saber que ahora se puede dibujar 'Azul_Fallo'...
If (s_NumVacias = 0) Then
For j = 0 To p_Filas - 1
For k = 0 To p_Columnas - 1
' OJO: 'AND' no '=', ya que puede ser Azul=1 o AzulFija =3, azulFallo solo es para dibujar, el estado nunca se establece en el mapa.
If (s_Mapa(j, k) And CASILLA_AZUL) Then ' azul, azulfija, azulfallo
If (r_Bolas(n) > 0) Then
If (ContarVecinas(j, k) <> r_Bolas(n)) Then
Call MarcarBolaFallo(k, j) ' esta bola se dibuja ahora de un modo especial..
Exit Sub
End If
Else ' fuerza una supuesta solución para bolas sin numeración.
' NOTA: el valor asignado en negativo, así con reset no estorban a los valores de fijas pués la suma de su vecindad es positiva (y mayor que 0)
r_Bolas(n) = -ContarVecinas(j, k)
End If
End If
n = (n + 1)
Next
Next
' Al llegar aquí: MapaValidado
Call PartidaFin ' sumará los puntos de partida y solicitará si se quiere jugar otra partida...
End If
End Sub
Un mapa se dibuja (completo) dos veces durante una partida (luego solo se dibuja la bola pulsada):
- La primera vez (justo al incio de partida), mostrará los valores elegidos al azar.
- La segunda vez (justo al final de partida), mostrará (además) los valores ficticios de la solución alternativa (valores menores que 0).
- Tantas otras veces como el jugador haga un 'reset'.
Private Sub MapaDibujar()
Dim j As Integer, k As Integer, n As Integer, t As Integer
For j = 0 To p_Filas - 1
For k = 0 To p_Columnas - 1
If (s_Mapa(j, k) And CASILLA_AZUL) Then
n = Abs(r_Bolas(t)) ' Valor absoluto porque: (las azules no fijas se puso valor negativo al validar).
Else
n = 0
End If
Call DibujarBola(j, k, s_Mapa(j, k), n) ' eel parámetro 'n' indicará que si es mayor que 0, se dibujo también el valor encima de la casilla.
t = (t + 1)
Next
Next
End Sub
En fin, se pueden generar tableros hacia adelante de forma simple sin 'reintentos' ni backtracking... En vez de inventarse valores y luego tratar de buscar un mapa que encaje con los valores se genera un mapa y luego se calculan sus valores, tal como señalaba más arriba en el pseudocódigo y (el código en vb6)
Una modificación interesante (como opción) sería cumplir el requisito de la regla japonesa que especifica que las rojas no pueden estar '4-contiguas', tan solo admitida como diagonal... al caso podría intercalarse entre el paso 3 y el 4, otro bucle que verifique si hay dos rojas contiguas en cuyo caso se puede intercambiar una de ellas por una azul a una fila (en la misma columna) o a una columna (en la misma fila) libre... Dado que el número de rojas es muy inferior al de azules se puede asegurar que siempre puede lograrse...
Y al final unas imágenes de como queda...
La primera imagen es forzado a ser dibujada, tras el paso 3, para ver como es el mapa original (los valores numéricos no reflejan la realidad porque es prematuro disponer de dicho valor):
La segunda imagen es como queda tras el paso 5 (elegir al azar las fijas) y el paso 6 (borrar el resto), listo para empezar la partida:
La tercera es cuando está casi resuelto, las casillas vacías, que se han dejado, puede verse que libremente pueden elegirse si rojas o azules (excepto la de la esquina inferior derecha, que al parecer una regla dice que si una bola azul, no tiene vecinas (está rodeada de rojas, debe ser roja). En mi opinión 'don't care'...
La 4 imagen es la del tablero totalmente resuelto, y puede compararse con la primera, y ver que el mapa es ligeramente distinto (y podría ser lo más si se hubiera elegido otros valores paras las vacías señaladas en la imagen 3). He optado por poner de blanco los números d elas pistas y de negro los números de las 'autocuenta'... (aquellos donde pusimos un valor negativo en las cuentas).
Dicho de otro modo, si se resuelven bien los valores de las pistas se considera resuelto el tablero...
Se me está ocurriendo luego poner un boton de "Me rindo!!!" en el que pulsando salga UNA de las posibles soluciones....
No es mala idea... a mi me pareció interesante que si uno se lía en exceso en vez de tener que borrar una a una, mejor un boton/tecla para borrar todo y dejar el tablero como estaba al inicio (que pueda volver as intentar el mismo tablero)... Útil sobre todo si un mapa es ya de cierto tamaño (10, 20,25 x...).
También debe notarse que el algoritmo de buscar vecinas no está optimizado es simple y funciona bien para tableros de tamaño 'real' con los que un jugador vaya a enfrentarse, pero para tableros de pongamos 1000x1000 casillas sería bastante ineficiente...
Un modo de hacerlo más óptimo (a base de usar más memoria como casi siempre), es disponer de sendos arrays de cuentas adicionales...
Entonces en uno se hace un barrido por filas (en el otro igual pero por columnas): en la fila 1, tras una roja o el comienzo y hasta la siguiente roja o final, todas ellas tienen las vecinas recién calculadas, luego a todo ese grupo se las anota el mismo valor, ejemplo:
AAARRAAAAARARAAARAA
333--55555-1-333-22Bucle para j desde hasta filas-1
n=0
Hacer
Si mapa(j, n) = azul
inicio = n
Hacer
n +=1
Si (n = columnas)
Mapafilas(j, n) = 0 // casilla roja
salir del bucle
fin si
Repetir mientras mapa(j, n) = azul
cuenta = (n - inicio)
Hacer
MapaFilas(j, inicio) = cuenta
inicio +=1
mientras (inicio < n)
sino
Mapafilas(j, n) = 0 // casilla roja
Fin si
n +=1
Repetir mientras (n < columnas)
Siguiente
Igualmente hacer lo mismo en otro array para las columnas, es decir verticalmente.
Ahora la cuenta de vecinas de cada casilla será la suma que arroja la casilla de ambos arrays, para cada casila (-2, pués se ha contado a sí misma 2 veces).
Ahora al validar, se invoca previamente 1 sola vez dicha función (ContarVecinas)...y luego:
Si (Bolas(n) > 0) Then
Si ((MapaFilas(j, k) +MapaColumnas(j,k) -2) <> Bolas(n))
llamada a MarcarBolaFallo(j,k)
Devover false // Salir, validación no pasada...
fin si
....
Así para 1000*1000 bolas, basta una suma, en vez de una búsqueda para contar en una fila de 1000 y en una columna de 1000... (esta búsqueda se hará por tanto 1000+1000 veces y no 1000*1000 veces)
...al final entre código y pesudocódigo, imágenes y explicaciones ha salido un mensaje largo...
p.d.: Editado para reponer 2 imágenes caídas y corregir un pequeño gazapo:
Donde pone:
k = (index \ Filas): j = (index Modulo Columnas)
Debiera poner:
j = (index \ Columnas): k = (index Modulo Columnas)
Primero porque estaban intercambiados los indices ('j' por 'k') y segundo porque si el tablero resultara no ser cuadrado, estaría apuntado a una casilla distinta...