Vistas de página en total

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.

domingo, 28 de julio de 2013

CURSOR

  Librería para manejo del cursor.
  Permite activar y desactivar el cursor.

   Esta librería es necesaria para el siguiente programa.


CURSOR.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
_modelo exe
_code
rutina _set_cursor p1
        push cx
        push bx
        mov ah,03
        mov bh,0
        int 10h
        mov ax,[bp].p1
        or ax,ax
        jz cero
        and cx,0dfdfh
        jmp camb
    cero:
        or cx,2020h
    camb:
        mov ah,1
        int 10h
        pop bx
        pop cx
rutina_end
_data
_end

viernes, 26 de julio de 2013

FUNCIONES MOUSE

Esta es la librería de funciones del ratón.
 Aquí existen algunas funciones que no están implementadas en macros de la cabecera. No todas las he usado, y por ello no creé macro.

MOUSE.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/>.
 
_modelo exe
_code

      public _mouse_thd
      public _inst_sub_mouse
      public _set_rang
      public _mouse_graf
      public _vel_mouse


;DEFINE CURSOR DE TEXTO POR HARDWARE
;MOUSE_THD()
_mouse_thd proc near
        mov ax,10
        mov bx,1
        mov cx,1
        mov dx,24
        int 33h
        ret
_mouse_thd endp



;COLOCA RANGO DE MOVIMIENTO DEL RATON EN UNA CIERTA DIRECCION
;SET_RANG(INT DIRECCION,INT MINIMO,INT MAXIMO)
_set_rang proc near
        push bp                   ;DIRECCION 0 HORIZONTAL
        mov bp,sp                 ;          1 VERTICAL
        mov cx,[bp+6]
        mov dx,[bp+8]
        cmp byte ptr[bp+4],0
        jz horizontal
        cmp byte ptr [bp+4],1
        jz vertical
        pop bp
        ret

horizontal:
        mov ax,7
        int 33h
        pop bp
        ret

vertical:
        mov ax,8
        int 33h
        pop bp
        ret
_set_rang endp

;DEFINE CURSOR GRAFICO
;MOUSE_GRAF(INT CEN_X,INT CEN_Y,INT *MASK)
_mouse_graf proc near
        push bp          ;cen_x y cen_y  -16 y 16
        mov bp,sp        ; fondo       cursor   efecto
        mov ax,9         ;   0          0        0
        mov bx,[bp+4]    ;   0          1        1
        mov cx,[bp+6]    ;   1          0        invariable
        mov dx,[bp+8]    ;   1          1        invertido
        int 33h          ;
        pop bp
        ret
_mouse_graf endp

;CAMBIA LA VELOCIDAD DEL RATON
;VEL_MOUSE(INT V_HORIZONTAL,INT V_VERTICAL)
_vel_mouse proc near
        push bp
        mov bp,sp
        mov ax,15
        mov cx,[bp+4]
        mov dx,[bp+6]
        int 33h
        pop bp
        ret
_vel_mouse endp
    end

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

sábado, 20 de julio de 2013

AHORCADO (3/5)

  Siguiendo con el programa del ahorcado, vamos a ver como buscar la letra en la palabra seleccionada, para poder definir si acertamos o no.

   Esta función es transparente también, pero como usa bx para devolver datos este registro no se salvaguarda.
    Usamos bl y bh como banderas, que nos indicarán si se ha encontrado la letra y si faltan letras por descubrir.
   El código creo que es claro.
         Tomamos las direcciones de la palabra seleccionada y de la mascara.
         Vamos comparando la letra a buscar con cada letra de la palabra.
          Si la encontramos la copiamos en la mascara y  montamos la bandera de encontrada.
         Verificamos si la mascara está en blanco. Si lo está es que no hemos encontrado nada en ningún intento, y por lo tanto quedan letras por encontrar. Por ello montamos la bandera de faltan letras.
         Recorremos toda la palabra en busca de la letra y simultáneamente comprobamos la máscara.
     


BUSCAR
(c) José Angel Moneo Fdez


; 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

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

