Juego Toledo Atomchess

El juego de ajedrez más pequeño del mundo en código máquina x86, ¡sólo 392 bytes!
Por el 28 de enero de 2015 tuve noticias de un nuevo programa de ajedrez en 487 bytes de código máquina x86. Ni siquiera lo probé y seguí con otras cosas ya que estaba ocupado.
Sin embargo mis amigos del JS1K y Twitter me incitaron a hacer algo al respecto, y tengo algunas nociones de código máquina x86.
Así que empecé a codificar mi propio programa de ajedrez en ensamblador x86, lo acabé en 24 horas y pasé otras 24 horas depurándolo.
Después de esto le di un vistazo a la documentación del otro programa de ajedrez y me sorprendió que hiciera movimientos ilegales y ni siquiera tuviera árbol de búsqueda, para mí eso es casi como no jugar ajedrez.
Así que aquí está, mi juego se llama Toledo Atomchess y en 481 bytes de código máquina x86 juega muy razonablemente con todas las limitaciones.
Mi primera versión de Toledo Atomchess fue de 481 bytes de código máquina x86 y juega muy razonablemente con todas las limitaciones, hace poco vi oportunidades de optimización y lo hice en 456 bytes (7-oct-2015), después en 446 bytes (10-oct-2015) y finalmente 392 bytes (04-mar-2016).

Desarrollo posterior

Recientemente tuve tiempo para investigar la implementación de movimientos completos de ajedrez, incluyendo validación del movimiento del jugador, enroque, captura al paso y coronación (sólo a dama)
Lo llamé Toledo Atomchess Recargado, y requiere 831 bytes de código máquina x86. También incluye un cargador para el segundo sector del disco así que puede arrancarse de un disco flexible.
Mientras lo desarrollaba, descubrí un pequeño defecto que evitaba que Toledo Atomchess moviera sus alfiles en diágonales hacia arriba y otro pequeño y no tan importante en las comparaciones de pila.
Después cambié la sintaxis a la del ensamblador nasm por sugerencia de hellmood y lo subí a Github para controlar más fácilmente los cambios (también dado que no actualizo frecuentemente mi sitio), aquí lo optimicé más y tuve ayuda de qkumba (Peter Ferrie) y theshich.
Y ahora también existe Toledo Atomchess 6502 comprimido en 1K de ROM con tablero gráfico para Atari VCS/2600

Como ejecutarlos

Para correrlo se necesita un disco flexible de 1.44 MB y poner el archivo de 512 bytes en el sector raíz utilizando una utilidad como Rawrite.
El paquete también incluye el juego como un archivo COM que se puede ejecutar en MS-DOS o en la línea de comandos de Wind*ws.
También se puede correr con DosBox o qemu (visto en Reddit coding)
qemu-system-x86_64 -hda toledo_atomchess_disk.bin

Código fuente de Toledo Atomchess

Este es el código fuente completo de Toledo Atomchess en su versión de 446 bytes, para la versión más reciente vea el git de Toledo Atomchess.

        ;
        ; Toledo Atomchess
        ;
        ; por Óscar Toledo Gutiérrez
        ;
        ; © Copyright Óscar Toledo Gutiérrez 2015
        ;
        ; Creación: 28-ene-2015 21:00 tiempo local.
        ; Revisióm: 29-ene-2015 18:17 tiempo local. Terminado.
        ; Revisión: 30-ene-2015 13:34 tiempo local. Depuración finalizada.
        ; Revisión: 01-jun-2015 10:08 tiempo local. Bug solucionado que evitaba que la computadora moviera los alfiles hacia arriba.
        ; Revisión: 06-oct-2015 06:38 tiempo local. Optimización de inicio de tablero/visualización. Y pequeños detalles.
        ; Revisión: 07-oct-2015 14:47 tiempo local. Más optimización y depuración.
        ; Revisión: 10-oct-2015 08:21 tiempo local. Más optimización.

        ; Características:
        ; * La computadora juega movimientos básicos legales del ajedrez ;)
        ; * Introduzca en forma algebraica (D2D4) (no se validan movimientos)
        ; * Profundidad de búsqueda de 3 niveles
        ; * No hay coronación de peones.
        ; * No hay enroque.
        ; * No hay captura al paso.
        ; * Tamaño de 446 bytes (cabe en un sector de arranque)

        ; Nota: Soy lo suficientemente perezoso para escribir mi propio
        ;       ensamblador en lugar de buscar uno, así que disculpará la
        ;       sintaxis usada ;)

        code16

        ; Cambiar a org &0100 para archivo COM
        org &7c00

        ; Limpieza general
        mov sp,stack
        cld
        push cs
        push cs
        push cs
        pop ds
        pop es
        pop ss
        ; Crea el tablero
        mov di,board-8
        mov cx,&0108
