Este sitio web usa cookies de terceros para analizar el tráfico y personalizar los anuncios. Si no está de acuerdo, abandone el sitio y no siga navegando por él. ×


Curso de Pascal. Tema 10: Pantalla en modo texto.

En este tema vamos a ver cómo acceder a la pantalla de texto, y algunos "bonus". :-)

Este tema va a ser específico de Turbo Pascal para DOS. Algunas de las cosas que veremos aparecen en otras versiones de Turbo Pascal (la 3.0 para CP/M, por ejemplo), pero no todas, y de cualquier modo, nada de esto es Pascal estándar. Aun así, como muchas versiones de Pascal posteriores (Tmt Pascal, Virtual Pascal, Free Pascal, etc) buscan una cierta compatibilidad con Turbo Pascal, es fácil que funcione con muchos compiladores recientes.

Me centraré primero en cómo se haría con las versiones 5.0 y superiores de Turbo Pascal. Luego comentaré cómo se haría con Turbo Pascal 3.01.

Vamos allá... En la mayoría de los lenguajes de programación, existen "bibliotecas" (en inglés, "library") con funciones y procedimientos nuevos, que permiten ampliar el lenguaje. En Turbo Pascal, estas bibliotecas reciben el nombre de "unidades" (UNIT), y existen a partir de la versión 5.

Veremos cómo crearlas un poco más adelante, pero de momento nos va a interesar saber cómo acceder a ellas, porque "de fábrica" ;-) Turbo Pascal incorpora unidades que aportan mayores posibilidades de manejo de la pantalla en modo texto o gráfico, de acceso a funciones del DOS, de manejo de la impresora, etc.

Así, la primera unidad que trataremos es la encargada de gestionar (entre otras cosas) la pantalla en modo texto. Esta unidad se llama CRT.

Para acceder a cualquier unidad, se emplea la sentencia "uses" justo después de "program" y antes de las declaraciones de variables:

program prueba;

uses crt;
var
[...]

Voy a mencionar algunos de los procedimientos y funciones más importantes. Al final de esta lección resumo todos los que hay y para qué sirven.


Algunos "extras" no relacionados con la pantalla son:


Comentarios generales, la mayoría "triviales" guiño :


Aquí va un programita de ejemplo que maneja todo esto... o casi

 {--------------------------}
 {  Ejemplo en Pascal:      }
 {                          }
 {    Ejemplo de la unidad  }
 {    CRT: acceso a panta-  }
 {    lla en modo texto TP  }
 {    EJCRT.PAS             }
 {                          }
 {  Este fuente procede de  }
 {  CUPAS, curso de Pascal  }
 {  por Nacho Cabanes       }
 {                          }
 {  Comprobado con:         }
 {    - Turbo Pascal 7.0    }
 {    - Tmt Pascal Lt 1.01  }
 {--------------------------}

 program PruebaDeCRT;

 uses crt;

 var
   bucle : byte;
   tecla : char;

 begin
   ClrScr;                        { Borra la pantalla }
   TextColor( Yellow );           { Color amarillo }
   TextBackground( Red );         { Fondo rojo }
   GotoXY( 40, 13 );              { Vamos al centro de la pantalla }
   Write(' Hola ');               { Saludamos ;-) }
   Delay( 1000 );                 { Esperamos un segundo }
   Window ( 1, 15, 80, 23 );      { Ventana entre las filas 15 y 23 }
   TextBackground ( Blue );       { Con fondo azul }
   ClrScr;                        { La borramos para que se vea }
   for bucle := 1 to 100
     do WriteLn( bucle );         { Escribimos del 1 al 100 }
   WriteLn( 'Pulse una tecla..');
   tecla := ReadKey;              { Esperamos que se pulse una tecla }
   Window( 1, 1, 80, 25 );        { Restauramos ventana original }
   GotoXY( 1, 24 );               { Vamos a la penúltima línea }
   Write( 'Ha pulsado ', tecla ); { Pos eso }
   Sound( 220 );                  { Sonido de frecuencia 220 Hz }
   Delay( 500 );                  { Durante medio segundo }
   NoSound;                       { Se acabó el sonido }
   Delay( 2000 );                 { Pausa antes de acabar }
   TextColor( LightGray );        { Colores por defecto del DOS }
   TextBackground( Black );       { Y borramos la pantalla }
   ClrScr;
 end. 

