Fundamentos de programación con Módula-2 (27)

11.7 Ejemplos de programas

A continuación se muestran varios programas completos con ejemplos de sus respectivas ejecuciones.

11.7.1 Sopa de letras
Con este programa se trata de realizar la búsqueda de una palabra dentro de una matriz de caracteres. La búsqueda debe realizarse en horizontal, vertical y diagonal en ambos sentidos. Por tanto, se pueden establecer 8 direcciones de búsqueda: norte, sur, este, oeste, noroeste, suroeste, noreste y sureste. En la búsqueda se deben tener en cuenta los límites de la matriz. La función Buscar comprueba si la palabra P de longitud L coincide con los caracteres de la matriz desde la posición: fila F y columna C, siguiendo la dirección R. Esta función tienen en cuenta los límites de la matriz y devuelve un resultado cierto o falso según se encuentre o no la palabra buscada.

Los demás procedimientos son auxiliares. El procedimiento IniciarSopa inicializa de forma aleatoria la matriz, mediante un recorrido de la misma. Cada carácter se obtiene a partir de un número aleatorio entre 0 y 26, al que se suma la posición del carácter "a" dentro de la tabla ASCII.

El procedimiento Cambiar, es el encargado de pasar de minúsculas a mayúsculas la palabra encontrada. Este cambio se realiza mediante un recorrido parcial de Lg caracteres de la matriz desde la posición: fila Fil y columna Col, siguiendo la dirección Ru.

El procedimiento EscribirSopa es un recorrido total de la matriz en el que se escriben por filas todos los caracteres de la matriz separados por un blanco.

En el programa se lee la palabra a buscar, acabada en punto, e inmediatamente se realiza su búsqueda exhaustiva desde todas las posiciones de la matriz y con todas las direcciones posibles. Si se encuentra, se cambia a mayúsculas. El listado del programa es el siguiente:

(**************************************************************************************************
*
*   Programa: SopaLetras
*
*   Descripción:
*      Este programa busca una palabra en una matriz de caracteres, en cualquier
*      dirección de forma semejante a como se hace en una sopa de letras
*
**************************************************************************************************)
MODULE SopaLetras;
   FROM InOut IMPORT
      WriteString, Write, WriteLn, Read;
   FROM Lib IMPORT RANDOMIZE, RANDOM;
   CONST
      Filas = 10;               (* Filas de la sopa de letras *)
      Columnas = 20;    (* Columnas de la sopa de letras *)
      TotalLetras = 26;    (* Total letras abecedario inglés *)
   TYPE
      Largo = [1..Filas];
      Ancho = [1..Columnas];
      TipoSopa = ARRAY Largo, Ancho OF CHAR;
      Ristra = ARRAY Ancho OF CHAR;
      TipoRumbo = ( Norte, Sur, Este, Oeste, Noroeste, Suroeste, Noreste, Sureste );
      Caracteres = SET OF CHAR;
   VAR
      sopa: TipoSopa;   palabra: Ristra;   long: Ancho;
      indFila: Largo;   indColu: Ancho;   rumbo: TipoRumbo;
      tecla: CHAR;

PROCEDURE IniciarSopa;
(*=====================================
Procedimiento para iniciar aleatoriamente una sopa de letras
=====================================*)
   VAR i : Largo; j : Ancho;
BEGIN
   RANDOMIZE;
   FOR i := 1 TO Filas DO
      FOR j := 1 TO Columnas DO
         sopa[i,j] := CHR(RANDOM(TotalLetras) + ORD("a"))
      END
   END
END IniciarSopa;

PROCEDURE Cambiar( Lg, Col: Ancho; Fil: Largo; Ru : TipoRumbo);
(*=====================================
Procedimiento para cambiar Lg letras a mayusculas desde
la posición Col, Fil con el rumbo RU
=====================================*)
   VAR i : Ancho;
BEGIN
   FOR i := 1 TO Lg DO
      sopa[Fil,Col] := CAP(sopa[Fil,Col]);
      (*– Nueva fila según el rumbo –*)
      CASE Ru OF
         Norte, Noreste, Noroeste : Fil := Fil-1 |
         Sur, Sureste, Suroeste : Fil := Fil+1 |
         Este, Oeste :
      END;
      (*– Nueva columna según el rumbo –*)
      CASE Ru OF
         Este, Noroeste, Sureste : Col := Col+1 |
         Oeste, Suroeste : Col := Col-1 |
         Norte, Sur :
      END
   END