sr1:    push di
        pop ax
        and al,&88      ; Tablero 0x88
        jz sr2
        mov al,&07      ; Frontera
sr2:    stosb
        loop sr1
        ; Setup board
        mov si,initial
        mov di,board
        mov cl,&08
sr3:    lodsb           ; Carga pieza
        stosb           ; Piezas negras
        or al,8
        mov [di+&6f],al ; Piezas blancas
        mov byte [di+&0f],&01 ; Peón negro
        mov byte [di+&5f],&09 ; Peón blanco
        loop sr3

        ;
        ; Bucle principal
        ;
sr21:   call display_board
        call key2
        push di
        call key2
        pop si
        call sr28
        call display_board
        mov ch,&08      ; Turno actual (0=blancas, 8=negras)
        call play
        jmp short sr21

        ;
        ; La computadora juega :)
        ;
play:   mov bp,-32768   ; Puntuación actual
        push cx         ; Lado actual
        push bp         ; Cuadro origen
        push bp         ; Cuadro destino

        xor ch,8        ; Cambia lado

        mov si,board
sr7:    lodsb           ; Lee cuadro
        xor al,ch       ; XOR con lado actual que juega
        dec ax
        cmp al,6        ; Ignora si es frontera o vacío
        jnc sr6
        or al,al        ; ¿Es un peón?
        jnz sr8
        or ch,ch        ; ¿Juega negras?
        jnz sr25        ; No, salta
sr8:    inc ax
sr25:   dec si
        add al,&04
        mov dl,al       ; Total de movimientos de pieza en dl
        and dl,&0c
        mov bx,offsets-4
        xlat
        add al,displacement&255
        mov dh,al       ; Offset de movimientos en dh
sr12:   mov di,si       ; Reinicia cuadro destino
        mov bl,dh
        mov cl,[bx]
sr9:    add di,cx
        and di,&ff
        or di,board
        mov al,[si]     ; Contenido de: origen en al, destino en ah
        mov ah,[di]
        or ah,ah        ; ¿Cuadro vacío?
        jz sr10
        xor ah,ch
        sub ah,&09      ; ¿Captura válida?
        cmp ah,&06
        mov ah,[di]
        jnc sr18        ; No, evita
        cmp dh,16+displacement&255       ; ¿Peón?
        jc sr19
        test cl,1       ; ¿Va derecho?
        je sr17         ; Si, evita y cancela movimiento de doble cuadro
        jmp short sr19

sr10:   cmp dh,16+displacement&255       ; ¿Peón?
        jc sr19
        test cl,1       ; ¿Diagonal?
        jne sr18        ; Si, evita

sr19:   push ax         ; Salva para restaurar en futuro cercano
        mov bl,scores&255
        mov al,ah
        and al,7
        cmp al,6        ; ¿Rey capturado?
        jne sr20
        cmp sp,stack-(5+8+5)*2  ; Si en primera respuesta entonces...
        mov bp,20000    ; ...puntos máximos (probable jaquemate/mate ahogado)
        je sr26
        mov bp,7811     ; Máxima puntuación
