Vistas de página en total

Mostrando entradas con la etiqueta JUEGO. Mostrar todas las entradas
Mostrando entradas con la etiqueta JUEGO. Mostrar todas las entradas

jueves, 15 de agosto de 2013

TIC_TAC_TOE ( TASM 2.0)

      Aquí está el TIC_TAC_TOE hecho usando las directivas TASM 2.0 y la nueva rutina waitmousexy.

    Espero que os guste.

TIC_TAC_TOE.ASM
; Copyright (C) 2013  José Ángel Moneo Fernández

;    This program is free software: you can redistribute it and/or modify
;    it under the terms of the GNU General Public License as published by
;    the Free Software Foundation, either version 3 of the License, or
;   (at your option) any later version.

;    This program is distributed in the hope that it will be useful,
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;    GNU General Public License for more details.

;    You should have received a copy of the GNU General Public License
;    along with this program.  If not, see <http://www.gnu.org/licenses/>.



title tic_tac_toe

include main.mac
include stdio.mac
include string.mac
include time.mac
include mouse.mac

.286  ; para poder usar shr al,3

tablero macro jugador,simbolo
        push bx
        mov bl,jugador
        mov bh,simbolo
        call _tablero
        pop bx
endm

.model compact,pascal

.stack 100

.data
;Mapa de juego
;significado tabla
;     oponente,respuesta,siguiente lista(2 byte)
;significado siguiente lista si
;   offset ->continual el juego en otro nivel
;   0-> ha finalizado el juego
;   1->  si la situación de la máquina es 30h
;   2->  si la situación de la máquina es 90H
;significado respuesta
;   si <>0 es posición de respuesta
;   si =0 no hay respuesta. Son tablas


nivel1  db 80h,20h
            dw offset n2_20h
        db 40h,20h
            dw offset n2_20h
        db 20h,80h
            dw offset n2_80h
        db 10h,80h
            dw offset n2_80h
        db 8,10h
            dw offset n2_10h
        db 4,80h
            dw offset n2_80h
        db 2,40h
            dw offset n2_40h
        db 1,40h
            dw offset n2_40h
       
n2_10h db 9,40h
           dw offset n3_40h
       db 88h,1,0,0
       db 48h,1,0,0
       db 28h,1,0,0
       db 0ch,1,0,0
       db 0ah,1,0,0
       dd 0


n2_20h db 84h,10h
          dw offset n3_10h_1
       db 44h,10h
          dw offset n3_10h_2
       db 0c0h,4,0,0
       db 90h,4,0,0
       db 88h,4,0,0
       db 82h,4,0,0
       db 81h,4,0,0
       db 50h,4,0,0
       db 48h,4,0,0
       db 42h,4,0,0
       db 41h,4,0,0
       dd 0

n2_40h db 82h,10h
            dw offset n3_10h_3
       db 81h,4
            dw offset n3_4h
       db 22h,80h,0,0
       db 21h,80h,0,0
       db 12h,80h,0,0
       db 11h,80h,0,0
       db 0ah,80h,0,0
       db 9,80h,0,0
       db 6,80h,0,0
       db 5,80h,0,0
       db 3,80h,0,0
       dd 0

n2_80h db 60h,10h
            dw offset n3_10h_3
       db 44h,10h
            dw offset n3_10h_3
       db 50h,4
            dw offset n3_4h
       db 30h,40h,0,0
       db 28h,40h,0,0
       db 24h,40h,0,0
       db 22h,40h,0,0
       db 21h,40h,0,0
       db 0ch,40h,0,0
       db 18h,40h,0,0
       db 14h,40h,0,0
       db 12h,40h,0,0
       db 11h,40h,0,0
       db 6,40h,0,0
       db 5,40h,0,0
       dd 0

n3_4h db 70h,8
         dw offset n4_8h
      db 58h,20h,0,0
      db 52h,20h,0,0
      db 51h,20h,0,0
      db 0a1h,10h,0,0
      db 91h,20h,0,0
      db 89h,20h,0,0
      db 83h,20h,0,0
     

n3_10h_1 db 0c4h,8,0,0           
       db 85h,8,0,0 
       db 8ch,1,0,0
       db 86h,8,0,0 
       dd 0

n3_10h_2 db 0c4h,8,0,0
       db 4ch,1,0,0
       db 86h,8,0,0
       db 85,8,0,0
       dd 0

n3_10h_3 db 0c4h,2,0,0
       db 0c2h,1,0,0
       db 0c8h,2,0,0
       db 0c1h,2,0,0
       db 4ch,2,0,0
       db 86h,1,0,0
       db 85h,2,0,0
       db 8ah,4,0,0
       db 83h,4,0,0
       db 0a2h,4,0,0
       db 61h,2,0,0
       db 62h,1,0,0
       db 64h,2,0,0
       db 68h,2,0,0
       db 46h,1,0,0
       db 45h,2,0,0
       dd 0


n3_40h db 89h,4,0,0
       db 29h,80h,0,0 
       db 0dh,80h,0,0
       db 0bh,80h,0,0 
       dd 0
      
n4_8h  db 72h,1,1,0
       db 71h,2,1,0
       dd 0
     
      
nivel_act dw 0 ; almacen de puntero de nivel actual       
maquina db 0 ; situación de la maquina
oponente db 0 ; situación del oponente
ocupados db 0 ; estado ocupados
    
estado db 0; estado partida
posx db 0   ; posicion pulsación del raton
posy db 0
raton dw 0


titulo db "TRES EN LINEA",0
ayuda db "PULSA CON EL RATON EN LA POSICION DESEADA",0
m_gana db "Lo siento has perdido.",0
m_tablas db "Esta partida son tablas",0
m_error db " Ha surgido un error",0

tablero1 db 201,205,203,205,203,205,187,0 ; "╔═╦═╦═╗"
Tablero2 db 186,32,186,32,186,32,186,0      ; "║ ║ ║ ║"
Tablero3 db 204,205,206,205,206,205,185,0   ; "╠═╬═╬═╣"
Tablero4 db 200,205,202,205,202,205,188,0   ; "╚═╩═╩═╝

NW_intento db "Quieres intentarlo de nuevo? S/N",0

.code
tic_tac_toe proc far
        main   ; inicia 
        setcursor off
        resmouse
        mouse off
        putmouse 8,8