END Cambiar;

PROCEDURE  Buscar( P: Ristra; L,C: Ancho; F: Largo; R: TipoRumbo): BOOLEAN;
(*============================================================
Procedimiento para buscar las L letras de la ristra P, desde la posición C, F con el
rumbo R en la sopa de letras
============================================================*)
   VAR i : Ancho; sigue : BOOLEAN;
BEGIN
   i := 1; sigue := TRUE;
   WHILE (i <= L) AND sigue DO
      (*– Se sigue buscando si está la letra buscada en mayúscula o minúscula –*)
      (*sigue := ( CAP( P[i] ) = CAP( sopa[F,C] ) );*)
      CASE R OF
         Norte, Noreste, Noroeste : F := F – 1 |
         Sur, Sureste, Suroeste : F := F + 1 |
         Este, Oeste:
      END;
      (*– Seguir si la nueva fila está dentro de la sopa –*)
      sigue := sigue AND (F > 0) AND (F <= Filas);
      CASE R OF
         Este, Noreste, Sureste : C := C+1 |
         Oeste, Suroeste : C := C-1 |
         Norte, Sur :
      END;
      (*– Seguir si la nueva columna está en la sopa –*)
      sigue := sigue AND (C > 0) AND (C <= Columnas);
      i := i+1
   END;
   RETURN sigue
END Buscar;

PROCEDURE EscribirSopa;
(*=====================================
Procedimiento para escribir la sopa de letras
=====================================*)
   VAR i : Largo; j : Ancho;
BEGIN
   WriteLn;
   FOR i := 1 TO Filas DO
      FOR j := 1 TO Columnas DO
         Write(sopa[i,j]); Write(" ")
      END;
      WriteLn
   END
END EscribirSopa;

BEGIN
   IniciarSopa;
   EscribirSopa;
   REPEAT
      long := 1;
      WriteString("¿Palabra a buscar.?");
      (*– Leer palabra a buscar –*)
      REPEAT
         Read(tecla); Write(tecla);
         IF tecla IN Caracteres{"a".."z"} THEN
            long := long + 1; palabra[long] := tecla
         END
      UNTIL tecla = ".";
   (*– Buscar desde todos los puntos posibles y en todas las direcciones  posibles –*)
   FOR indFila := 1 TO Filas DO
      FOR indColu := 1 TO Columnas DO
         FOR rumbo := Norte TO Sureste DO
            IF Buscar( palabra, long, indColu, indFila, rumbo)
            THEN
               (*– Cuando se encuentra se camba a mayusculas –*)
               Cambiar( long, indColu, indFila, rumbo )
             END
         END
      END
   END;
   (*– Escribir cómo queda la sopa –*)
   EscribirSopa;
   WriteString( "¿Otra Palabra (s/n)?");
   Read( tecla ); Write( tecla ); WriteLn
   UNTIL tecla = "n"
END SopaLetras.

La ejecución del programa produce el siguiente resultado:

w a u l k v j x j c q d x w g l u v u w
t y j k j d a l d p a i t j k d t n m e
w n r u x v o h c f o f r q y j n g o d
d n e v y w r b q q f r t k d p s z i i
e w k i d c i w d y j o e n p v a p q j
d q k w r p o n s n k v k e d z t v y o
g t h x w d c h g e u j l z e s z i b w
q k q o a u c a l f j v q r p k a w q y
u m i o c b l z x i g z k q y a z y e n
j o c t w b g n v d b c m x w m z b h a
¿Palabra a buscar.?re.
w a u l k v j x j c q d x w g l u v u w
t y j k j d a l d p a i t j k d t n m e
w n R u x v o h c f o f r q y j n g o d
d n E v y w r b q q f R t k d p s z i i
e w k i d c i w d y j o E n p v a p q j
d q k w r p o n s n k v k e d z t v y o
g t h x w d c h g e u j l z E s z i b w
q k q o a u c a l f j v q R p k a w q y
u m i o c b l z x i g z k q y a z y e n
j o c t w b g n v d b c m x w m z b h a
¿Otra Palabra (s/n) ?n