sr26:   add sp,6        ; Ignora valores
        pop cx          ; Restaura bando
        ret

sr20:   xlat
        cbw
;        cmp sp,stack-(5+8+5+8+5+8+5+8+5)*2  ; Profundidad 4 niveles
        cmp sp,stack-(5+8+5+8+5+8+5)*2  ; Profundidad 3 niveles
;        cmp sp,stack-(5+8+5+8+5)*2  ; Profundidad 2 niveles
;        cmp sp,stack-(5+8+5)*2  ; Profundidad 1 nivel
        jbe sr22
        pusha
        call sr28       ; Realiza movimiento
        call play
        mov bx,sp
        sub [bx+14],bp  ; Substrae BP de AX
        popa
sr22:   cmp bp,ax       ; ¿Mejor puntuación?
        jg sr23         ; No, salta
        xchg ax,bp      ; Nueva mejor puntuación
        jne sr23        ; ¿Misma puntuación?
        in al,(&40)
        cmp al,&aa      ; Inserta aleatoriedad
sr23:   pop ax          ; Restaura el tablero
        mov [si],al
        mov [di],ah
        jg sr18
        add sp,4
        push si         ; Guarda el movimiento
        push di

sr18:   dec ax
        and al,&07      ; ¿Era un peón?
        jz sr11         ; Si, verificación especial
        cmp al,&04      ; ¿Caballo o rey?
        jnc sr14        ; Fin de secuencia, escoge siguiente movimiento
        or ah,ah        ; ¿A cuadro vacío?
        jz sr9          ; Si, sigue línea de cuadros
sr16:   jmp short sr14

sr11:   and cl,&1f      ; ¿Avanzó el primer cuadro?
        cmp cl,&10
        jnz sr14
        mov ax,si       ; Ya verificó que es movimiento a cuadro vacío
        sub al,&20
        cmp al,&40      ; ¿En línea inicial de arriba o abajo?
        jb sr17         ; No, cancela movimiento de doble cuadro
sr14:   inc dh
        dec dl
        jnz sr12
sr17:   inc si
sr6:    cmp si,board+120
        jne sr7
        pop di
        pop si
        pop cx
        cmp sp,stack-2
        jne sr24
        cmp bp,-16384   ; ¿Movimiento ilegal? (siempre en jaque)
        jl sr24         ; Si, no se mueve
sr28:   movsb
        mov byte [si-1],0
sr24:   ret

        ; Ilustra el tablero
display_board:
        mov si,board-8
        mov cx,73       ; 1 frontera + 8 líneas * (8 cols + 1 frontera)
sr4:    lodsb
        mov bx,chars
        xlat
        cmp al,&0d      ; ¿Es RC?
        jnz sr5         ; No, salta
        add si,7        ; Brinca 7 bytes de frontera
        call display    ; Ilustra RC
        mov al,&0a      ; Ahora ilustra LF
sr5:    call display
        loop sr4
        ret

        ; Lee coordenada algebraica
key2:   call key        ; Espera letra
        add ax,board+127 ; Cálcula columna del tablero
        push ax
        call key        ; Espera dígito
        pop di
        shl al,4        ; Substrae dígito de línea multiplicado por 16
        sub di,ax
        ret
key:
        mov ah,0        ; Lee el teclado
        int &16         ; Llama al BIOS
display:
        pusha
        mov ah,&0e      ; Salida de consola
        mov bh,&00
        int &10         ; Llama al BIOS
        popa
        and ax,&0f
        ret

initial:
        db 2,5,3,4,6,3,5,2
scores:
        db 0,10,50,30,90,30

chars:
        db ".prbqnk",&0d,".PRBQNK"

offsets:
        db 16,20,8,12,8,0,8