nw:
;inicia tablero 
        clrscr
        gotoxy 9,1
        puts titulo
        gotoxy 9,2
        puts ayuda
        gotoxy 9,3   
        puts tablero1
        gotoxy 9,4
        puts tablero2
        gotoxy 9,5
        puts tablero3
        gotoxy 9,6
        puts tablero2
        gotoxy 9,7
        puts tablero3       
        gotoxy 9,8
        puts tablero2       
        gotoxy 9,9
        puts tablero4
        gotoxy 10,4
        putchar 'X'
        mov maquina,0
        mov oponente,0
        mov nivel_act,offset nivel1
        
otra:      
        tablero oponente,'O'
        tablero maquina,'X'


;espera seleccion oponente 
        mouse on
espera:  
        waitmousexy 10,4,4,4
        cmp al,0ffh
        jz espera
        shr ah,1          ; divide por 2 ya que el tablero es de dos caracteres
        mov posx,ah
        shr al,1 ; divide por 2 ya que el tablero es de dos caracteres
        mov posy,al


     ;coloca el bit
        mov al,posy    ; posy*3+posx
        add al,posy
        add al,posy
        add al,posx

        cmp al,8       ; si pulsamos fuera no procesamos
        ja espera

        mov cl,al
        xor al,al   ; borra al
        stc    ; carry a 1
        rcr al,cl      ; situa el bit elegido
        ; comprueba que no esté seleccionada ya
     
        mov ah,oponente
        or ah,maquina
        mov ocupados,ah
        or ah,al     ;montamos nuevo bit
        cmp ah,ocupados   ; ha añadido bit nuevo?
        je  espera ; si no añade bit nuevo la posición está ya estaba ocupada
         
        or oponente,al   ; guarda la jugada
        call ver_respuesta
;presentamos la nueva posición del tablero
         ;si estado = 4 sigue el juego
        cmp estado,4
        jne sig01
        jmp otra  
sig01:
       ;si estado=6 gana
        cmp estado,6 
        je gano
        cmp estado,0ffh
        jne acierto
        gotoxy 10,20         ;error
        puts m_error 
        jmp acabo
      
acierto:
       ;si estado=7 tablas
        gotoxy 10,20         ;ha acertado
        puts m_tablas  
        jmp acabo
gano:
        mouse off
        gotoxy 10,20         ;ha acertado
        puts m_gana  
acabo:       
        tablero oponente,'O'
        tablero maquina,'X'
        gotoxy 10,21
        puts nw_intento
        getch al             ;espera pulsación antes de salir
        upr                   ;convierte al en mayusculas
        cmp al,'S'
        jne  salir
        jmp nw
salir: setcursor on
        mouse off
        exit 0

tic_tac_toe endp


proc ver_respuesta 
; busca la respuesta a la situación del oponente en la tabla correspondiente
; se pasa la dirección de la tabla en si
; devuelve estado=7 si gana, estado=6 si tablas y estado=4 si sigue el juego
;    0ffh= error
        mov si,nivel_act
comprueba:
        mov al,[si]    ;posibilidad
        cmp al,0        ;error fin de lista. No hay acción
        jne n_error
        mov estado,0ffh   ; marca error
        ret
n_error:
        cmp oponente,al  ;es la jugada hecha?
        je encontrado
sig_estado:
        add si,4   ; siguiente estado
        jmp comprueba
encontrado:
        mov al,[si+1]
        or maquina,al    ;añade al tablero de la máquina la jugada correspondiente
        mov ax,[si+2]    ;dato siguiente estado
        cmp ax,0          ;fin de la partida
        je _fin
        cmp ax,1        ;tablas
        je _fin

        mov nivel_act,ax     ;pasamos el puntero del nivel a la lista del siguiente nivel
        xor al,al
        jmp _fin_ver


_fin:   or  al,2      ; devuelve al=6 si gana y al=7 si tablas
_fin_ver:              
        or  al,4      ;devuelve al=4 si sigue el juego
        mov estado,al
ret
ver_respuesta endp

proc _tablero
; oponente viene en bl, y el simbolo a imprimir en bh
        mouse off
        shl bl,1
        jnc c2
        gotoxy 12,4
        putchar bh
c2:
        shl bl,1
        jnc c3
        gotoxy 14,4
        putchar bh
c3:
        shl bl,1
        jnc c4
        gotoxy 10,6
        putchar bh
c4:       
        shl bl,1
        jnc c5
        gotoxy 12,6
        putchar bh
c5:
        shl bl,1
        jnc c6
        gotoxy 14,6
        putchar bh
c6:
        shl bl,1
        jnc c7
        gotoxy 10,8
        putchar bh
c7:
        shl bl,1
        jnc c8
        gotoxy 12,8
        putchar bh
c8:
        shl bl,1
        jnc c9
        gotoxy 14,8
        putchar bh
c9:
        mouse on
        ret
_tablero endp

end tic_tac_toe

miércoles, 7 de agosto de 2013

TIC_TAC_TOE (5/5)

     Aquí está por fin el juego TIC_TAC_TOE completo, aunque simplificable mediante la posterior rutina getmousexy.
 
      Esta es al última entrada hecha con mis directivas _data,_code, _rutina. A partir de la siguiente entrada de blog, comenzaré a usar las directivas de TASM. Una vez declarada la función getmousexy, volveré a colocar este juego, pero ya totalmente en TASM 2.0

     En este caso veis como introducimos al comienzo una macro. Esta macro nos permite definir una nueva instrucción (tablero), mediante la cual pasamos los parámetros a la rutina _tablero.


TIC_TAC_TOE.ASM

; Copyright (C) 2013  José Ángel Moneo Fernández

;    This program is free software: you can redistribute it and/or modify
;    it under the terms of the GNU General Public License as published by
;    the Free Software Foundation, either version 3 of the License, or
;   (at your option) any later version.

;    This program is distributed in the hope that it will be useful,
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;    GNU General Public License for more details.

;    You should have received a copy of the GNU General Public License
;    along with this program.  If not, see <http://www.gnu.org/licenses/>.


title tic_tac_toe

include main.mac
include stdio.mac
include string.mac
include time.mac
include mouse.mac

.286  ; para poder usar shr al,3

; macro para crear la instrución de dibujo de tablero
tablero macro jugador,simbolo
        push bx
        mov bl,jugador
        mov bh,simbolo
        call _tablero
        pop bx
endm

_modelo exe

_stack 250

_data
;Mapa de juego
;significado tabla
;     oponente,respuesta,siguiente lista(2 byte)
;significado siguiente lista si
;   offset ->continual el juego en otro nivel
;   0-> ha finalizado el juego
;   1->  si la situación de la máquina es 30h
;   2->  si la situación de la máquina es 90H
;significado respuesta
;   si <>0 es posición de respuesta
;   si =0 no hay respuesta. Son tablas