11.7.2 Recortar una imagen
Este programa es un ejemplo de utilización de una matriz orlada. El procedimiento Recortar ya fue explicado en el apartado dedicado a las matrices orladas. El procedimiento Imprimir es simplemente un recorrido de la matriz para imprimir la imagen contenida. El procedimiento LeerFoto lee una imagen de los datos de entrada, leyendo un carácter por cada punto.

El listado completo del programa es el siguiente:

(*****************************************************************************
*     Programa: RECORTE
*    
*     Descripción:
*        Este programa recorta una imagen digitalizada
*
****************************************************************************)
MODULE Recorte;

FROM InOut IMPORT WriteString, WriteLn, Read, Write;

CONST
   Ancho = 40;                      (* Anchura de la imagen *)
   Alto = 20;                          (* Altura de la imagen *)
   Borde = -1;                         (* Indicador de borde de la imagen *)
   Blanco = 0;                        (* Nivel bajo de grises = blanco *)
   Negro = 5;                         (* Nivel alto de grises = negro *)

TYPE
   Grises = [Borde..Negro];
   TipoImagen = ARRAY [0..Alto+1], [0..Ancho+1] OF Grises;

VAR
   imagen: TipoImagen;

PROCEDURE LeerImagen;
(*===============================================
   Lee la imagen como dato de entrada.
================================================*)
   VAR i, j: INTEGER; c: CHAR;
BEGIN
   (*– 1º Paso: Inicializar toda la imagen a ‘Borde’ –*)
      FOR i := 0 TO Alto+1 DO
         FOR j := 0 TO Ancho+1 DO
            imagen[i,j] := Borde
         END
      END;
   (*– 2º Paso: Leer los datos, punto a puto –*)
      FOR   i := 1 TO Alto DO
         FOR j := 1 TO Ancho DO
            Read( c );
            imagen[i,j] := ORD( c ) – ORD( ‘0’ )
         END;
         Read( c )                     (* salto de línea *)
      END;
   END LeerImagen;

PROCEDURE Constrastar( nivel: Grises );
(*===============================================
    Procedimiento para constrastar la imagen
================================================*)
   VAR i,j: INTEGER;
BEGIN
   FOR i := 1 TO Alto DO
      FOR j := 1 TO Ancho DO
         IF imagen[i,j] <= nivel THEN
            imagen[i,j] := Blanco
         ELSE
            imagen[i,j] := Negro
         END
      END
   END;
END Constrastar;

PROCEDURE Recortar;
(*===============================================
   Procedimiento para recortar la imagen
================================================*)
   VAR i, j: INTEGER; fin : BOOLEAN;
BEGIN
   REPEAT
      fin := TRUE;
      FOR i := 1 TO Alto DO
         FOR j := 1 TO Ancho DO
            IF (imagen[i,j] = Blanco) AND ( (imagen[i-1, j] = Borde)
                                                          OR (imagen[i, j-1] = Borde)
                                                          OR (imagen[i, j+1] = Borde)
                                                          OR (imagen[i+1,j] = Borde) ) THEN
                 imagen[i,j] := Borde;
                 fin := FALSE
            END
         END
      END
   UNTIL fin
END Recortar;

PROCEDURE Imprimir;
(*================================================
   Procedimiento para imprimir la imagen
=================================================*)
   VAR i, j: INTEGER;
BEGIN
   FOR i := 1 TO Alto DO
      FOR j := 1 TO Ancho DO
         CASE imagen[i,j] OF
            Borde: Write( " " ) |
            Blanco: Write( "." ) |
            1:       Write( ".") |
            2:       Write( "+") |
            3:       Write( "x") |
            4:       Write( "*") |
            Negro: Write( "#" )
         END
       END;
       WriteLn
   END
END Imprimir;
BEGIN
(*– Leer la imagen inicial –*)
   LeerImagen;
   WriteString( "Imagen inicial:"  ); WriteLn;
   Imprimir;
(*– Reducir la imagen a blanco y negro –*)
   Constrastar( 3 );
   WriteLn;
   WriteString( "Imagen constratada:" ); WriteLn;
   Imprimir;
(*– Recortar la imagen, marcando el borde externo –*)
   Recortar;
   WriteLn;
   WriteString( "Imagen recortada:xXx" ); WriteLn;
   Imprimir;
END Recorte.