displacement:
        db -33,-31,-18,-14,14,18,31,33
        db -16,16,-1,1
        db 15,17,-15,-17
        db -15,-17,-16,-32
        db 15,17,16,32

        ; 64 bytes para decir algo
        db "Toledo Atomchess 10oct2015"
        db " (c)2015 Oscar Toledo G. "
        db "nanochess.org"

        ;
        ; Este marcador lo requiere el BIOS para arrancar de disco flexible
        ;
        ds &7dfe-*      ; Cambiar a &02fe para archivo COM
        db &55,&aa

board:  ds 256

        ds 256
stack:
        end

Código fuente de Toledo Atomchess Recargado

Aquí está el código fuente completo para Toledo Atomchess Recargado, incluyendo apoyo para validar el movimiento del jugador, enroque, captura al paso y coronación a dama:

        ;
        ; Toledo Atomchess recargado
        ;
        ; por Óscar Toledo Gutiérrez
        ;
        ; © Copyright Óscar Toledo Gutiérrez 2015
        ;
        ; Creación: 28-ene-2015 21:00 tiempo local.
        ; Revisión: 29-ene-2015 18:17 tiempo local. Terminado.
        ; Revisión: 30-ene-2015 13:34 tiempo local, termina depuración.
        ; Revisión: 26-may-2015. Verifica movimientos ilegales. Maneja
        ;                        coronacion a reina, captura al paso y enroque.
        ; Revisión: 04-jun-2015. Al fin depurado.

        ; Características:
        ; * Movimientos completos del ajedrez (excepto coronación sólo a reina)
        ; * Introduzca movimientos en forma algebraica (D2D4) (todos sus
        ;   movimientos son verificados)
        ; * Búsqueda en profundidad hasta 3 niveles
        ; * Tamaño de 831 bytes (cabe en dos sectores de arranque)

        ; Note: Soy lo bastante flojo para escribir mi propio ensamblador
        ;       en lugar de buscar uno, así que disculpe la sintaxis ;)

        code16

        ; Búsque "REEMPLACE" para cambios para archivo COM
        org &7c00       ; REEMPLACE with ORG &0100

        ; Inicialización
        mov sp,stack
        cld
        push cs
        push cs
        push cs
        pop ds
        pop es
        pop ss
        ; Carga el segundo sector
sr0:    push ds
        push es
        mov ax,&0201
        mov bx,&7e00
        mov cx,&0002
        xor dx,dx
        int &13         ; REEMPLACE con NOP NOP
        pop es
        pop ds
        jb sr0
        ; Crea el tablero
        mov bx,board
sr1:    mov al,bl
        and al,&88      ; Tablero 0x88
        jz sr2
        mov al,&07      ; Frontera
sr2:    mov [bx],al
        inc bl
        jnz sr1
        ; Posiciona las piezas
        mov si,initial
        mov [enp],si    ; Reinicia estado de captura al paso
sr3:    lodsb           ; Lee pieza
        mov [bx],al     ; Piezas negras
        or al,8
        mov [bx+&70],al ; Piezas blancas
        mov al,&11
        mov [bx+&10],al ; Peón negro
        mov al,&19
        mov [bx+&60],al ; Peón blanco
        inc bx
        cmp bl,&08
        jnz sr3

        ;
        ; Bucle principal
        ;
sr21:   call display_board
        call key2
        push di
        call key2
        pop si
        mov ch,&00      ; Turno actual (0=Blanco, 8=Negro)
        call play_validate
        test ch,ch      ; ¿Cambió de turno?
        je sr21         ; No, el movimiento no era válido
        call display_board
        mov ch,&08      ; Turno actual (0=Blanco, 8=Negro)
        dec byte [legal]
        mov word [depth],stack-(4+8+4+8+4+8+4)*2
        call play
        call play_validate
        jmp short sr21

        ;
        ; La computadora juega :)
        ;
play_validate:
        mov byte [legal],1
        mov word [depth],stack-(4+8+4)*2