nivel1  db 80h,20h
            dw offset n2_20h
        db 40h,20h
            dw offset n2_20h
        db 20h,80h
            dw offset n2_80h
        db 10h,80h
            dw offset n2_80h
        db 8,10h
            dw offset n2_10h
        db 4,80h
            dw offset n2_80h
        db 2,40h
            dw offset n2_40h
        db 1,40h
            dw offset n2_40h

;revisado      
n2_10h db 9,40h
           dw offset n3_40h
       db 88h,1,0,0
       db 48h,1,0,0
       db 28h,1,0,0
       db 0ch,1,0,0
       db 0ah,1,0,0
       dd 0


n2_20h db 84h,10h
          dw offset n3_10h_1
       db 44h,10h
          dw offset n3_10h_2
       db 0c0h,4,0,0
       db 90h,4,0,0
       db 88h,4,0,0
       db 82h,4,0,0
       db 81h,4,0,0
       db 50h,4,0,0
       db 48h,4,0,0
       db 42h,4,0,0
       db 41h,4,0,0
       dd 0

;revisado
n2_40h db 82h,10h
            dw offset n3_10h_3
       db 81h,4
            dw offset n3_4h
       db 22h,80h,0,0
       db 21h,80h,0,0
       db 12h,80h,0,0
       db 11h,80h,0,0
       db 0ah,80h,0,0
       db 9,80h,0,0
       db 6,80h,0,0
       db 5,80h,0,0
       db 3,80h,0,0
       dd 0


n2_80h db 60h,10h
            dw offset n3_10h_3
       db 44h,10h
            dw offset n3_10h_3
       db 50h,4
            dw offset n3_4h
       db 30h,40h,0,0
       db 28h,40h,0,0
       db 24h,40h,0,0
       db 22h,40h,0,0
       db 21h,40h,0,0
       db 0ch,40h,0,0
       db 18h,40h,0,0
       db 14h,40h,0,0
       db 12h,40h,0,0
       db 11h,40h,0,0
       db 6,40h,0,0
       db 5,40h,0,0
       dd 0

n3_4h db 70h,8
         dw offset n4_8h
      db 58h,20h,0,0
      db 52h,20h,0,0
      db 51h,20h,0,0
      db 0a1h,10h,0,0
      db 91h,20h,0,0
      db 89h,20h,0,0
      db 83h,20h,0,0
   

n3_10h_1 db 0c4h,8,0        
       db 85h,8,0,0
       db 8ch,1,0,0
       db 86h,8,0,0
       dd 0

n3_10h_2 db 0c4h,8,0,0
       db 4ch,1,0,0
       db 86h,8,0,0
       db 85,8,0,0
       dd 0

n3_10h_3 db 0c4h,2,0,0
       db 0c2h,1,0,0
       db 0c8h,2,0,0
       db 0c1h,2,0,0
       db 4ch,2,0,0
       db 86h,1,0,0
       db 85h,2,0,0
       db 8ah,4,0,0
       db 83h,4,0,0
       db 0a2h,4,0,0
       db 61h,2,0,0
       db 62h,1,0,0
       db 64h,2,0,0
       db 68h,2,0,0
       db 46h,1,0,0
       db 45h,2,0,0
       dd 0



n3_40h db 89h,4,0,0
       db 29h,80h,0,0
       db 0dh,80h,0,0
       db 0bh,80h,0,0
       dd 0
   
n4_8h  db 72h,1,1,0
       db 71h,2,1,0
       dd 0
   
   
nivel_act dw 0 ; almacen de puntero de nivel actual    
maquina db 0 ; situación de la maquina
oponente db 0 ; situación del oponente
ocupados db 0 ; estado ocupados
 
estado db 0; estado partida
posx db 0   ; posicion pulsación del raton
posy db 0
raton dw 0


titulo db "TRES EN LINEA",0
ayuda db "PULSA CON EL RATON EN LA POSICION DESEADA",0
m_gana db "Lo siento has perdido.",0
m_tablas db "Esta partida son tablas",0
m_error db " Ha surgido un error",0

tablero1 db 201,205,203,205,203,205,187,0 ; "╔═╦═╦═╗"
Tablero2 db 186,32,186,32,186,32,186,0      ; "║ ║ ║ ║"
Tablero3 db 204,205,206,205,206,205,185,0   ; "╠═╬═╬═╣"
Tablero4 db 200,205,202,205,202,205,188,0   ; "╚═╩═╩═╝

NW_intento db "Quieres intentarlo de nuevo? S/N",0

_code
tic_tac_toe proc far
        main   ; inicia
        setcursor off
        resmouse
        mouse off
        putmouse 8,8
nw:
;inicia tablero
        clrscr
        gotoxy 9,1
        puts titulo
        gotoxy 9,2
        puts ayuda
        gotoxy 9,3
        puts tablero1
        gotoxy 9,4
        puts tablero2
        gotoxy 9,5
        puts tablero3
        gotoxy 9,6
        puts tablero2
        gotoxy 9,7
        puts tablero3    
        gotoxy 9,8
        puts tablero2    
        gotoxy 9,9
        puts tablero4
        gotoxy 10,4
        putchar 'X'
        mov maquina,0
        mov oponente,0
        mov nivel_act,offset nivel1
     
otra:    
        tablero oponente,'O'
        tablero maquina,'X'


;espera seleccion oponente
        mouse on
espera:
        getmouse                ;comprueba el estado del raton
        cmp ax,1
        jnz actual              ;si no se ha pulsado se espera
        cmp ax,raton            ;si se pulso se verifica si ha sido un
        mov raton,ax            ;flanco de subida
        jnz  seleccion           ;si es asi se selecciona la opcion deseada
actual:
        mov raton,ax
        jmp espera