Finalmente, veamos los cambios para Turbo Pascal 3.01: En TP3 no existen unidades, por lo que la línea "uses crt;" no existiría. La otra diferencia es que para leer una tecla se hace con "read(kbd, tecla);" (leer de un dispositivio especial, el teclado, denotado con kbd) en vez de con "tecla := readkey". Con estos dos cambios, el programa anterior funciona perfectamente.


Tema 10.2: Pantalla en modo texto con Surpas.

Para Surpas la cosa cambia un poco:


Con estas consideraciones, el programa (que aun así se parece) queda:

 {--------------------------}
 {  Ejemplo en Pascal:      }
 {                          }
 {    Pantalla de texto     }
 {    con Surpas            }
 {    EJCRTSP.PAS           }
 {                          }
 {  Este fuente procede de  }
 {  CUPAS, curso de Pascal  }
 {  por Nacho Cabanes       }
 {                          }
 {  Comprobado con:         }
 {    - Surpas 1.00         }
 {--------------------------}

 program PruebaDeCRT;

 { ----- Aqui empiezan las definiciones que hacen que SurPas
         maneje la pantalla de forma similar a Turbo Pascal  ------ }
         { Para comprender de donde ha salido esto, consulta el
           fichero IBMPC.DOC que acompaña a SURPAS }

 const
   Black       =  0;
   Blue        =  1;
   Green       =  2;
   Cyan        =  3;
   Red         =  4;
   Magenta     =  5;
   Brown       =  6;
   LightGray   =  7;
   DarkGray    =  8;
   LightBlue   =  9;
   LightGreen  = 10;
   LightCyan   = 11;
   LightRed    = 12;
   LightMagenta= 13;
   Yellow      = 14;
   White       = 15;

 procedure ClrScr;
 begin
   gotoxy(0,0);
   write( CLREOS );
 end;

 procedure TextColor(n: byte);
 begin
   write( chr(27), 'b', chr(n) );
 end;

 procedure TextBackground(n: byte);
 begin
   write( chr(27), 'c', chr(n) );
 end;

 { Se podrían añadir otras posibilidades, como TextMode, HighVideo y
   LowVideo, etc, siguiendo este esquema, si se cree necesario }

 { ----- Final del añadido ----- }
 var
   bucle : byte;
   tecla : char;
 begin
   ClrScr;                        { Borra la pantalla }
   TextColor( Yellow );           { Color amarillo }
   TextBackground( Red );         { Fondo rojo }
   GotoXY( 30, 13 );              { Vamos al centro de la pantalla }
   Write(' Hola. Pulse una tecla... ');               { Saludamos ;-) }
   read(kbd,tecla);               { Esperamos que se pulse una tecla }
   TextBackground ( Blue );       { Con fondo azul }
   ClrScr;                        { La borramos para que se vea }
   for bucle := 1 to 100
     do Write( bucle, ' ' );      { Escribimos del 1 al 100 }
   WriteLn;                       { Avanzamos una línea }
   WriteLn( 'Pulse otra tecla..');
   read(kbd,tecla);               { Esperamos que se pulse una tecla }
   GotoXY( 0, 12 );               { Vamos al centro de la pantalla }
   Write( 'Ha pulsado ', tecla ); { Pos eso }
   TextColor( LightGray );        { Colores por defecto del DOS }
   TextBackground( Black );       { Y borramos la pantalla }
   GotoXY( 0, 23 );               { Vamos a la penúltima línea }
 end.
  




Tema 10.3: Procedimientos y funciones en CRT.

Finalmente, y por eso de que lo prometido es deuda, va un resumen de los procedimientos y funciones que tenemos disponibles en la unidad CRT (comprobado con Turbo Pascal 7.0):

También tenemos las variables siguientes (cuyo valor podemos leer o cambiar):