play:   mov bp,-32768   ; Puntuación actual
        push si         ; Cuadro origen
        push di         ; Cuadro destino

        xor ch,8        ; Cambia de bando

        mov si,board
sr7:    lodsb           ; Lee el cuadro
        xor al,ch       ; XOR con el bando que juega actualmente
        and al,&0f      ; Elimina el bit de pieza movida
        dec ax          ; Traslada a 0-5
        cmp al,6        ; ¿Es frontera o cuadro vacío?
        jnc sr6         ; Sí, salta
        or al,al        ; ¿Es un peón?
        jnz sr8         ; No, salta
        or ch,ch        ; ¿Juega con negras?
        jnz sr25        ; No, salta
sr8:    inc ax          ; Dirección revertida para peón
sr25:   dec si
        mov bx,offsets
        push ax
        xlat
        mov dh,al       ; Offset de movimientos en dh
        pop ax
        add al,total-offsets
        xlat
        mov dl,al       ; Total de movimientos de pieza en dl
sr12:   mov di,si       ; Reinicia el cuadro destino
        mov bx,displacement
        mov al,dh
        xlat
        mov cl,al       ; Offset de desplazamiento en cl
sr9:    add di,cx
        and di,&ff
        or di,board
        mov al,[si]     ; Contenido del cuadro origen en al
        mov ah,[di]     ; Contenido del cuadro destino en ah
        and ah,&0f      ; ¿Cuadro vacío?
        jz sr10         ; Sí, salta
        xor ah,ch
        sub ah,&09      ; ¿Es una captura válida?
        cmp ah,&06
        mov ah,[di]
        jnc sr18        ; No, salta para evitar
        cmp dh,16       ; ¿Moviendo peón?
        jc sr19
        test cl,1       ; ¿Avance recto?
        je sr18         ; Sí, evita
        jmp short sr19

sr10:   cmp dh,16       ; ¿Moviendo peón?
        jc sr19         ; No, salta
        test cl,1       ; ¿En diagonal?
        je sr19         ; No, salta
        mov bx,si
        dec bx
        test cl,2       ; ¿Yendo a la izquierda?
        jne sr29
        inc bx
        inc bx
sr29:   cmp bx,[enp]    ; ¿Es una captura válida al paso?
        jne sr18        ; No, evita

sr19:   push ax         ; Salva los cuadros origen y destino en la pila
        mov al,ah
        and al,7
        cmp al,6        ; ¿Se comió al rey?
        jne sr20
        cmp sp,stack-(4+8+4)*2  ; Si fue en la primera respuesta...
        mov bp,20000    ; ...máxima puntuación (probable jaquemate/ahogado)
        je sr26
        mov bp,7811     ; Puntuación máxima
sr26:   add sp,6        ; Ignora valores
        jmp sr24

sr20:   mov bx,scores
        xlat
        cbw             ; ax = puntuación por captura (garantiza ah = 0)
        mov bx,[enp]    ; bx = peón actual disponible para captura al paso
        cmp sp,[depth]
        jbe sr22
        pusha
        mov [enp],ax    ; Ahora captura al paso no es posible
        mov al,[si]     ; Lee el cuadro origen
        and al,&0f      ; Limpia el bit 4 (marca pieza movida)
        cmp al,&0e      ; ¿Es un rey?
        je sr36
        cmp al,&06
        jne sr37        ; No, salta
sr36:   mov bx,si
        sub bx,di
        mov bh,ch       ; Crea una torre movida
        xor bh,&02      ;
        cmp bl,2        ; ¿Es enroque a la izquierda?
        jne sr38        ; No, salta
        mov [di+1],bh   ; Pone junto al rey
        mov [di-2],ah
        jmp sr37

sr38:   cmp bl,-2       ; ¿Es enroque a la derecha?
        jne sr37
        mov [di-1],bh   ; Pone junto al rey
        mov [di+1],ah
sr37:
        cmp al,&09      ; ¿Es un peón?
        je sr31
        cmp al,&01
        jne sr30        ; No, salta