martes, 16 de julio de 2013

AHORCADO (1/5)

     Como ya voy haciendo en el blog, voy a subir el nivel un poco más. Para ello  colocaré el código de otro de los juegos más programados como ejemplo, el "AHORCADO".
     Como este juego resulta más complejo que el anterior, lo realizaré en 5 entradas.
      En la primera que es la de hoy explicaré el planteamiento del programa. Es decir haré un análisis de las necesidades para poder estructurar el programa. No colocaré ordinogramas ni pseudocódigos, ya que resultan más complejos de hacer que el propio programa.
     Aunque no sirvan en muchos casos los pseudocódigos, si suelen servir los ordinogramas. Lo que sucede es, que al ser tan simple el lenguaje ensamblador, resulta igual de claro hacer un ordinograma que representar el código en una forma de borrador.
   
     Las 4 entradas del blog las estructuraré de la siguiente manera:
                   1- (La de hoy) Plantearé el problema y organizaré los datos. El segmento Code.
                   2- Primera rutina auxiliar
                   3- segunda rutina auxiliar
                   4- secuencia principal, y por lo tanto programa completo.


     PLANTEAMIENTO

     Como hemos dicho antes, vamos a comenzar por definir el juego, para saber lo que necesitamos construir y en que nos vamos a apoyar.


    Esta será la pantalla durante el juego. Faltan los mensajes finales en caso de perder o acertar.
    Por lo tanto necesitamos ser capaces de dibujar al muñeco y la horca. Cosa facil en principio, para ello usaremos las funciones puts y putchar.+

   ESTRUCTURA
   Necesitamos elegir una palabra de forma aleatoria. En este caso no es un número y por lo tanto parece más difícil, pero en realidad es igual de simple. Generaremos un número que nos permita elegir la palabra. Para ello crearemos una función nw_pal en la que usaremos random, con una lista de punteros a una lista de palabras.
   Necesitamos pedir una letra. Para ello usamos getch. Pero como la letra pueden ponerla en mayúsculas o en minúsculas, para no tener todas las combinaciones de palabras
    Necesitamos buscar la letra dentro de la palabra y definir si la hemos encontrado y si están todas las letras encontradas. Para ello deberemos crear una función buscar.
   Necesitamos dibujar el muñeco, según los errores que se vayan cometiendo. para ello crearemos una función muneco.
    
   Con todo esto ya tenemos analizada la situación del juego. Crearemos tres funciones, muneco (dibuja el muñeco según los errores), nw_pal (selecciona de forma aleatoria una palabra y buscar (busca la letra en la palabra seleccionada).
   Básicamente el código principal entonces queda como el del mastermind, ya que nw_pal equivale a random, muñeco a printf, y buscar a cmp.

     DATOS

   El segmento de datos lo expongo debajo de esta explicación.
   Primero definimos la lista de palabras. Como es un juego ejemplo, no pondré muchas, 16 en concreto para que sean seleccionables con un nibble.
   Quiero que las palabras sean libres, es decir que no estén sujetas a una longitud fija. Esto me plantea el problema de su indexación. Sin su longitud no es fija, no puedo localizarlas con la formula pos=x*longitud.
Pero en  cambio el juego ganará potencia si su longitud es variable.
    Para resolver este dilema, lo que haremos es crear 16 variables db, en las que escribiremos las palabras en formato string. Es decir, colocamos un byte con su longitud y luego una cadena de caracteres terminada en 0. Así podrá ser identificada y manejada de forma fácil.
   Como queremos usar la formula pos=x*longitud para poder seleccionar la palabra a través de un número random, y las palabras no tienen  longitud fija, debemos usar un truco. Este consiste en realizar una tabla de punteros (2 bytes= 1dw), con las direcciones de cada palabra. Así podremos desplazarnos por la tabla con la formula pos=x*2, y seleccionar cualquier palabra a partir del número x generado a través de random.

    La tabla es fácil de crear como una variable dw cuyos valores son los offset de cada palabra.
   Una vez elegida la palabra debemos usarla como el número a buscar. Por ello se pasará su dirección a una variable fija a_buscar. Esta es la misión de la rutina nw_pal. Deberá generar un número aleatorio, indexar con el en la tabla, recoger la dirección de la palabra elegida y guardarla en a_buscar
   Esta era la parte dificil. El resto no hace falta explicarlo. Necesitamos una variable para llevar la cuenta de fallos (fallos), y una variable para ir representando la palabra con las letras encontradas (mascara).
   El dibujo de horca está hecho mediante una lista de números, para evitar que el notepad, guarde mal los códigos ascii especiales. Si usais un editor de dos como ED no hará falta y podréis representar la barra como un texto.

_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 de indexación
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   ;"┌───┐"
ends

domingo, 14 de julio de 2013

MASTERMIND


    Hoy vamos a realizar un programa de cierta complejidad. Vamos a crear el juego MasterMind.

   No complicaremos mucho las pantalla, pues todavía no he subido las funciones avanzadas de ventanas y menús. Por lo tanto, lo realizaremos al estilo de un Basic.
   Aquí os dejo la ventana que resultará del programa.



   

  Como veis  colocamos el título, debajo la pregunta, y debajo el contador de intentos.
       Pedimos el número y en la parte inferior indicamos el mensaje de si acertamos, el número es alto o el número es bajo.
    Hacer este programa directamente en ensamblador sin apoyo de las rutinas expuestas anteriormente todavía es posible, aunque el código ya resulta tan grande que perdemos la visión global del programa en las pormenorizaciones.
    En cambio si hemos estructurado bien el código podremos concentrarnos en resolver el algoritmo del programa sin preocuparnos del código de presentación.
    Como se trata de un ejemplo, el número generado lo enmascaramos con 0ffH para que no sea demasiado grande.
     El fichero resultante es un .EXE de 6370 Bytes.
     El código es en realidad  100 bytes de pila, 236 de datos,  321 bytes de código principal y 740 bytes de librerías.


   
MATERMIND.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 MASTERMIND
include main.mac
include stdio.mac
include string.mac
include time.mac
_modelo exe

_stack 100

_data
a_buscar dw 0
numero dw 0,0
contador dw 0,0

titulo db "MASTERMIND",0
pregunta db "Cual es el numero que estoy pensando?",0
acierto db "!Enhorabuena! Acertaste",0
alto db "Lo siento. Numero alto. Intentalo de nuevo",0
bajo db "Lo siento. Numero bajo. Intentalo de nuevo",0
m_intentos db "Llevas       intentos",0
NW_intento db "Quieres intentarlo de nuevo? S/N",0
limpia db "           ",0

_code
mastermind proc far
        main   ; inicia
nw:
        random    ;gernera un número aleatorio
        and ax,0ffh         ;tomamos valores de 0 a 256
        mov a_buscar, ax
        clrscr
        mov contador,0
        ;Preparamos la pantalla
        gotoxy 10,6
        puts titulo
        gotoxy 10,7
        puts pregunta
_otro:
        gotoxy 10,8
        puts m_intentos
        gotoxy 17,8
        printf contador
        gotoxy 10,10
        puts limpia
        gotoxy 10,10
        scanf numero    ;pedimos el numero
        mov ax, a_buscar
        cmp numero,ax ;lo comprobamos
        jb _bajo
        ja _alto
        gotoxy 10,20         ;ha acertado
        puts acierto
        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
_bajo:
        inc contador
        gotoxy 10,20       ;ha fallado. muesta mensaje
        puts bajo
        jmp _otro
_alto:
        inc contador
        gotoxy 10,20       ;ha fallado. muesta mensaje
        puts alto
        jmp _otro
mastermind endp
_end

viernes, 12 de julio de 2013

EJEMPLO "HORA"


     Este es un ejercicio en el que imprimiremos la hora. Para ello usamos las funciones ya creadas anteriormente: printf para imprimir los valores,  time para tomar la hora, y clrscr para borrar pantalla.

     Como en este caso se trata de un programa ejecutable y no de una librería, se declara la pila mediante _stack, se usa main al comienzo del programa para inicializar el programa., y usamos exit para salir al DOS devolviendo 0.

    El programa al ejecutarse borra la pantalla y muestra la hora en formato hh:mm:ss.


EJ_HORA.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 stdio.mac
include main.mac
include time.mac
_modelo exe

_stack 512
_data
time hora
separador db ":",0
_code
p proc far
       main
       clrscr
       gettime hora
       printf hora.ti_hora,@d
       puts separador
       printf hora.ti_min,@d
       puts separador
       printf hora.ti_seg,@d
       getch al
       exit 0
p endp
_data
time hora
separador db ":",0
_end p

miércoles, 10 de julio de 2013

CABECERA TIME

        Vamos a ver ahora una cabecera que añadirá, junto con sus librerías asociadas, las funciones necesarias para tomar la hora.
      Ahora no hemos añadido a esta cabecera las funciones de fecha. Eso lo podremos hacer más tarde.
   
     En este caso creamos una macro que creará una estructura con el formato de hora, si no ha sido creada antes,  y posteriormente la variable asociada que deseamos. Por lo tanto creamos un tipo de variable time.

     Para empezar, tendremos tres funciones gettime, asctime, y delay. La primera está implementada directamente en la macro y la usaremos en el siguiente blog para crear un pequeño ejercicio impresión de hora y en el siguiente blog crearé un MASTERMIND.

      Luego añadiremos las librerías de asctime y delay.
      Ascitime nos permitirá tomar la hora directamente en formateada en una cadena.
      Delay lo usaremos para crear retardos en los programas.

TIME.MAC
; 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/>.

;macro para generar varible hora
time macro nombre
ifndef _time
    _time struc
        ti_hora dw 2 dup (?)
        ti_min dw 2 dup (?)
        ti_seg dw 2 dup (?)
        ti_dec dw 2 dup (?)
    _time ends
endif
     nombre _time ?
endm

;devuelve un número aleatorio en ax
random macro 
    push dx
    mov ah,00
    int 1ah
    mov ax,dx
    pop dx
endm
;obtiene la hora y la comunica a una varialbe con la estructura _time
gettime macro hora
     push cx
     push dx
     mov ah,2ch
     int 21h
     mov byte ptr hora&.ti_hora,ch
     mov byte ptr hora&.ti_min,cl
     mov byte ptr hora&.ti_seg,dh
     mov byte ptr hora&.ti_dec,al
     pop dx
     pop cx
endm
asctime macro cadena
ifndef _asctime
   extrn _asctime:near
endif
        lea ax,cadena
        push ax
        call _asctime
        pop ax
  endm

delay macro tiempo
ifndef _delay
        extrn _delay:near
endif
        mov ax,tiempo
        push ax
        call _delay
        pop ax
 endm


lunes, 8 de julio de 2013

COMPARA CADENAS DE TEXTO




STRCMP.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

 extrn _strlen:near
_modelo exe
_code
rutina _strcmp destino,fuente
        PUSH SI
        PUSH DI
        PUSH ES
        PUSH DS
        POP ES
        MOV SI,[BP].destino
        MOV DI,[BP].fuente
        CLD
   MAS: CMPSB
        jne final
        CMP BYTE PTR [SI-1],0
        JNZ MAS
final:
        POP ES
        POP DI
        POP SI
 
rutina_end
_data
_end

sábado, 6 de julio de 2013

CORTA CADENA





STRCUT.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
_modelo exe
_code
rutina _strcut destino,inicio,final,fuente

        PUSH SI
        PUSH DI
        PUSH ES
        PUSH DS
        POP ES

        MOV SI,[BP].fuente
        MOV DI,[BP].destino
        ADD SI,[BP].inicio
        MOV CX,[BP].FINAL
        SUB CX,[BP].INICIO
        CLD
   MAS: MOVSB
        CMP BYTE PTR [SI-1],0
        JZ FIN
        LOOP MAS
FIN:
        MOV BYTE PTR [DI],0
        POP ES
        POP DI
        POP SI
rutina_end
_data
_end