Reconozco que esto es una frikada. Pero el otro día venía dándole vueltas, y pensé: ¿Implementar el algoritmo de cálculo de DNI en Locomotive Basic, el intérprete de Basic que viene con los ordenadores Amstrad de la serie CPC. El algoritmo es muy sencillo: Hay que calcular el resto de la división del número de DNI y 23. Dicho valor sirve para indexar la siguiente tabla y obtener la letra del DNI.
T | R | W | A | G | M | Y | F | P | D | X |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
B | N | J | Z | S | Q | V | H | L | C | K | E |
11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
Hacer esta operación en un ordenador que soporte división entera de 32 bits es muy sencillo. Mi pequeño reto es hacerlo en BASIC del CPC. Esto da para varias limitaciones que hay que tener en cuenta.:
- No se puede usar aritmética en coma flotante
- El Locomotive Basic sólo tiene aritmética entera de 16 bits en complemento a 2
- No quería usar una rutina en código máquina
Tras cerca de 25 años sin tocar el Basic de Amstrad, programando en lenguajes estructurados, tiene su aquel volver a usar números de línea, el goto, colocar el cursor en la pantalla,... e implementar una simple división entre 23 - aquí sí, podemos usar la división entera del Locomotive Basic, ya que como mucho el número mayor a dividir será 207 - y diseñar el pequeño programita en Basic con la siguiente captura y el listado del programa
Y este es el listado en Locomotive Basic que lo genera
' Calcula la letra de DNI
MODE 1
t$="Letra de dni"
msg1$="Pulsa q para salir"
msg2$="Pulsa c para borrar"
msg3$="Pulsa n para nuevo"
dl$="TRWAGMYFPDXBNJZSQVHLCKE"
tlen%=LEN(t$)
xp=(20-tlen%)/2
LOCATE xp,1
PEN 1
PRINT t$
'
PEN 2
LOCATE 1,3
st$="DNI: " + STRING$(8,CHR$(127))
ldni%=LEN(st$)
PRINT st$;
PEN 3
LOCATE ldni% + 2, 3
PRINT CHR$(127);
PEN 1
LOCATE 1,5:PRINT msg1$;
LOCATE 1,6:PRINT msg2$;
' Bucle principal
P%=0
dni$=""
PEN 1
WHILE p%<8
k$=INKEY$
IF k$="" GOTO 300
IF k$="q" THEN 640
IF k$="c" THEN 140
IF ASC(k$) < ASC("0") OR ASC(k$)>ASC("9") THEN PRINT CHR$(7): GOTO 300
p%=p% + 1
dni$ = dni$ + k$
LOCATE 5 + p%,3
PRINT k$;
WEND
inx%=3
div%=(ASC(MID$(dni$,1,1))-ASC("0"))*10
div%=div% + (ASC(MID$(dni$,2,1))-ASC("0"))
' Este bucle funciona porque vamos
' diviendo modulo 23
WHILE inx% < 9
q% = div% \ 23
IF q% <> 0 THEN div% = div% MOD 23
div%=div%*10
div% = div% + (ASC(MID$(dni$,inx%,1))-ASC("0"))
inx%=inx%+1
WEND
r% = (div% MOD 23) + 1
LOCATE ldni%+2,3
PEN 3
PRINT MID$(dl$,r%,1);
LOCATE 1,6:PRINT SPACE$(LEN(msg2$))
LOCATE 1,6:PRINT msg3$;
K$=INKEY$
IF K$="" THEN 580
IF K$="q" THEN 640
IF K$="n" THEN LOCATE 1,6:PRINT SPACE$(LEN(msg3$)):GOTO 130
GOTO 580
' Clear screen
PEN 1
MODE 1
END
Supongo que el siguiente reto será hacerlo en ensamblador de Z80A y Amstrad ;). Veremos si tengo un hueco.