sr31:   mov bp,sp
        mov bx,di
        cmp bl,&10      ; ¿Llegando a la línea superior?
        jc sr32         ; Sí, salta
        cmp bl,&70      ; ¿Llegando a la línea inferior?
        jc sr33         ; No, salta
sr32:   xor al,&05      ; Corona a reina
        add word [bp+14],90     ; Añade puntos por reina
sr33:   sub bx,si
        call en_passant_test
        jnc sr41
        mov [bx],ah     ; Limpia el peón tomado al paso
        add word [bp+14],10     ; Añade puntos por peón
        jmp sr30

sr41:   and bx,&001f    ; ¿Moviéndose dos cuadros adelante?
        jne sr30        ; No, salta
        mov [enp],di    ; Toma nota de que vale tomarlo al paso
sr30:   mov [di],al
        mov [si],ah     ; Limpia el cuadro origen
        call play
        mov bx,sp
        sub [bx+14],bp  ; Substrae BP (puntos) de AX
        popa

        ;
        ; Si llega a la máxima profundidad entonces el código
        ; llega aquí >sin< mover la pieza
        ;
sr22:   mov [temp],ax
        cmp sp,stack-4*2        ; ¿Primer nivel?
        jnz sr28        ; No, salta
        test byte [legal],255   ; ¿Buscando movimiento legal?
        jz sr28         ; No, salta
        mov bp,sp
        cmp si,[bp+4]   ; ¿El origen es igual?
        jnz sr23
        cmp di,[bp+2]   ; ¿El destino es igual?
        jnz sr23
        cmp ax,-16384   ; ¿Es movimiento legal?
        jl sr23
        add sp,6
        ret

        ;
        ; Nota: La instrucción TEST limpia la bandera de acarreo
        ;
en_passant_test:
        test bl,1       ; ¿Diagonal?
        je sr42         ; No, salta
        test byte [di],255 ; ¿Captura?
        jne sr42        ; Sí, salta
        test bl,2       ; ¿Yendo a la izquierda?
        stc             ; Pone acarreo
        lea bx,[si-1]
        jne sr42
        lea bx,[si+1]
sr42:   ret

displacement:
        db -33,-31,-18,-14,14,18,31,33
        db -16,16,-1,1
        db 15,17,-15,-17
        db -15,-17,-16,-32
        db 15,17,16,32

scores:
        db 0,10,50,30,90,30

        ;
        ; Marcador requerido por BIOS para arrancar el disco flexible.
        ;
        ds &7dfe-*      ; REEMPLACE con nada para archivo COM
        db &55,&aa  ; REEMPLACE con nada para archivo COM

        ; Inicio del segundo sector

sr28:   cmp bp,ax       ; ¿Mejor puntuación?
        jg sr23         ; No, salta
        mov bp,ax       ; Nueva mejor puntuación
        jne sr27
        in al,(&40)
        cmp al,&55      ; Un poco de aleatoriedad
        jb sr23
sr27:   pop ax
        add sp,4
        push si         ; Guarda el movimiento
        push di
        push ax

sr23:   mov [enp],bx    ; Restaura estado de captura al paso
        pop ax          ; Restaura el tablero
        mov [si],al
        mov [di],ah
        mov bx,di
        sub bx,si
        and al,&07      ; Separa el código de pieza
        cmp al,&01      ; ¿Es un peón?
        jne sr43
        call en_passant_test
        jnc sr43
        mov byte [bx],ch ; Limpia
        xor byte [bx],9  ; Restaura peón del oponente

sr43:   cmp al,&06      ; ¿Es un rey?
        jne sr18
        mov bh,ch       ; Crea una torre sin mover
        xor bh,&12      ;
        cmp bl,-2       ; ¿Enroque a la izquierda?
        jne sr40
        mov [di-2],bh
        mov [di+1],ah
        jmp sr18