seleccion:
     ;toma la coordenada
        getmousex
        shr ax,4 ;divide por 16 para obtener coordenada letra
        sub ax,5 ;referencia desde cero de la posicion en la matriz
        cmp al,2  ;no valido si pulsamos fuera
        ja espera
        mov posx,al
        getmousey
        shr ax,4 ;divide por 16 para obtener coordenada letra
        sub ax,2 ;referencia desde cero de la posicion en la matriz
        cmp al,2    ;no valido si pulsamos fuera
        ja espera
        mov posy,al
     ;coloca el bit
        mov al,posy    ; posy*3+posx
        add al,posy
        add al,posy
        add al,posx

        cmp al,8       ; si pulsamos fuera no procesamos
        ja espera

        mov cl,al
        xor al,al   ; borra al
        stc    ; carry a 1
        rcr al,cl      ; situa el bit elegido
        ; comprueba que no esté seleccionada ya
   
        mov ah,oponente
        or ah,maquina
        mov ocupados,ah
        or ah,al     ;montamos nuevo bit
        cmp ah,ocupados   ; ha añadido bit nuevo?
        je  espera ; si no añade bit nuevo la posición está ya estaba ocupada
       
        or oponente,al   ; guarda la jugada
        call ver_respuesta
;presentamos la nueva posición del tablero
         ;si estado = 4 sigue el juego
        cmp estado,4
        jne sig01
        jmp otra
sig01:
       ;si estado=6 gana
        cmp estado,6
        je gano
        cmp estado,0ffh
        jne acierto
        gotoxy 10,20         ;error
        puts m_error
        jmp acabo
   
acierto:
       ;si estado=7 tablas
        gotoxy 10,20         ;ha acertado
        puts m_tablas
        jmp acabo
gano:
        mouse off
        gotoxy 10,20         ;ha acertado
        puts m_gana
acabo:    
        tablero oponente,'O'
        tablero maquina,'X'
        gotoxy 10,21
        puts nw_intento
        getch al             ;espera pulsación antes de salir
        upr                   ;convierte al en mayusculas
        cmp al,'S'
        jne  salir
        jmp nw
salir: setcursor on
        mouse off
        exit 0

tic_tac_toe endp


ver_respuesta proc near
; busca la respuesta a la situación del oponente en la tabla correspondiente
; devuelve estado=7 si gana, estado=6 si tablas y estado=4 si sigue el juego
;    0ffh= error
        mov si,nivel_act
comprueba:
        mov al,[si]    ;posibilidad
        cmp al,0        ;error fin de lista. No hay acción
        jne n_error
        mov estado,0ffh   ; marca error
        ret
n_error:
        cmp oponente,al  ;es la jugada hecha?
        je encontrado
sig_estado:
        add si,4   ; siguiente estado
        jmp comprueba
encontrado:
        mov al,[si+1]
        or maquina,al    ;añade al tablero de la máquina la jugada correspondiente
        mov al,[si+2]    ;dato siguiente estado
        cmp al,0          ;fin de la partida
        je _fin
        cmp al,1        ;tablas
        je _fin
        mov ax,[si+2]
        mov nivel_act,ax     ;pasamos el puntero del nivel a la lista del siguiente nivel
        xor al,al
        jmp _fin_ver


_fin:   or  al,2      ; devuelve al=6 si gana y al=7 si tablas
_fin_ver:            
        or  al,4      ;devuelve al=4 si sigue el juego
        mov estado,al
ret
ver_respuesta endp

_tablero proc near
; oponente viene en bl, y el simbolo a imprimir en bh
        mouse off
        shl bl,1
        jnc c2
        gotoxy 12,4
        putchar bh
c2:
        shl bl,1
        jnc c3
        gotoxy 14,4
        putchar bh
c3:
        shl bl,1
        jnc c4
        gotoxy 10,6
        putchar bh
c4:    
        shl bl,1
        jnc c5
        gotoxy 12,6
        putchar bh
c5:
        shl bl,1
        jnc c6
        gotoxy 14,6
        putchar bh
c6:
        shl bl,1
        jnc c7
        gotoxy 10,8
        putchar bh
c7:
        shl bl,1
        jnc c8
        gotoxy 12,8
        putchar bh
c8:
        shl bl,1
        jnc c9
        gotoxy 14,8
        putchar bh
c9:
        mouse on
        ret
_tablero endp
_end tic_tac_toe

lunes, 5 de agosto de 2013

TIC_TAC_TOE (4/5)

  Antes de colocar el programa completo, vamos a analizar una sección del programa total. Esta sección es la que analiza la pulsación del ratón y define la coordenada.

   A partir de este código añadiré una nueva función a la librería macro. Esta función será un getmousexy, pero en coordenadas de texto.

   Efectivamente ahora tenemos un getmousex y un getmousey. Estas funciones son las tomadas del dos, y dan la posición de pantalla en pixel. Pero en una pantalla de texto, esto no tiene sentido. Además si trabajamos en texto el getmousex y el getmousey devuelven el mismo valor dentro de la matriz que forma un carácter.
   Es por ello para mayor comodidad vamos a transformar en cordenadas de caracter lo mandado por getmousex y getmousey. Luego lo referenciaremos al inicio del tablero y daremos como inválido las coordenadas fuera de él.
  Una vez conocida la coordenada correcta, la transformaremos en posición de bit, usando la instrucción rcr para situar  ese bit en una palabra auxiliar que se sume a la de las demás jugadas.

    La parte roja será la que convertiremos en una nueva función getmousexy.


;espera seleccion oponente 
        mouse on
espera:
        getmouse                ;comprueba el estado del raton
        cmp ax,1
        jnz actual              ;si no se ha pulsado se espera
        cmp ax,raton            ;si se pulso se verifica si ha sido un
        mov raton,ax            ;flanco de subida
        jnz  seleccion           ;si es asi se selecciona la opcion deseada
actual:
        mov raton,ax
        jmp espera
seleccion:
     ;toma la coordenada
        getmousex  
        shr ax,4 ;divide por 16 para obtener coordenada letra   
        sub ax,5 ;referencia desde cero de la posicion en la matriz
        cmp al,2  ;no valido si pulsamos fuera
        ja espera 
        mov posx,al
        getmousey  
        shr ax,4 ;divide por 16 para obtener coordenada letra   
        sub ax,2 ;referencia desde cero de la posicion en la matriz
        cmp al,2    ;no valido si pulsamos fuera
        ja espera 
        mov posy,al
     ;coloca el bit
        mov al,posy    ; posy*3+posx
        add al,posy
        add al,posy
        add al,posx

        cmp al,8       ; si pulsamos fuera no procesamos
        ja espera

        mov cl,al
        xor al,al   ; borra al
        stc    ; carry a 1
        rcr al,cl      ; situa el bit elegido
        ; comprueba que no esté seleccionada ya
     
        mov ah,oponente
        or ah,maquina
        mov ocupados,ah
        or ah,al     ;montamos nuevo bit
        cmp ah,ocupados   ; ha añadido bit nuevo?
        je  espera ; si no añade bit nuevo la posición está ya estaba ocupada
         
        or oponente,al   ; guarda la jugada