Y como constantes (por ejemplo, para poder escribir el nombre de un color en vez de recordar qué número indica ese color, como hemos hecho en los ejemplos anteriores):

Las constantes que indican los modos de pantalla son:

Y por compatibilidad con la versión 3.0:


Pues hala, a experimentar...


Tema 10.4: Ejemplo: juego del ahorcado.


Antes de dejar el tema, un ejemplo sencillo que ponga a prueba algunas de las cosas que hemos visto: vamos a hacer el juego del ahorcado:

{--------------------------}
{  Ejemplo en Pascal:      }
{                          }
{    Juego del Ahorcado    }
{    AHORCA.PAS            }
{                          }
{  Este fuente procede de  }
{  CUPAS, curso de Pascal  }
{  por Nacho Cabanes       }
{                          }
{  Comprobado con:         }
{    - Free Pascal 2.2.0w  }
{    - Turbo Pascal 7.0    }
{    - Tmt Pascal Lt 1.20  }
{--------------------------}

Program Ahorcado;

Uses crt;

Var
  palabra, intento, letras:string; { La palabra a adivinar, la que }
                                   {   el jugador 2 va consiguiendo y }
                                   {   las letras que se han probado }
  oportunidades: integer;          { El número de intentos permitido }
  letra: char;                     { Cada letra que prueba el jug. dos }
  i: integer;                      { Para mirar cada letra, con "for" }
  acertado: boolean;               { Si ha acertado alguna letra }


begin
  clrscr;                        { Valores iniciales, del jugador 1 }
  gotoxy (10,5);
  write ('Jugador 1:  ¿Que frase hay que adivinar?  ');
  readln (palabra);
  gotoxy (10,7);
  write ('¿En cuantos intentos?  ');
  readln (oportunidades);

  intento := '';                 { Relleno con _ y " " lo que ve Jug. 2 }
  for i:=1 to length(palabra) do
    if palabra[i]= ' ' then
      intento:=intento+' '
    else
      intento:=intento+'_';

  repeat
    clrscr;
    gotoxy (10,6);               { Digo cuantos intentos le quedan }
    writeln('Te quedan ',oportunidades,' intentos');

    gotoxy (10,8);               { Le muestro cómo va }
    writeln(intento);

    gotoxy (10,10);              { Y le pido otra letra }
    write('Letras intentadas: ', letras);

    gotoxy (10,12);              { Y le pido otra letra }
    write('¿Qué letra? ');
    letra := readkey;
    letras := letras + letra;

    acertado := false;           { Miro a ver si ha acertado }
    for i:=1 to length(palabra) do
      if letra=palabra[i] then
        begin
        intento[i]:=palabra[i];
        acertado := true;
        end;

    if acertado = false then     { Si falló, le queda un intento menos }
      oportunidades := oportunidades-1;

  until (intento=palabra)        { Hasta que acierte }
    or (oportunidades=0);        { o gaste sus oportunidades }

  gotoxy(10, 15);                { Le felicito o le digo cual era }
  if intento=palabra then
    writeln('¡Acertaste!')
  else
    writeln('Lo siento.  Era: ', palabra);
end.