sr40:   cmp bl,2        ; ¿Enroque a la derecha?
        jne sr18
        mov [di+1],bh
        mov [di-1],ah

sr18:   dec ax
        and al,&07      ; ¿Es un peón?
        jz sr11         ; Sí, verificación especial
        cmp al,&05      ; ¿Es un rey?
        jne sr34        ; No, salta
        test byte [si],&10      ; ¿El rey ya se había movido?
        je sr34         ; Sí, salta
        cmp word [temp],-4096   ; ¿Está en jaque?
        jl sr34         ; Sí, salta
        or ah,ah        ; ¿Se mueve a cuadro vacío?
        jne sr34        ; No, salta
        cmp bl,-1       ; ¿Va a la izquierda por un cuadro?
        je sr44
        cmp bl,1        ; ¿Va a la derecha por un cuadro?
        jne sr34
        mov bh,[si+3]   ; Lee la torre
        mov bl,[si+2]   ; Lee el cuadro destino
        jmp sr46

sr44:   test byte [si-3],255    ; ¿Está vacío el cuadro a la der. de la torre?
        jne sr34        ; No, salta
        mov bh,[si-4]   ; Lee la torre
        mov bl,[si-2]   ; Lee el cuadro destino
sr46:   test bl,bl      ; ¿Finalizando en cuadro vacío?
        jne sr34        ; No, salta
        and bh,&17
        cmp bh,&12      ; ¿Torre sin mover?
        je sr9          ; Sí, puede moverse dos cuadros para enroque

sr34:   cmp al,&04      ; ¿Caballo o rey?
        jnc sr14        ; Termina secuencia, va a siguiente movimiento
        or ah,ah        ; ¿A cuadro vacío?
        jz sr9          ; Sí, sigue línea de cuadros
sr16:   jmp short sr14

sr11:   and cl,&1f      ; ¿Avanzó a primer cuadro?
        cmp cl,&10
        jnz sr14
sr15:   or ah,ah        ; ¿Peón a cuadro vacío?
        jnz sr17        ; No, cancela el movimiento de doble cuadro
        mov ax,si
        sub al,&20      ; ¿En la línea inicial superior?
        cmp al,&40      ; ¿En la línea inicial inferior?
        jb sr17         ; No, cancela el movimiento de doble cuadro
sr14:   inc dh
        dec dl
        jnz sr12
sr17:   inc si
sr6:    cmp si,board+120
        jne sr7
        pop di
        pop si
sr24:   xor ch,8
        ret

display_board:
        ; Ilustra el tablero
        call display3
        mov si,board
sr4:    lodsb
        and al,&0f
        mov bx,chars
        xlat
        call display2
sr5:    cmp si,board+128
        jnz sr4
        ret

key2:
        mov di,board+127
        call key
        add di,ax
        call key
        shl al,4
        sub di,ax
        ret
key:
        push di
        mov ah,0
        int &16
        push ax
        call display
        pop ax
        and ax,&0f
        pop di
        ret

display2:
        cmp al,&0d
        jnz display
display3:
        add si,7
        mov al,&0a
        call display
        mov al,&0d
display:
        push si
        mov ah,&0e
        mov bh,&00
        int &10
        pop si
        ret

chars:
        db ".prbqnk",&0d,".PRBQNK"

initial:
        db &12,&15,&13,&14,&16,&13,&15,&12
offsets:
        db 16,20,8,12,8,0,8
total:
        db  4, 4,4, 4,8,8,8

        ; Bytes to say something
        db "Toledo Atomchess reloaded"
        db "nanochess.org"

        ds &8000-*      ; REEMPLACE con &0500 para archivo COM

board:  ds 256

depth:  ds 2            ; Profundidad de búsqueda
enp:    ds 2            ; Captura al paso
temp:   ds 2            ; Puntuación temporal
legal:  ds 1            ; Bandera que indica validación de movimiento legal
        ds 249
stack:
        end

Ligas relacionadas