sábado, 3 de agosto de 2013

TIC_TAC_TOE (3/5)

   Vais a ver hoy la forma de representar el estado de la jugada. Es el refresh del tablero.
   Podía programar  en esta rutina los bordes del tablero, pero dad que no van a borrarse la pantalla durante el juego, no tiene sentido gastar recursos en redibujar algo que ya está dibujado. Por ello, esta rutina solo rellena el interior del tablero, actualizando las "X" y las "O" según estén los bits de las variables oponente y máquina.
   Como ya se ha podido deducir de la entrada anterior, cada casilla está representada por un bit, partiendo de la segunda, contando desde la esquina superior izquierda.
  Hay nueve casillas, pero como la primera siempre es usada por la máquina como jugada inicial, quedan 8 para elegir. Por eso, un byte =8 bits, nos es suficiente para representar todas las casillas.
  Esta función, por lo tanto analiza cada bit y representa el símbolo.
   Dado que el tablero es idéntico para el oponente y la máquina, podemos utilizar la misma rutina, pasando la variable de máquina o la de oponente, según corresponda. Es por eso que se le pasa a la rutina dos parámetros. El byte con las casillas a presentar, un bit por cada una, y el símbolo a dibujar.

  Se podía haber utilizado un bucle con indices para recorrer las posibilidades, pero no quedaría ni más corto, ni más claro, ni sería más rápido, por lo que mejor lo programo de forma lineal

RUTINA _TABLERO

_tablero proc near
; oponente viene en bl, y el simbolo a imprimir en bh
        mouse off
        shl bl,1
        jnc c2
        gotoxy 12,4
        putchar bh
c2:
        shl bl,1
        jnc c3
        gotoxy 14,4
        putchar bh
c3:
        shl bl,1
        jnc c4
        gotoxy 10,6
        putchar bh
c4:       
        shl bl,1
        jnc c5
        gotoxy 12,6
        putchar bh
c5:
        shl bl,1
        jnc c6
        gotoxy 14,6
        putchar bh
c6:
        shl bl,1
        jnc c7
        gotoxy 10,8
        putchar bh
c7:
        shl bl,1
        jnc c8
        gotoxy 12,8
        putchar bh
c8:
        shl bl,1
        jnc c9
        gotoxy 14,8
        putchar bh
c9:
        mouse on
        ret
_tablero endp

jueves, 1 de agosto de 2013

TIC_TAC_TOE (2/5)

  Hoy voy a colocar la rutina de como pensar la respuesta.
  Como dije en la anterior entrada, esta es la rutina más importante, pues es la que analiza la jugada y toma la decisión correcta. Esta rutina es  realmente el juego.

  La he llamado ver_respuesta.
  A esta rutinano se le pasan parámetros, pues la variable nivel_act, ya es la dirección en la que hay que buscar.
  Esta rutina recorrerá la lista activa, desde el puntero indicado en nivel_act, e irá analizando si el oponente tiene la posición almacenada en la tabla. Si es así almacena la respuesta asociada mediante una "or" con la variable de máquina, para colocar la nueva jugada en el tablero.
  Una vez almacenada la respuesta, verifica si hay puntero a un nuevo nivel, en cuyo caso almacena este nivelen la varible nivel_act, para que sea el nivel a buscar durante la siguiente llamada.
  Si no es así es que el juego ha terminado. Analiza por lo tanto si está en el cuarto nivel, para determinar si es tablas y sale de la rutina indicando en estado el estado de la búsqueda.
   En caso de haber recorrido la tabla y no haber encontrado el estado del oponente, devuelve en estado 0ffh como indicador de error.
  
RUTINA VER_RESPUESTA
(C) José Angel Moneo Fdez

ver_respuesta proc near
; busca la respuesta a la situación del oponente en la tabla correspondiente
; se pasa la dirección de la tabla en nivel_act
; devuelve estado=7 si gana, estado=6 si tablas y estado=4 si sigue el juego
;    0ffh= error
        mov si,nivel_act
comprueba:
        mov al,[si]    ;posibilidad
        cmp al,0        ;error fin de lista. No hay acción
        jne n_error
        mov estado,0ffh   ; marca error
        ret
n_error:
        cmp oponente,al  ;es la jugada hecha?
        je encontrado
sig_estado:
        add si,4   ; siguiente estado
        jmp comprueba
encontrado:
        mov al,[si+1]
        or maquina,al    ;añade al tablero de la máquina la jugada correspondiente
        mov ax,[si+2]    ;dato siguiente estado
        cmp ax,0          ;fin de la partida
        je _fin
        cmp ax,1        ;tablas
        je _fin

        mov nivel_act,ax     ;pasamos el puntero del nivel a la lista del siguiente nivel
        xor al,al
        jmp _fin_ver


_fin:   or  al,2      ; devuelve al=6 si gana y al=7 si tablas
_fin_ver:              
        or  al,4      ;devuelve al=4 si sigue el juego
        mov estado,al
ret
ver_respuesta endp

martes, 30 de julio de 2013