A continuación se presenta un ejemplo de la ejecución de este programa. Los datos de entrada contienen un carácter por cada punto de la imagen, y simulan una rejilla. Una de las esquinas del borde derecho está rota. Los datos son:

0123454321012345432101234543210123454321
1234545432123454543212345454321234545432
2345434543234543454323454345432345434543
3454323454345432345434543234543454323454
4543212345454321234545432123454543212344
5432101234543210123454321012345432101233
4543212345454321234545432123454543212344
3454323454345432345434543234543454323454
2345434543234543454323454345432345434543
1234545432123454543212345454321234545432
0123454321012345432101234543210123454321
1234545432123454543212345454321234545432
2345434543234543454323454345432345434543
3454323454345432345434543234543454323454
4543212345454321234545432123454543212345
5432101234543210123454321012345432101234
4543212345454321234545432123454543212345
3454323454345432345434543234543454323454
2345434543234543454323454345432345434543
1234545432123454543212345454321234545432

El resultado de la ejecución del programa es el siguiente:

Imagen inicial:
..+x*#*x+…+x*#*x+…+x*#*x+…+x*#*x+.
.+x*#*#*x+.+x*#*#*x+.+x*#*#*x+.+x*#*#*x+
+x*#*x*#*x+x*#*x*#*x+x*#*x*#*x+x*#*x*#*x
x*#*x+x*#*x*#*x+x*#*x*#*x+x*#*x*#*x+x*#*
*#*x+.+x*#*#*x+.+x*#*#*x+.+x*#*#*x+.+x**
#*x+…+x*#*x+…+x*#*x+…+x*#*x+…+xx
*#*x+.+x*#*#*x+.+x*#*#*x+.+x*#*#*x+.+x**
x*#*x+x*#*x*#*x+x*#*x*#*x+x*#*x*#*x+x*#*
+x*#*x*#*x+x*#*x*#*x+x*#*x*#*x+x*#*x*#*x
.+x*#*#*x+.+x*#*#*x+.+x*#*#*x+.+x*#*#*x+
..+x*#*x+…+x*#*x+…+x*#*x+…+x*#*x+.
.+x*#*#*x+.+x*#*#*x+.+x*#*#*x+.+x*#*#*x+
+x*#*x*#*x+x*#*x*#*x+x*#*x*#*x+x*#*x*#*x
x*#*x+x*#*x*#*x+x*#*x*#*x+x*#*x*#*x+x*#*
*#*x+.+x*#*#*x+.+x*#*#*x+.+x*#*#*x+.+x*#
#*x+…+x*#*x+…+x*#*x+…+x*#*x+…+x*
*#*x+.+x*#*#*x+.+x*#*#*x+.+x*#*#*x+.+x*#
x*#*x+x*#*x*#*x+x*#*x*#*x+x*#*x*#*x+x*#*
+x*#*x*#*x+x*#*x*#*x+x*#*x*#*x+x*#*x*#*x
.+x*#*#*x+.+x*#*#*x+.+x*#*#*x+.+x*#*#*x+

Imagen constratada:
….###…….###…….###…….###…
…#####…..#####…..#####…..#####..
..###.###…###.###…###.###…###.###.
.###…###.###…###.###…###.###…###
###…..#####…..#####…..#####…..##
##…….###…….###…….###……..
###…..#####…..#####…..#####…..##
.###…###.###…###.###…###.###…###
..###.###…###.###…###.###…###.###.
…#####…..#####…..#####…..#####..
….###…….###…….###…….###…
…#####…..#####…..#####…..#####..
..###.###…###.###…###.###…###.###.
.###…###.###…###.###…###.###…###
###…..#####…..#####…..#####…..##
##…….###…….###…….###…….#
###…..#####…..#####…..#####…..##
.###…###.###…###.###…###.###…###
..###.###…###.###…###.###…###.###.
…#####…..#####…..#####…..#####..

Imagen recortada:
    ###       ###       ###       ###
   #####     #####     #####     #####
  ###.###   ###.###   ###.###   ### ###
###…### ###…### ###…### ###   ###
###…..#####…..#####…..#####     ##
##…….###…….###…….###
###…..#####…..#####…..#####     ##
###…###.###…###.###…###.###   ###
  ###.###…###.###…###.###…### ###
   #####…..#####…..#####…..#####
    ###…….###…….###…….###
   #####…..#####…..#####…..#####
  ###.###…###.###…###.###…###.###