Esto es muy mejorable. La primera mejora será que no haya necesidad de que un primer jugador sea el que escriba la palabra a adivinar y el número de intentos, sino que el número de intentos esté prefijado en el programa, y exista una serie de palabras de las que el ordenador escoja una al azar (para lo que usaremos "random" y "randomize", que se ven con más detalle en la Ampliación 1):

 {--------------------------}
 {  Ejemplo en Pascal:      }
 {                          }
 {    Juego del Ahorcado    }
 {    (segunda version)     }
 {    AHORCA2.PAS           }
 {                          }
 {  Este fuente procede de  }
 {  CUPAS, curso de Pascal  }
 {  por Nacho Cabanes       }
 {                          }
 {  Comprobado con:         }
 {    - Free Pascal 2.2.0w  }
 {    - Turbo Pascal 7.0    }
 {    - Tmt Pascal Lt 1.20  }
 {--------------------------}

 Program Ahorcado2;

 Uses crt;

 Const
   NUMPALABRAS = 10;
   MAXINTENTOS = 2;
   datosPalabras: array[1..NUMPALABRAS] of string =
     (
     'Alicante','Barcelona','Guadalajara','Madrid',
     'Toledo','Malaga','Zaragoza','Sevilla',
     'Valencia','Valladolid'
     );

 Var
   palabra, intento, letras:string; { La palabra a adivinar, la que }
                                    {   el jugador 2 va consiguiendo y }
                                    {   las letras que se han probado }
   numeroPalabra: word;
   oportunidades: integer;          { El numero de intentos permitido }
   letra: char;                     { Cada letra que prueba el jug. dos }
   i: integer;                      { Para mirar cada letra, con "for" }
   acertado: boolean;               { Si ha acertado alguna letra }

 begin
   randomize;                     { Comienzo a generar numeros aleatorios }
   numeroPalabra :=               { Tomo una palabra al azar }
     random(NUMPALABRAS);
   palabra := datosPalabras[numeroPalabra+1];
   oportunidades := MAXINTENTOS;
   intento := '';                 { Relleno con _ y " " lo que ve Jug. 2 }
   for i:=1 to length(palabra) do
     if palabra[i]= ' ' then
       intento:=intento+' '
     else
       intento:=intento+'*';

   repeat
     clrscr;
     gotoxy (10,6);               { Digo cuantos intentos le quedan }
     writeln('Te quedan ',oportunidades,' intentos');
     gotoxy (10,8);               { Le muestro como va }
     writeln(intento);
     gotoxy (10,10);              { Y le pido otra letra }
     write('Letras intentadas: ', letras);
     gotoxy (10,12);              { Y le pido otra letra }
     write('¿Qué letra? ');
     letra := upcase(readkey);    { Convierto a mayusculas }
     letras := letras + letra;

     acertado := false;           { Miro a ver si ha acertado }
     for i:=1 to length(palabra) do
       if letra=upcase(palabra[i]) then
         begin                    { Comparo en mayusculas }
         intento[i]:=palabra[i];
         acertado := true;
         end;
     if acertado = false then     { Si falla, le queda un intento menos }
       oportunidades := oportunidades-1; 
   until (intento=palabra)        { Hasta que acierte }
     or (oportunidades=0);        { o gaste sus oportunidades } 
   gotoxy(10, 15);                { Le felicito o le digo cual era }

   if intento=palabra then
     begin
     gotoxy (10,8);
     writeln(intento);
     gotoxy(10, 15);
     writeln('¡Acertaste!')
     end
   else
     writeln('Lo siento.  Era: ', palabra);
 end.

Una segunda mejora podría ser que realmente "se dibujara" el ahorcado en pantalla en vez de limitarse a decirnos cuantos intentos nos quedan. Como todavía no sabemos manejar la pantalla en modo gráfico, dibujaremos de un modo rudimentario, empleando letras. El resultado será "feo", algo parecido a esto:



Y lo podríamos conseguir así:

 {--------------------------}
 {  Ejemplo en Pascal:      }
 {                          }
 {    Juego del Ahorcado    }
 {    (tercera version)     }
 {    AHORCA3.PAS           }
 {                          }
 {  Este fuente procede de  }
 {  CUPAS, curso de Pascal  }
 {  por Nacho Cabanes       }
 {                          }
 {  Comprobado con:         }
 {    - Free Pascal 2.2.0w  }
 {    - Turbo Pascal 7.0    }
 {    - Tmt Pascal Lt 1.20  }
 {--------------------------}

 Program Ahorcado3;

 Uses crt;

 Const
   NUMPALABRAS = 10;
   datosPalabras: array[1..NUMPALABRAS] of string =
     (
     'Alicante','Barcelona','Guadalajara','Madrid',
     'Toledo','Malaga','Zaragoza','Sevilla',
     'Valencia','Valladolid'
     );
   MAXINTENTOS = 5;  { No debe ser modificado: vamos a "dibujar" 5 cosas }

 Var
   palabra, intento, letras:string; { La palabra a adivinar, la que }
                                    {   el jugador 2 va consiguiendo y }
                                    {   las letras que se han probado }
   numeroPalabra: word;
   oportunidades: integer;          { El numero de intentos permitido }
   letra: char;                     { Cada letra que prueba el jug. dos }
   i: integer;                      { Para mirar cada letra, con "for" }
   acertado: boolean;               { Si ha acertado alguna letra }


 procedure PrimerFallo;       { Primer fallo: }
 var
   j: byte;                   { Dibujamos la "plataforma" }
 begin
   for j := 50 to 60 do
     begin
     gotoxy(j,20);
     write('-');
     end;
 end;


 procedure SegundoFallo;       { Segundo fallo: }
 var
   j: byte;                   { Dibujamos el "palo vertical" }
 begin
   for j := 14 to 19 do
     begin
     gotoxy(53,j);
     write('|');
     end;
 end;


 procedure TercerFallo;       { Tercer fallo: }
 var
   j: byte;                   { Dibujamos el "palo superior" }
 begin
   for j := 53 to 57 do
     begin
     gotoxy(j,14);
     write('-');
     end;
 end;

 procedure CuartoFallo;       { Cuarto fallo: }
 var
   j: byte;                   { Dibujamos la "plataforma" }
 begin
   gotoxy(57,15);
   write('|');
 end;


 procedure QuintoFallo;       { Quinto fallo: }
 var
   j: byte;                   { Dibujamos la "plataforma" }
 begin
   gotoxy(56,16);
   write(' O');
   gotoxy(56,17);
   write('/|\');
   gotoxy(56,18);
   write('/ \');

   for j := 50 to 60 do
     begin
     gotoxy(j,20);
     write('-');
     end;
 end;



 begin
   randomize;                     { Comienzo a generar numeros aleatorios }
   numeroPalabra :=               { Tomo una palabra al azar }
     random(NUMPALABRAS);
   palabra := datosPalabras[numeroPalabra+1];
   oportunidades := MAXINTENTOS;
   intento := '';                 { Relleno con _ y " " lo que ve Jug. 2 }
   for i:=1 to length(palabra) do
     if palabra[i]= ' ' then
       intento:=intento+' '
     else
       intento:=intento+'*';

   repeat
     clrscr;

                                  { Dibujo lo que corresponde del "patibulo" }
     if oportunidades <= 4 then PrimerFallo;
     if oportunidades <= 3 then SegundoFallo;
     if oportunidades <= 2 then TercerFallo;
     if oportunidades <= 1 then CuartoFallo;

     gotoxy (10,6);               { Digo cuantos intentos le quedan }
     writeln('Te quedan ',oportunidades,' intentos');
     gotoxy (10,8);               { Le muestro como va }
     writeln(intento);
     gotoxy (10,10);              { Y le pido otra letra }
     write('Letras intentadas: ', letras);
     gotoxy (10,12);              { Y le pido otra letra }
     write('¿Qué letra? ');
     letra := upcase(readkey);    { Convierto a mayusculas }
     letras := letras + letra;

     acertado := false;           { Miro a ver si ha acertado }
     for i:=1 to length(palabra) do
       if letra=upcase(palabra[i]) then
         begin                    { Comparo en mayusculas }
         intento[i]:=palabra[i];
         acertado := true;
         end;
     if acertado = false then     { Si falla, le queda un intento menos }
       oportunidades := oportunidades-1;
   until (intento=palabra)        { Hasta que acierte }
     or (oportunidades=0);        { o gaste sus oportunidades } 
                   { Le felicito o le digo cual era }

   if intento=palabra then
     begin
     gotoxy (10,8);
     writeln(intento);
     gotoxy(10, 15);
     writeln('¡Acertaste!')
     end
   else
     begin
     QuintoFallo;
     gotoxy(10, 15);
     writeln('Lo siento.  Era: ', palabra);
     end;
 end.


Tema 10.5: Ejemplo: entrada mejorada.

Finalmente, vamos a hacer algo mejor que el "readln". Crearemos una rutina de introducción de datos que permita corregir con mayor facilidad: en cualquier posición de la pantalla, limitando el tamaño máximo de la respuesta, desplazándonos con las flechas, usando las teclas Inicio y Fin, permitiendo insertar o sobreescribir, etc. Podría ser así:

{--------------------------}
{  Ejemplo en Pascal:      }
{                          }
{    Entrada mejorada de   }
{    datos                 }
{    ENTRMEJ.PAS           }
{                          }
{  Este fuente procede de  }
{  CUPAS, curso de Pascal  }
{  por Nacho Cabanes       }
{                          }
{  Comprobado con:         }
{    - Turbo Pascal 7.0    }
{    - Turbo Pascal 5.0    }
{--------------------------}

{
  PIDEXY: Entrada mejorada de datos.
  - En cualquier posición de la pantalla.
  - Muestra el tamaño máximo y lo limita.
  - Permite usar las flechas, Inicio, Fin, Ctrl+Flechas, Supr.
  - Modo de inserción o sobreescritura.

 -- Esto es parte de CUPAS, curso de Pascal por Nacho Cabanes --

 -- Este ejemplo sólo funcionará en Turbo Pascal 5.0 o superior --

 Mejoras posibles no incluidas:
  - Cambiar la forma del cursor según se esté en modo de inserción o
    sobreescritura.
  - Quitar los espacios sobrantes a la derecha de la palabra.
  - Permitir la edición en varias líneas.
  - Seguro que alguna más...  :-)
}

uses crt;


FUNCTION SPC(n:byte):string;             {Espacios en blanco}
var b:string; c:byte;
begin
 b:='';
 for c:=1 to n do b:=b+' ';
 spc:=b
end;


PROCEDURE PIDEXY(var valor:string; long:byte; x,y:byte; nuevo:boolean);
  { Valor: la variable en la que se va a devolver }
  { Long: longitud máxima permitida }
  { x,y: posición en pantalla }
  { Nuevo: ¿borrar el contenido anterior de "valor"? }

var
  i,fila,posix,posiy: byte;  {bucles, fila, posición, inicial, final}
  inicial,final:byte;           { inicial, final }
  tecla:char;                { tecla que se pulsa }
  insertar:boolean;          { ¿modo de inserción? }

begin
  if nuevo=true then valor:='';
  gotoxy(x,y);
  fila:=wherey;
   write('['); ;
  for i:=1 to long do write('·');            { Para que se vea mejor }
   write(']'); ;
  for i:=length(valor) to long-1 do valor:=valor+'·';
  insertar:=false;
  posix:=1;
  posiy:=y;
  repeat
    gotoxy(x+1,y);
    write(valor);
    gotoxy(posix+x,y);
    tecla:=readkey;                           { Lee una pulsación }

    if ord(tecla)=0 then                      { Si es tecla de función }
      case ord(readkey) of
      { Flecha izquierda }
      75: if posix>1 then posix:=posix-1;
      { Flecha derecha }
      77: if posix' ')
           then posix:=i+1;
           if  posix=inicial then posix:=1
           end;
      { Ctrl + -> }
      116: for i:=long-1 downto posix do
             if (valor[i]=' ') and (valor[i+1]<>' ') then posix:=i+1;
      end
    else                                    { Si es carácter imprimible }
      if tecla>=' ' then
      if not insertar then                  { Si no hay que insertar }
        begin
        valor[posix]:=tecla;                { Reemplaza }
        if posix1) then
        begin
        for i:=posix-1 to long-1 do valor[i]:=valor[i+1];
        valor[long]:='·';
        posix:=posix-1
        end;
  until ord(tecla)=13;                   { Hasta pulsar INTRO }

  for i:=1 to length(valor) do           { Al terminar, pone espacios }
     if valor[i]='·' then valor[i]:=' ';
  gotoxy(x,y); write(' ' + valor + ' '); { Y muestra el resultado }
end;


{ --- Mini-Programa de prueba --- }

var
  nombre: string;

begin
  clrscr;
  gotoxy(3,3); write( '¿Cómo te llamas?' );
  pidexy( nombre, 20, 3,4, TRUE );
  gotoxy(3, 10); writeln( 'Tu nombre es: ', nombre );
  readln;
end.