TIC_TAC_TOE (1/5)

   Voy a colocar en los próximos días un nuevo juego. En este caso el famoso Tic Tac Toe, Tres en línea, Tres en raya o Juego del gato.
    Este es ya un juego mucho más complejo por las cantidad de decisiones que puede tener y en él, practicaré el recorrido de listas y tablas. Sobre todo, vamos a implementar una forma de leer e interpretar un árbol de decisiones.
    Al tiempo, usaré la función getmousex, getmousey, para leer la posición del ratón, y las de activación y desactivación del cursor cursor on y cursor off.

    Aquí veréis una forma de tomar decisiones a través de un árbol de decisión o árbol de juego. El árbol de decisión ha sido sacado a partir de la tabla de posibilidades.
   Como se recorre, es simple, basta leer el programa. Puesto que este es muy simple y la secuencia es muy corta, no será complicado sacarlo del programa. Hay que dejar algo para analizar....

     Esta es la pantalla que queremos conseguir. En ella crearé una matriz para el tablero e iremos pulsando con el ratón cada casilla, colocando una O en su posición. El ordenador entonces analizará la jugada y colocará una X en la posición correspondiente.
    El ordenador siempre empieza. Por desgracia solo podrás hacer tablas o perder.

    Si  gana  consigues hacer tablas el ordenador te muestreará un mensaje, como el de abajo, y te invita a repetir el juego.



  Comenzaré con la estructura del programa.

   Para realizar el programa vemos que necesitaremos.
    tic_tac_toe    Esta rutina, que será la principal, y deberá hacer en orden:

  •           Dibujar el tablero
  •           Tomar la posición indicada mediante el ratón por el oponente
  •           Pensar una respuesta
  •           Refrescar el tablero

    Dibujar el tablero
 Como se trata de un tablero fijo, que no varía, lo haré en las primeras líneas del programa. No, imprimiré el tablero más que una vez, y por lo tanto no vale la pena crear subrutina.

   Tomar la posición indicada mediante el ratón por el oponente
   Para ello  leeré la posición del ratón y espere el flanco positivo de pulsación. Si se pulsa corregirá la posición a coordenadas de texto, ya que el ratón las da en coordenadas de pixel. Devolverá dicha posición xy. Este código desarrollado para este juego, resulta muy útil en el futuro, y por lo tanto, más adelante en el blog mostraré como implementarla en nuestra librería para futuros programas. La programación estructurada trata de crear elementos que sirvan como herramientas futuras y ser capaz de implementarlos para un uso futuro. Un buen programador cuanto más programa, más poderoso es, pues más herramientas tiene. No se debe usar copy-paste de trozos de programa. Se debe crear herramientas para el futuro.

    Pensar una respuesta
     Esta el la parte más bonita del programa. En una rutina aparte. Realizada para poder analizar esta secuencia por separado, vamos a una rama del árbol y tomar la decisión correcta, dejando el sistema preparado para el siguiente nivel de juego. Conviene formar subrutinas, cuando la función puede escindirse del código madre. Es decir, cuando podemos realizar un programa que funcione sin contar con esta parte del programa, de forma que podamos realizar un simulación del resto del programa. Esto nos permitirá ir probando el programa principal sin estas partes y activando posteriormente cada subrutina, de manera que podamos ir corrigiendo defectos de forma sencilla en el debuger.

     Refrescar el tablero
    Esta es una función simple como la de imprimir tablero, que simplemente representa el estado del juego. En este caso es subrutina, porque se va a usar muchas veces a lo largo del código. Haré una función que me sirva por separado para imprimir el estado del oponente y de la máquina, y que pueda usar cualquier símbolo como marca. Así me ahorro código particularizado para oponente y máquina  dado que las casillas donde imprimir son comunes.


    Vamos a comenzar con lo más valioso. El MAPA DE JUEGO


MAPA DE JUEGO
     Este mapa nos representa las acciones a realizar por la máquina según el estado en que se encuentre el oponente, y nos indica si debemos toma  nueva rama de decisión o si el juego ha terminado.
    En el árbol de decisión de este juego existen hasta 4 niveles. Si llegamos al nivel 4 el resultado es tablas
    Al final de cada lista hemos colocado un dd 0, como marca de fin de lista. En realidad no se necesita, pero sirve, durante la depuración, para detener el programa en caso de no encontrar la jugada dentro de la lista. Por ejemplo, si hemos escrito mal la secuencia de números del árbol de decisión.



(c) Jose Angel Moneo Fdez

;Mapa de juego TICTACTOC

nivel1  db 80h,20h
            dw offset n2_20h
        db 40h,20h
            dw offset n2_20h
        db 20h,80h
            dw offset n2_80h
        db 10h,80h
            dw offset n2_80h
        db 8,10h
            dw offset n2_10h
        db 4,80h
            dw offset n2_80h
        db 2,40h
            dw offset n2_40h
        db 1,40h
            dw offset n2_40h

   
n2_10h db 9,40h
           dw offset n3_40h
       db 88h,1,0,0
       db 48h,1,0,0
       db 28h,1,0,0
       db 0ch,1,0,0
       db 0ah,1,0,0
       dd 0


n2_20h db 84h,10h
          dw offset n3_10h_1
       db 44h,10h
          dw offset n3_10h_2
       db 0c0h,4,0,0
       db 90h,4,0,0
       db 88h,4,0,0
       db 82h,4,0,0
       db 81h,4,0,0
       db 50h,4,0,0
       db 48h,4,0,0
       db 42h,4,0,0
       db 41h,4,0,0
       dd 0


n2_40h db 82h,10h
            dw offset n3_10h_3
       db 81h,4
            dw offset n3_4h
       db 22h,80h,0,0
       db 21h,80h,0,0
       db 12h,80h,0,0
       db 11h,80h,0,0
       db 0ah,80h,0,0
       db 9,80h,0,0
       db 6,80h,0,0
       db 5,80h,0,0
       db 3,80h,0,0
       dd 0

;revisado
n2_80h db 60h,10h
            dw offset n3_10h_3
       db 44h,10h
            dw offset n3_10h_3
       db 50h,4
            dw offset n3_4h
       db 30h,40h,0,0
       db 28h,40h,0,0
       db 24h,40h,0,0
       db 22h,40h,0,0
       db 21h,40h,0,0
       db 0ch,40h,0,0
       db 18h,40h,0,0
       db 14h,40h,0,0
       db 12h,40h,0,0
       db 11h,40h,0,0
       db 6,40h,0,0
       db 5,40h,0,0
       dd 0

n3_4h db 70h,8
         dw offset n4_8h
      db 58h,20h,0,0
      db 52h,20h,0,0
      db 51h,20h,0,0
      db 0a1h,10h,0,0
      db 91h,20h,0,0
      db 89h,20h,0,0
      db 83h,20h,0,0
   

n3_10h_1 db 0c4h,8,0,0      
       db 85h,8,0,0
       db 8ch,1,0,0
       db 86h,8,0,0
       dd 0

n3_10h_2 db 0c4h,8,0,0
       db 4ch,1,0,0
       db 86h,8,0,0
       db 85,8,0,0
       dd 0

n3_10h_3 db 0c4h,2,0,0
       db 0c2h,1,0,0
       db 0c8h,2,0,0
       db 0c1h,2,0,0
       db 4ch,2,0,0
       db 86h,1,0,0
       db 85h,2,0,0
       db 8ah,4,0,0
       db 83h,4,0,0
       db 0a2h,4,0,0
       db 61h,2,0,0
       db 62h,1,0,0
       db 64h,2,0,0
       db 68h,2,0,0
       db 46h,1,0,0
       db 45h,2,0,0
       dd 0



n3_40h db 89h,4,0,0
       db 29h,80h,0,0
       db 0dh,80h,0,0
       db 0bh,80h,0,0
       dd 0
   