###…###.###…###.###…###.###…###
###…..#####…..#####…..#####…..##
##…….###…….###…….###…….#
###…..#####…..#####…..#####…..##
###…### ###…### ###…### ###…###
  ###.###   ###.###   ###.###   ###.###
   #####     #####     #####     #####

11.7.3 Frases políndromas
Este programa ilustra el uso de vectores abiertos. Se trata de comprobar si una frase es un políndromo, esto es, si las letras de las que consta se leen igual hacia adelante que hacia atrás. Para ello se define un procedimiento LeerTexto, capaz de leer un vector de caracteres de cualquier longitud. Este procedimiento sólo guarda las letras válidas de la "a" a la "z" y finaliza cuando se introduce un punto "." o se llena el vector pasado como argumento.

La función Simetrico es la encargada de comprobar que el contenido del vector abierto, pasado como argumento por valor, es simétrico. Primeramente, se busca el punto de final del texto a analizar o el final del vector. Esto se hace mediante el esquema típico de búsqueda. La posición final se decrementa en uno después de la búsqueda para apuntar al primer carácter válido Después, se comprueba si coinciden los caracteres de un extremo con los del otro. Esta comprobación acaba o bien cuando se cruzan los índices y todos los caracteres han sido iguales o bien cuando no coinciden algunos de ellos.

El listado completo del programa es el siguiente:

(**************************************************************************************************
*
*   Programa: Palindromo
*
*   Descripción:
*      Este programa comprueba si una frase es un palindromo.
*
**************************************************************************************************)
MODULE Palindromo;
   FROM InOut IMPORT
      WriteString, WriteLn, Write, Read;

   CONST
      Fin = ".";
      Maximo = 100;            (* Máxima longitud de la frase *)

   TYPE
      TipoLong = [0..Maximo];
      TipoRistra = ARRAY TipoLong OF CHAR;
      Caracteres = SET OF CHAR;

   VAR
      frase : TipoRistra;

PROCEDURE LeerTexto( VAR Tex: ARRAY OF CHAR );
(*===============================================
Procedimiento para leer una frase acabada en un punto (.) y dejarla
en el argumento vector abierto. Solo se guardan en el vector las letras
de a..z mayúsculas o minúsculas y el punto final.
===============================================*)
   VAR   car: CHAR;   long: TipoLong;
BEGIN
   WriteString( "¿Frase acabada en punto(.)?"); WriteLn;
   long := 0;
   REPEAT
      Read(car);   Write(car);
      (*– Se comprueba si es un caracter correcto –*)
      IF car IN Caracteres{"A".."Z", "a".."z", Fin} THEN
         long := long + 1;   Tex[long] := CAP(car)
      END;
      (*– Se acaba al encontrar el punto o si se acaba el vector  –*)
   UNTIL (car = Fin) OR (long = HIGH(Tex));
END LeerTexto;

PROCEDURE Simetrico( Texto: ARRAY OF CHAR ): BOOLEAN;
(*===============================================
Función que comprueba si hay simetría entre las letras del
comienzo y las del final de una frase: es un palindromo. El
argumento pasado es de tipo vector abierto
===============================================*)
   VAR i, j: TipoLong;
BEGIN
(*– 1º Paso: Buscar el punto final (.) o final del vector –*)
   j := 0;
   WHILE (Texto[j] <> Fin) AND (j <= HIGH(Texto)) DO
      j := j + 1
   END;
   j := j – 1; i := 1;
(*– 2º Paso: Comprobar igualdad entre caracteres simetricos –*)
   WHILE (i < j) AND (Texto[i] = Texto[j]) DO
      i := i+1; j := j-1
   END;
   RETURN i >= j
END Simetrico;

BEGIN
   LeerTexto( frase );
   IF Simetrico( frase ) THEN
      WriteString( " Es Palindromo")
   ELSE
      WriteString( " No es Palindromo")
   END
END Palindromo.

El resultado de la ejecución del programa es el siguiente:

¿Frase acabada en punto(.)?
Dabale arroz a la zorra el abad. Es Palindromo

Un comentario en “Fundamentos de programación con Módula-2 (27)

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión /  Cambiar )

Google photo

Estás comentando usando tu cuenta de Google. Cerrar sesión /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión /  Cambiar )

Conectando a %s