EL JUEGO
El objetivo de un SUDOKU es rellenar una cuadrícula de 9x9, que a su vez está dividida en 9 regiones de 3x3, con números de 1 al 9 sin repetir ninguna cifra en la misma fila, columna y región.
El sistema muestra una cantidad de números, que no podemos modificar, y debemos deducir el resto hasta completar todas las casillas.
Controles:
Usa las teclas Q - A - O - P para mover el cursor por la cuadrícula.
Usa los números del 1 al 9 para poner ese número en la posición del cursor.
Pulsa el "0" para borrar el contenido de una celda.
Pulsa "RETURN" para revisar el estado del juego. Se borran los números erróneos y finaliza el juego si no hay fallos.
Pulsa "H" para que el programa ponga el número correcto en la posición del cursor.
Pulsa "R" para mostrar la solución del SUDOKU y finalizar la partida.
Descargar el juego en formato "TAP":
BLOQUES
He dividido el programa en 12 bloques:
- Definición de variables e inicialización.
- Gestión de teclas.
- Posición del cursor: forma y posición.
- Poner número en una celda.
- Mostrar SUDOKU correcto.
- Corregir el SUDOKU introducido.
- Generar un SUDOKU.
- Mostrar el SUDOKU en pantalla.
- Pantalla de presentación.
- Imprimir la cabecera.
- Rutina de pulsar una tecla.
- Lista de SUDOKU correctos para generar las variantes.
COMO FUNCIONA
He optado por estructurar el programa con una instrucción por línea para facilitar su comprensión.
Se utilizan las siguientes variables, principalmente:
V$() = Matriz donde se guardan el SUDOKU resuelto.
T$() = Matriz donde se guarda los números que se ven en pantalla.
M$() = Matriz donde se indican las casillas fijas (1) o modificables (0).
X = Posición horizontal del cursor respecto a las posiciones del tablero.
Y = Posición vertical del cursor respecto a las posiciones del tablero.
El resto de variables son utilizadas en distintos procesos sin ser de ámbito global.
10 - Definimos las matrices.
50 - Llamamos a la rutina que muestra la presentación (3000) y la que genera el SUDOKU (2000).
90 – Llama a la rutina que destaca la celda activa.
100 - Bloque con el que controlamos el teclado para mover el cursor, ayudar, corregir o resolver el SUDOKU.
500 - Calcula la posición del cursor según la casilla activa.
600 - Pone el valor y color de la casilla activa. Si el número es 0 imprime un punto.
700 - Muestra la solución del SUDOKU. Finaliza la partida.
800 - Rutina de revisión del SUDOKU introducido.
840 - En función de los fallos muestra un mensaje u otro.
890 - Si el SUDOKU es correcto (N=0) se acaba el juego y salta a 50.
900 - Si no es correcto salta a 90, que muestra el cursor.
2000 - Seleccionamos uno de los 3 SUDOKU predefinidos y lo cargamos en B$.
2010 - Si un número aleatorio entre 0 y 1 es menos de 0.5 invertimos el tablero diagonalmente.
2030 - Decidimos si rotamos las columnas verticalmente, y cuantas posiciones (0 a 2).
2040 - Decidimos si rotamos las columnas horizontalmente, y cuantas posiciones (0 a 2).
2080 - Guardamos el SUDOKU en las matrices para su posterior control.
2110 - Ocultamos las celdas en función del nivel de dificultad seleccionado (L). N=L*8.
2500 - Mostramos el SUDOKU definitivo en pantalla.
3000 - Mostramos la pantalla de presentación.
3100 - Seleccionamos el nivel de dificultad pidiendo un número entre 1 y 8. Se guarda en (L).
4000 - Borramos la pantalla y ponemos la cabecera en vídeo inverso.
4100 - Rutina que espera a la pulsación de una tecla.
9000 –Líneas DATA donde guardamos los SUDOKU predefinidos. Se pueden entrar todos los que se quieran.
EL PROGRAMA
Código: Seleccionar todo
10 DIM T$(9,9),V$(9,9),M$(9,9)
50 GOSUB 3000:GOSUB 2000:X=1:Y=1
90 GOSUB 600
'
' Gestión Teclas
'
100 GOSUB 4100:GOSUB 640
120 IF K$=CHR$(13) THEN 800
130 IF K$="O" AND X>1 THEN X=X-1
140 IF K$="P" AND X<9 THEN X=X+1
150 IF K$="Q" AND Y>1 THEN Y=Y-1
160 IF K$="A" AND Y<9 THEN Y=Y+1
170 IF K$="R" THEN 700
180 IF K$>="0" AND K$<="9" AND M$(Y,X)="0" THEN GOSUB 620
190 IF K$="H" AND M$(Y,X)="0" THEN K$=V$(Y,X):GOSUB 620
200 GOSUB 600:GOTO 100
'
' Posición Cursor
'
500 P=7702+Y*44+X*2:RETURN
'
' Poner Número
'
600 C=5:IF M$(Y,X)="1" THEN C=2
610 GOTO 650
620 IF K$="0" THEN K$="."
630 T$(Y,X)=K$
640 C=6:IF M$(Y,X)="1" THEN C=0
650 GOSUB 500:POKE P,ASC(T$(Y,X)):POKE 30720+P,C
660 RETURN
'
' Mostrar Sudoku correcto
'
700 FOR Y=1 TO 9:FOR X=1 TO 9
710 IF M$(Y,X)="0" THEN GOSUB 500:POKE P,ASC(V$(Y,X))
720 NEXT X:NEXT Y
730 PRINT "{HOME}{CRSR+DOWN}{RED} TE HAS RENDIDO !!!"
740 GOSUB 4100:GOTO 50
'
' Corregir el Sudoku
'
800 N=0:F=X:I=Y
810 FOR Y=1 TO 9:FOR X=1 TO 9
820 IF T$(Y,X)<>V$(Y,X) THEN N=N+1:K$=".":GOSUB 620
830 NEXT X:NEXT Y
840 IF N=0 THEN C$="{GRN}SUDOKU CORRECTO !!!"
850 IF N>0 THEN C$="{BLU} HAY"+STR$(N)+" ERRORES"
860 PRINT "{HOME}{CRSR+DOWN} "+C$
870 GOSUB 4100
880 PRINT "{HOME}{CRSR+DOWN}{BLK} "
890 IF N=0 THEN 50
900 X=F:Y=I:GOTO 90
' ***************************************
' * Generar el SUDOKU *
' ***************************************
2000 RESTORE:FOR F=1 TO INT(RND(1)*3)+1:READ B$,C$:NEXT F:B$=B$+C$
' Invertir Diagonalmente
2010 IF RND(1)<.5 THEN 2030
2020 C$="":FOR G=81 TO 1 STEP -1:C$=C$+MID$(B$,G,1):NEXT G:B$=C$
' Rotar Verticalmente
2030 N=INT(RND(1)*3):FOR G=0 TO N:B$=RIGHT$(B$,27)+LEFT$(B$,54):NEXT G
' Rotar Horizontalmente
2040 N=INT(RND(1)*3)
2050 FOR G=0 TO N
2060 C$="":FOR F=0 TO 8:I=F*9+1:C$=C$+MID$(B$,I+3,6)+MID$(B$,I,3):NEXT F:B$=C$
2070 NEXT G
' Guardar el tablero en la matriz
2080 N=1:FOR Y=1 TO 9
2090 FOR X=1 TO 9:C$=MID$(B$,N,1):T$(Y,X)=C$:V$(Y,X)=C$:M$(Y,X)="1":N=N+1:NEXT X
2100 NEXT Y
' Ocultar parte de las celdas
2110 N=8*L:FOR F=1 TO N
2120 X=INT(RND(1)*9)+1:Y=INT(RND(1)*9)+1:IF T$(Y,X)="." THEN 2120
2130 T$(Y,X)=".":M$(Y,X)="0":NEXT F
'
' Imprimir el Sudoku Final
'
2500 GOSUB 4000:PRINT " ÚÄÄÄÄÄÂÄÄÄÄÄÂÄÄÄÄÄ¿"
2510 FOR F=1 TO 3
2520 FOR I=1 TO 5:PRINT " ³ ³ ³ ³":NEXT I
2530 IF F<3 THEN PRINT " ÃÄÄÄÄÄÅÄÄÄÄÄÅÄÄÄÄÄ´"
2540 NEXT F
2550 PRINT " ÀÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÙ";
2560 FOR Y=1 TO 9:FOR X=1 TO 9:K$=T$(Y,X):GOSUB 640:NEXT X:NEXT Y
2570 PRINT " [RTN]:Revisar [H]elp "
2580 RETURN
'
' Pantalla de Presentacion
'
3000 GOSUB 4000
3010 PRINT "{CRSR-DOWN}{CRSR-DOWN}CONTROLES:{CRSR-DOWN}"
3020 PRINT "CURSOR: Q-A-O-P"
3030 PRINT "NUMERO: 1-9 0=ANULAR"
3040 PRINT "RENDIR: R"
3100 PRINT "{CRSR-DOWN}{CRSR-DOWN}{CRSR-DOWN}{CRSR-DOWN}DIFICULTAD: 1-8"
3110 GOSUB 4100:IF K$<"1" OR K$>"8" THEN 3110
3120 PRINT "{CRSR-DOWN}{CRSR-DOWN}GENERANDO..."
3130 L=VAL(K$):RETURN
'
' Imprimir la Cabecera
'
4000 PRINT "{CLR}{RVS-ON}{BLK}SUDOKU SCAINET,2013":RETURN
'
' Rutina Pulsar Tecla
'
4100 GET K$:IF K$="" THEN 4100
4110 RETURN
'
' Datos de SUDOKUS Correctos
'
9000 DATA "835416927296857431417293658569134782123678549"
9005 DATA "748529163652781394981345276374962815"
9010 DATA "357964281468123579912587463631795842724318695"
9015 DATA "895246137176459328583672914249831756"
9020 DATA "845967312723814956961532748359178624617243895"
9025 DATA "284659137576491283492386571138725469"
EL PROYECTO
El objetivo del programa consistía en investigar un método para generar SUDOKUS automáticamente, y trasladarlo al BASIC de sistemas de 8 bits. Esto quiere decir que el proceso debía ser rápido y sencillo.
Lo que en un principio parecía algo trivial se convirtió en un quebradero de cabeza. Pero como dicen que más vale “maña que fuerza”, al final he recurrido a una solución más que digna que funciona bien, y sobretodo muy rápidamente.
APUNTES FINALES
Este programa es una adaptación de la versión del SHARP MZ-80B publicada anteriormente, con algunas mejoras para hacerlo caber en los 3.5 KB de RAM del VIC-20.
Diferencias:
- Los datos de los SUDOKU correctos están en líneas DATA en lugar de una matriz, para ahorrar memoria. De esta forma gastamos la mitad de memoria, ya que en la versión anterior los SUDOKU ocupan memoria como líneas de programa y como matrices. En esta versión, en la línea 2000 decidimos que SUDOKU usamos, cargando únicamente uno en memoria y no los tres. Cada SUDOKU ocupa dos líneas ya que el VIC-20 no admite líneas de más de 90 caracteres.
- Las matrices usadas para almacenar el SUDOKU son del tipo cadena y no numéricas. Teniendo en cuenta que solo guardamos una cifra por posición, el uso de matrices numéricas ocupaba unas 6 o 7 veces más memoria, no dejando espacio para el programa en si.
- Esta versión es en color, haciendo que las cifras fijas sean de color negro y las variables de color azul. La dígito de la celda activa es verde si nos permite modificarlo o roja si es fijo.
Por el resto, la funcionalidad de esta versión es idéntica a la original del SHARP MZ-80B.
Respecto al BASIC, esta versión es casi idéntica a la original. Las únicas modificaciones afectan a todo lo relacionado con la pantalla, ya que el BASIC del VIC-20 no permite (de una forma sencilla) situarse en una posición concreta de la pantalla. Aquí he POKEado directamente la memoria de video, tanto para los caracteres como para el color.
El programa ocupa unos 2.2 KB de RAM y durante la ejecución solo deja libres unos 160 bytes, con lo que quedaría memoria para introducir algún SUDOKU más.
Para terminar, decir que hacía 20 años que no programaba nada en el VIC-20, y ya no recordaba lo poco cómodo que es trabajar con una pantalla con tan pocas columnas. Sus 23 filas x 22 columnas son un engorro. Pero el SUDOKU ha quedado bastante bien...
Os invito a probarlo.