n4_8h  db 72h,1,1,0
       db 71h,2,1,0
       dd 0
   
VARIABLES DE JUEGO
   Vamos a necesitar una serie de variables para el juego. Básicamente:
              Un puntero a la lista del árbol.
              Almacén de las jugadas de la máquina.
              Almacén de las jugadas del oponente.

 ;VARIABLES TICTACTOC
  (c) Jose Angel Moneo Fdez
nivel_act dw 0 ; almacen de puntero de nivel actual    
maquina db 0 ; situación de la maquina
oponente db 0 ; situación del oponente

VARIABLES CONTROL DEL RATÓN
   Para control del ratón usaremos estas varialbes, donde almacenamos la posición y una bandera de estado para manejar el flanco.

(c) Jose Angel Moneo Fdez
;VARIABLES TICTACTOC
estado db 0; estado partida
posx db 0   ; posicion pulsación del raton
posy db 0
raton dw 0

VARIABLES DE PANTALLA
  Estas son las variables necesarias para presentar el juego y el tablero. El tablero está creado mediante los valores ASCII, para poder usar el Notepad como editor.

(c) Jose Angel Moneo Fdez
;VARIABLES TICTACTOC
titulo db "TRES EN LINEA",0
ayuda db "PULSA CON EL RATON EN LA POSICION DESEADA",0
m_gana db "Lo siento has perdido.",0
m_tablas db "Esta partida son tablas",0
m_error db " Ha surgido un error",0

tablero1 db 201,205,203,205,203,205,187,0 ; "╔═╦═╦═╗"
Tablero2 db 186,32,186,32,186,32,186,0      ; "║ ║ ║ ║"
Tablero3 db 204,205,206,205,206,205,185,0   ; "╠═╬═╬═╣"
Tablero4 db 200,205,202,205,202,205,188,0   ; "╚═╩═╩═╝

NW_intento db "Quieres intentarlo de nuevo? S/N",0

En el proximo blog pondré la rutina de como pensar la respuesta.

miércoles, 24 de julio de 2013

AHORCADO (5/5)

    Ya tenemos las herramientas necesarias para hacer el juego. Las rutinas expuestas antes, no necesitamos guardarlas en librerías, pues son parte de este programa. Por lo tanto son parte del código principal.
    Este, por lo tanto, es el fichero .asm completo que habrá que compilar.
    En el usamos funciones de time, de stdio, de string, y de main.
    El ejecutable resulta de 5232 Bytes

   Es importante pedir la letra con getch, la almacenamos en letra, y luego la convertimos en mayúsculas con upr.

   El programa está preparado para ser un .exe. Para que sea .com debemos colocar la directiva "_modelo com" y linkarlo con una librería preparada para .com.
    Esta librería se formará compilando todas las rutinas expuestas anteriormente pero con esta directiva. y creando luego una libreria completa para .com
   En el caso de que se compile como .com habrá que pasar los datos al final del programa. Esto no lo podemos hacer ahora, pues se producen problemas de compilación.

AHORCADO.ASM
; Copyright (C) 2013  José Ángel Moneo Fernández

;    This program is free software: you can redistribute it and/or modify
;    it under the terms of the GNU General Public License as published by
;    the Free Software Foundation, either version 3 of the License, or
;   (at your option) any later version.

;    This program is distributed in the hope that it will be useful,
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;    GNU General Public License for more details.

;    You should have received a copy of the GNU General Public License
;    along with this program.  If not, see <http://www.gnu.org/licenses/>.

include main.mac
include stdio.mac
include string.mac
include time.mac

_modelo exe
_stack 250

_data
;palabras
p1 db 9,"BARCELONA",0
P2 DB 4,"CASA",0
P3 DB 4,"CAMA",0
P4 DB 5,"ARBOL",0
P5 DB 7,"ARMARIO",0
P6 DB 5,"COJIN",0
P7 DB 5,"SUELO",0
P8 DB 4,"FLOR",0
P9 DB 3,"PAN",0
P10 DB 11,"ENCRUCIJADA",0
P11 DB 4,"HOJA",0
P12 DB 8,"CUADERNO",0
P13 DB 11,"ENSAMBLADOR",0
P14 DB 8,"PROGRAMA",0
P15 DB 7,"COLEGIO",0
P16 DB 6,"CAMARA",0

TABLA DW OFFSET P1
      DW OFFSET P2
      DW OFFSET P3
      DW OFFSET P4
      DW OFFSET P5
      DW OFFSET P6
      DW OFFSET P7
      DW OFFSET P8
      DW OFFSET P9
      DW OFFSET P10
      DW OFFSET P11
      DW OFFSET P12
      DW OFFSET P13
      DW OFFSET P14
      DW OFFSET P16

PAL_SEL DW 0
mascara DB "__________________________",0

a_buscar dw 0
letra db 0
fallos db 0
titulo db "AHORCADO",0
pregunta db "INDICA UNA LETRA",0
acierto db "!Enhorabuena! Acertaste",0
perdio db "!Lo siento! Has periddo",0
NW_intento db "Quieres intentarlo de nuevo? S/N",0
limpia db "    ",0
HORCA DB 218,196,196,196,0   ;"┌───┐"


_code
ahorcado proc far
        main   ; inicia
nw:
        call nw_pal    ;gernera una nueva palabra
        mov fallos,0   ;coloca el contador fallos a 0
        ;Preparamos la pantalla
        clrscr
        gotoxy 10,2     ;dibujamos horca
        puts titulo
        gotoxy 8,4
        puts horca
        gotoxy 8,5
        putchar 179
        gotoxy 8,6
        putchar 179
        gotoxy 8,7
        putchar 179
        gotoxy 8,8
        putchar 179
        gotoxy 8,9
        putchar 193
 
        gotoxy 10,10   ; muestra la mascara incial
        puts mascara
        gotoxy 10,13     ; hacemos la pregunta
        puts pregunta
_otro:
        gotoxy 29,13      ;limpia la ultima respuesta
        puts limpia
        gotoxy 29,13
        getch letra    ;pedimos la letra
        upr letra    ;convierte en mayuscula
        call buscar    ;busca la letra
        cmp bh,1       ; 1 si encuentra la letra
        je bien
        inc fallos     ; cuenta un fallo
        cmp fallos,8
        jne bien
        ;perido el juego
        gotoxy 11,4
        putchar 191  ;"┐"   ;dibuja la horca
        gotoxy 10,20         ;Perdiste
        puts perdio
        jmp  nw_int          

bien:
        gotoxy 10,10
        puts mascara
        call muneco
        cmp bl,1      ;1 si faltan letras
        jne _fin     ; estrucutra de saltos debido a que el salto relativo no llega hasta _otro
        jmp _otro
_fin:
        gotoxy 10,20         ;ha acertado
        puts acierto
nw_int:
        gotoxy 10,21
        puts nw_intento
        getch al             ;espera pulsación antes de salir
        upr                   ;convierte al en mayusculas
        cmp al,'S'
        jne  _salir
        jmp nw
_salir: exit 0

endp

nw_pal proc near
        push di
        push si
        random
        and ax,0fh    ; tomo numeros >16
        shl ax,1      ;multiplico por dos
        add ax,offset tabla   ;indexo a la tabla de punteros a palabras
        mov si,ax      ;paso la dirección a 'SI' para indexar
        mov ax,[si]    ; recupero la dirección de la palabra de la tabla de punteros
        mov pal_sel,ax  ; almaceno la dirección de la palabra
        mov si,ax        ; paso esta dirección a si para indexar
        mov di,offset mascara  ; usa 'DI' como indexador de mascara
        mov al,[si]   ; leo el numero de letras de la palabra
ini:
        mov byte ptr [di],'_'   ;borra la mascara
        inc di             ; incrementamos puntero busqueda
        dec al           ; decremento el número de letras
        jnz ini
        mov byte ptr [di],0 ; pongo final de cadena
        pop si
        pop di
ret
nw_pal endp

; busca la letra
; devuelve bl=1 si la encuentra la letra
;          bh=1 si faltan letras
buscar proc near
        push di
        push si
        push cx
        mov bx,0  ;borra banderas
        mov si,pal_sel
        mov di,offset mascara
        mov cl,[si] ;numero de letras a contador de busqueda
        inc si ;salta la longitud de la palabra
prueba:
        mov al,letra
        cmp byte ptr [si],al ;comprueba la letra pasada en al
        jne otra
        mov [di],al ; almacena la letra en mascara
        mov bh,1  ; marca bandera letra encontrada
otra:
        cmp byte ptr [di],"_"
        jne sigue
        mov bl,1  ; bandera palabra incompleta
sigue:
        inc si
        inc di
        dec cl
        jnz prueba
        pop cx
        pop si
        pop di
ret
buscar endp

;representación del muneco
; el contador está en la variable 'fallos'
muneco proc near
        push bx
        mov bl,fallos
        cmp bl,7
        jb s1
        gotoxy 12,8
        putchar '\'
s1:
        cmp bl,6
        jb s2
        gotoxy 10,8
        putchar '/'
s2:
        cmp bl,5
        jb s3
        gotoxy 11,7
        putchar 179   ;"│"
s3:
        cmp bl,4
        jb s4
        gotoxy 11,6
        putchar 179   ;"│"
s4:
        cmp bl,3
        jb s5
        gotoxy 12,6
        putchar '\'
s5:
        cmp bl,2
        jb s6
        gotoxy 10,6
        putchar '/'
s6:
        cmp bl,1
        jb fin
        gotoxy 11,5
        putchar 'O'
fin:
        pop bx
        ret
muneco endp
_end ahorcado








lunes, 22 de julio de 2013

AHORCADO (4/5)

   Esta es la subrutina última antes de generar el programa completo.
   Con ella dibujamos el muñeco.
    Esta si que resulta fácil. Vamos comprobando el valor de fallos y vamos imprimiendo un caracter en una posición según su valor. Comenzamos a comparar del mayor número al menor de manera que se dibujen todos los caracteres por debajo del valor de fallos.
    En este caso no haría falta refrescar todo el dibujo, ya que no borramos pantalla, pero me gusta siempre dejar las cosas bien hechas por si decido cambiar el proceso principal o hacer una nueva versión.



MUÑECO
(c) José Angel Moneo Fdez

;representación del muneco
; el contador está en la variable 'fallos'
muneco proc near
        push bx
        mov bl,fallos
cmp bl,7
jb s1
gotoxy 12,8
putchar '\'
s1:
cmp bl,6
jb s2
gotoxy 10,8
putchar '/'
s2:
cmp bl,5
jb s3
gotoxy 11,7
putchar 179   ;"│"
s3:
cmp bl,4
jb s4
gotoxy 11,6
putchar 179   ;"│"
s4:
cmp bl,3
jb s5
gotoxy 12,6
putchar '\'
s5:
cmp bl,2
jb s6
gotoxy 10,6
putchar '/'
s6:
cmp bl,1
jb fin
gotoxy 11,5
putchar 'O'
fin:
        pop bx
        ret
muneco endp

jueves, 18 de julio de 2013

AHORCADO (2/5)

   Hoy vamos a ver la primera función auxiliar del juego Ahorcado. La función que selecciona la palabra.
   Esta función la hago transparente, para evitar interferencias con el proceso. para ello salvo y recupero los registros que uso en pila.
   El seudocódigo sería:
       - Genera un número aleatorio
       - Se queda con los 4 bits bajos, para que el número no resulte mayor de 15.
       - Lo multiplica por 2 y suma el offset de TABLA para obtener una dirección válida en la tabla de punteros. 
       - Guarda esta dirección como palabra seleccionada.
       - Toma su longitud e inicializa la máscara borrando lo que tuviera y colocando un cero al final para que sea imprimible por puts.
     

     El programa no es compilable si no incluimos las cabeceras y las definiciones de segmentos, pero en este caso todo es parte de un solo programa que colocaré completo en la parte 5/5.

NW_PAL
(c) José Angel Moneo Fdez

nw_pal proc near
        push di
push si
random
       and ax,0fh    ; tomo numeros >16
shl ax,1      ;multiplico por dos
add ax,offset tabla   ;indexo a la tabla de punteros a palabras
mov si,ax      ;paso la dirección a 'SI' para indexar
mov ax,[si]    ; recupero la dirección de la palabra de la tabla de punteros
mov pal_sel,ax  ; almaceno la dirección de la palabra
        mov si,ax        ; paso esta dirección a si para indexar
mov di,offset mascara  ; usa 'DI' como indexador de mascara
        mov al,[si]   ; leo el numero de letras de la palabra
ini:
mov byte ptr [di],'_'   ;borra la mascara
inc di             ; incrementamos puntero busqueda
dec al           ; decremento el número de letras
jnz ini 
mov byte ptr [di],0 ; pongo final de cadena
pop si
pop di
ret
nw_pal endp