Programación en Pascal/Ejemplo

El siguiente ejemplo puede ejecutarse tanto en Linux como en Windows (en modo MS-DOS).

Para ejecutarlo en Linux, es necesario instalar la librería svgalib, y ejecutar el programa con permisos de superusuario:

$ sudo ./Serpiente2

Aunque el ejemplo es antiguo y utiliza librerías desfasadas, es un buen ejemplo de lo que se puede hacer con poquito código en Pascal. En otras partes de este curso iremos poniendo ejemplos más modernos usando Lazarus.

program Serpiente2;
(*******************************************
 * Por Victor Barbero Romero - Oct. 2.001   *
 * vbarbero@movistar.com o @telefonica.net  *
 *                                          *
 *******************************************) {v2.0e}
uses crt, Graph;
const
   DLY = 2;
   {Cambiar este valor para hacer el juego más lento.}
type
   Puntuaci = record
		 name : string[15];
		 punt : integer;
	      end;
var
   MaxPtosPar, PtosPar, PtosTot : integer;
   PosX, PosY, BolaX, BolaY, IncrmX, IncrmY : shortint;
   Lab, c, NumArray, Rtraso : shortint;
   datmem, mejora, basta, Sonido, definal : boolean;
   ColaX, ColaY : array[1..40] of shortint;
   Laberinto : array[1..1850] of boolean;
   marca : array[1..6] of Puntuaci;
   P : file of Puntuaci;
   TipoMov : char;
   
procedure IniciaVideo;
var
   Driver, Modo : smallint;
begin
   Driver := VGA;  { Modo := VGAHi; }
   Modo := G640x480x256; { Cambiado debido a problemas con algunas resoluciones gráficas }
   InitGraph(Driver,Modo,'.BGI');
end;

procedure AbreVentana(PX, PY, Anch, Alto : integer; Titulo : string);
var
   contaX, differ, alter, tlitb : integer;
   tapavent : array[1..12] of integer;
begin
   alter := PX + Anch - (Anch div 5);
   tlitb := alter + 20;
   differ := PX - PY;
   
   tapavent[1] := PX; tapavent[2] := PY;
   tapavent[3] := PX; tapavent[4] := PY+Alto;
   tapavent[5] := PX+Anch; tapavent[6] := PY+Alto;
   tapavent[7] := PX+Anch; tapavent[8] := PY+(Anch div 5);
   tapavent[9] := alter; tapavent[10] := PY;
   tapavent[11] := PX; tapavent[12] := PY;
   setcolor(0); setfillstyle(1,0);
   fillpoly(6,tapavent);
   
   setcolor(7);
   line(PX-1, PY, alter, PY);
   line(PX-1, PY-1, alter, PY-1);
   for contaX := PX to PX+Anch do
   begin
      if contaX-differ < PY+Alto+1 then
      begin putpixel(PX, contaX-differ, 7);
	 putpixel(PX-1, contaX-differ, 7); end;
      if contaX-differ < PY+Alto+1 then
      begin putpixel(alter, contaX-differ, 7);
	 putpixel(alter+1, contaX-differ, 7); end;
      if alter < PX+Anch then alter := alter + 1;
      putpixel(contaX, PY+Alto, 7);
      putpixel(contaX-1, PY+Alto+1, 7);
      if contaX < tlitb then putpixel(contaX, PY+20, 7);
      Delay(4*DLY);
   end;
   putpixel(PX+Anch+1, PY+Alto+1, 7);
   putpixel(PX+Anch, PY+Alto+1, 7);
   setfillstyle(9,8);
   floodfill(PX+(Anch div 2), PY+3, 7);
   setfillstyle(10,8); floodfill(PX+(Anch div 2), PY+25, 7);
   setcolor(15);
   outtextxy(PX+12, PY+7, Titulo);
end;

procedure CreaFichero;
begin
   {$I-} rewrite(P); {$I+}
   for c := 1 to 6 do begin
      marca[c].name := '- - -';
      marca[c].punt := 0;
      seek(P,c); write(P,marca[c]);
   end;
end;

procedure ManejaFichero;
var
   report : integer;
begin
   assign(P,'srp2pnt.fps');
   {$I-} reset(P); {$I+}
   report := IOResult;
   if report <> 0 then begin CreaFichero; end else begin
      for c := 1 to 6 do begin
	 seek(P,c); read(P, marca[c]);
      end; end; close(P);
   datmem := true;
end;

procedure GrabaPunts;
var
   reprt : integer;
begin
   assign(P,'srp2pnt.fps');
   {$I-} reset(P); {$I+}
   reprt := IOResult;
   if reprt <> 0 then begin CreaFichero; end else begin
      for c := 1 to 6 do begin
	 seek(P,c); write(P, marca[c]);
      end; end;
   close(P);
end;

procedure MuestraPunts;
var
   puntos : string[5];
begin
   AbreVentana(150,140,300,250,'Mejores puntuaciones');
   if datmem = false then ManejaFichero;
   setcolor(7);
   outtextxy(175,185,'PUNTOS');
   outtextxy(300,185,'NOMBRE');
   line(160,198, 420,198); line(236,180, 236,380);
   setfillstyle(1,0); setcolor(0);
   for c := 1 to 6 do begin
      bar(165,175+(30*c), 225,190+(30*c));
      bar(250,175+(30*c), 410,190+(30*c));
      str(marca[c].punt, puntos);
      setcolor(11); outtextxy(175,180+(30*c), puntos);
      setcolor(9); outtextxy(260,180+(30*c), marca[c].name);
   end;
   readkey;
end;

procedure OrdenaPunts;     {Utiliza el Algoritmo Bubble Short}
var
   d : shortint;
   puntcambio : integer;
   namecambio : string[15];
begin
   for c:= 1 to 6 do
   begin
      for d := c+1 to 6 do
      begin
	 if marca[d].punt > marca[c].punt then
	 begin
	    puntcambio := marca[c].punt;
	    marca[c].punt := marca[d].punt;
	    marca[d].punt := puntcambio;
	    namecambio := marca[c].name;
	    marca[c].name := marca[d].name;
	    marca[d].name := namecambio;
	 end;
      end;
   end;
end;

procedure CompruebaMejora;
var
   Nombre : string[15];
begin
   if datmem = false then begin ManejaFichero; end;
   for c:= 1 to 6 do begin
      if PtosTot > marca[c].punt then mejora := true;
   end;
   if mejora then begin
      AbreVentana(140,150,250,110,'­Enhorabuena!');
      setcolor(7);
      outtextxy(159,193,'­Ha superado un record!');
      if Sonido then begin
	 Sound(293); Delay(193*DLY); NoSound; Delay(27*DLY);
	 Sound(293); Delay(110*DLY); NoSound; Sound(293); Delay(110*DLY);
	 Sound(440); Delay(330*DLY); Sound(293); Delay(110*DLY);
	 Sound(440); Delay(440*DLY); NoSound; end;
      outtextxy(160,208,'Introduzca su nombre:');
      setfillstyle(1,0); setcolor(0);
      bar(160,223, 320,237); textcolor(9);
      gotoxy(22,15); readln(Nombre);
      marca[6].punt := PtosTot; marca[6].name := Nombre;
      OrdenaPunts; GrabaPunts;
   end;
   MuestraPunts;
end;

procedure CamSonido;
var SonSim : string[1];
begin
   SonSim := #14;
   if Sonido then begin
      setcolor(0); outtextxy(585,5,SonSim); Sonido := false; end
      else begin
	 setcolor(2); outtextxy(585,5,SonSim); Sonido := true; end;
end;

procedure FinJuego;
begin
   cleardevice;
   AbreVentana(175,130,275,150,'FIN');
   setcolor(14); outtextxy(235,185,'S E R P I E N T E');
   setcolor(7); outtextxy(192,240,'Victor Barbero - Octubre 2.001');
   Delay(2000*DLY);
   basta := true; definal := true;
end;

procedure CambiaNivel;
var
   Nivel : shortint;
   c : char; nvl : string[1];
   procedure PintaCuad(num,tipo : shortint);
   begin
      if tipo = 1 then setfillstyle(1,9);
      if tipo = 0 then setfillstyle(4,9);
      str(num,nvl); bar(210+(30*num),210, 230+(30*num),230);
      if tipo = 1 then begin setcolor(11);
	 outtextxy(215+(30*num), 220, nvl); end;
   end;
   procedure TeclaDerecha;
   begin
      if Nivel < 5 then
      begin
	 PintaCuad(Nivel+1,1);
	 Nivel := Nivel + 1;
      end; c := 'A';
   end;
   procedure TeclaIzquierda;
   begin
      if Nivel > 1 then
      begin
	 PintaCuad(Nivel,0);
	 Nivel := Nivel - 1;
      end; c := 'A';
   end;
begin
   AbreVentana(195,150,240,110,'Nivel'); setcolor(7);
   outtextxy(240,190,'Mayor dificultad'); outtextxy(375,190,#26);
   outtextxy(260,240,#27); outtextxy(350,240,#26);
   setcolor(1); rectangle(239,209, 261,231); rectangle(238,208, 262,232);
   rectangle(269,209, 291,231); rectangle(268,208, 292,232);
   rectangle(299,209, 321,231); rectangle(298,208, 322,232);
   rectangle(329,209, 351,231); rectangle(328,208, 352,232);
   rectangle(359,209, 381,231); rectangle(358,208, 382,232);
   PintaCuad(1,1); PintaCuad(2,1); PintaCuad(3,1);
   PintaCuad(4,0); PintaCuad(5,0); Nivel := 3;
   repeat
      if Keypressed then c := readkey;
      case c of
	#75 : TeclaIzquierda;
	#77 : TeclaDerecha;
      end;
   until c=#13;
   case Nivel of
     1 : begin MaxPtosPar := 9+Lab; Rtraso := 100; end;
     2 : begin MaxPtosPar := 14+Lab; Rtraso := 85; end;
     3 : begin MaxPtosPar := 19+Lab; Rtraso := 75; end;
     4 : begin MaxPtosPar := 24+Lab; Rtraso := 65; end;
     5 : begin MaxPtosPar := 39+Lab; Rtraso := 53; end;
   end;
   setfillstyle(1,0); bar(568,4, 578,13);
   setcolor(15); str(Nivel,nvl); outtextxy(569,5,nvl);
end;

procedure PintaLabs;
var
   x, y : shortint;
begin
   setfillstyle(11,6);
   for x := 1 to 50 do
   begin
      for y := 1 to 37 do
      begin
	 if Laberinto[((y-1)*50)+x] = true then begin
	    setcolor(12);
	    rectangle(8+(x*12), 6+(y*12), 20+(x*12), 18+(y*12));
	    setcolor(6);
	    rectangle(9+(x*12), 7+(y*12), 19+(x*12), 17+(y*12));
	    floodfill(14+(x*12), 12+(y*12), 6);
	 end;
      end;
   end;
end;

procedure EligeLaberinto;
var cn : char;
   procedure BorraLabAnter;
   var P : integer;
   begin
      for P := 1 to 1850 do
      begin
	 Laberinto[P] := false;
      end;
   end;
   procedure Lab2;
   var P : integer;
   begin
      for P := 601 to 626 do begin Laberinto[P] := true; end;
      for P := 1224 to 1250 do begin Laberinto[P] := true; end;
      for P := 438 to 450 do begin Laberinto[P] := true; end;
      for P := 1451 to 1463 do begin Laberinto[P] := true; end;
   end;
   procedure Lab3;
   var P : integer;
   begin
      P := 260;
      while P < 1610 do begin
	 P := P + 50;
	 Laberinto[P] := true;
	 Laberinto[P+31] := true;
      end;
      for P := 901 to 911 do begin Laberinto[P] := true; end;
      for P := 990 to 1000 do begin Laberinto[P] := true; end;
   end;
   procedure Lab4;
   var P : integer;
   begin
      P := 20;
      while P < 756 do begin
	 case P of
	   265 :; 216 :; 167 :;
	 else Laberinto[P] := true; end;
	 P := P + 49;
      end; Laberinto[19] := true; Laberinto[18] := true;
      Laberinto[751] := true; Laberinto[754] := true;
      Laberinto[752] := true; Laberinto[753] := true;
      P := 1683;
      while P > 1028 do begin
	 Laberinto[P] := true;
	 P := P - 49;
      end; Laberinto[68] := true;
      Laberinto[1046] := true; Laberinto[1050] := true;
      Laberinto[1047] := true; Laberinto[1048] := true;
      Laberinto[1049] := true;
      P := 525;
      while P < 1000 do begin
	 Laberinto[P] := true;
	 Laberinto[P+245] := true;
	 P := P + 51;
      end;
      for P := 1501 to 1513 do begin Laberinto[P] := true; end;
   end;
   procedure TAbajo;
   begin
      if Lab < 4 then begin
	 setcolor(11); setfillstyle(1,11);
	 bar(225,135+(20*(Lab+1)), 230,140+(20*(Lab+1)));
	 bar(383,135+(20*(Lab+1)), 388,140+(20*(Lab+1)));
	 cn := 'A'; Lab := Lab + 1; end;
   end;
   procedure TArriba; begin
      if Lab > 1 then begin
	 setcolor(0); setfillstyle(1,0);
	 bar(225,135+(20*Lab), 230,140+(20*Lab));
	 bar(383,135+(20*Lab), 388,140+(20*Lab));
	 cn := 'A'; Lab := Lab - 1; end;
   end;
begin
   AbreVentana(215,120,190,114,'Laberinto');
   setcolor(9);
   line(222,149, 232,149); line(221,149, 221,166);
   line(222,166, 232,166); line(391,149 ,381,149);
   line(392,149, 392,166); line(381,166, 391,166);
   line(222,169, 232,169); line(221,169, 221,186);
   line(222,186, 232,186); line(391,169 ,381,169);
   line(392,169, 392,186); line(381,186, 391,186);
   line(222,189, 232,189); line(221,189, 221,206);
   line(222,206, 232,206); line(391,189 ,381,189);
   line(392,189, 392,206); line(381,206, 391,206);
   line(222,209, 232,209); line(221,209, 221,226);
   line(222,226, 232,226); line(391,209 ,381,209);
   line(392,209, 392,226); line(381,226, 391,226);
   setfillstyle(1,0); setcolor(7);  Lab := 1;
   bar(223,150, 390,165); outtextxy(260,155,'Sin laberinto');
   bar(223,170, 390,185); outtextxy(260,175,'Laberinto 1');
   bar(223,190, 390,205); outtextxy(260,195,'Laberinto 2');
   bar(223,210, 390,225); outtextxy(260,215,'Laberinto 3');
   outtextxy(395,165,#24); outtextxy(395,204,#25);
   setcolor(11); setfillstyle(1,11);
   bar(225,155, 230,160); bar(383,155, 388,160);
   repeat
      if Keypressed then cn := readkey;
      case cn of
	#72 : TArriba;
	#80 : TAbajo;
      end;
   until cn=#13;
   BorraLabAnter;
   case Lab of 2 : Lab2; 3 : Lab3; 4 : Lab4; end;
end;

procedure BorraMenu;
begin
   setfillstyle(1,0); floodfill(320, 240, 12);
   setfillstyle(1,10);
   bar(14+(BolaX*12)-2, 12+(BolaY*12)-2, 14+(BolaX*12)+2, 12+(BolaY*12)+2);
   if definal = false then PintaLabs;
   setcolor(14);
end;

procedure Presentacion;
begin
   cleardevice;
   AbreVentana(130,100,380,190,'­Bienvenido!');
   setcolor(14); outtextxy(180,170,'S E R P I E N T E');
   setcolor(7); outtextxy(379,170,'v2.0');
   outtextxy(180,220,'Presione ESC durante el juego');
   outtextxy(235,240,'para entrar en el men£');
   outtextxy(155,268,'Pulse cualquier tecla para continuar');
   readkey;
end;

procedure Menu;
var
   c : char;
begin
   AbreVentana(180,125,250,180,'MENU');
   setcolor(7);
   outtextxy(200,180, '1.- Cambiar el nivel.');
   case Sonido of
     true : outtextxy(200,200, '2.- Desactivar sonido.');
     false : outtextxy(200,200, '2.- Activar sonido.');
   end;
   outtextxy(200,220, '3.- Volver al juego.');
   outtextxy(200,240, '4.- Salir del juego.');
   outtextxy(200,260, '5.- Ver las puntuaciones.');
   repeat
      if Keypressed then c := readkey;
   until ((c > #48) and (c < #54));
   case c of
     #49 : CambiaNivel;
     #50 : CamSonido;
     #52 : begin CompruebaMejora; FinJuego; end;
     #53 : MuestraPunts;
   end;
   BorraMenu;
end;

procedure IniciaCampo;
begin
   cleardevice;
   setcolor(12);
   rectangle(20,17,620,462);
   rectangle(19,18,621,463);
   rectangle(410,2,600,15);
   setfillstyle(6,4);
   floodfill(320,10,12);
   setcolor(7); outtextxy(415,5,'Puntos:');
   outtextxy(520,5,'Nivel:');
   for c := 1 to 30 do begin
      ColaX[c] := 0; ColaY[c] := 0; end;
   setcolor(14);
   rectangle(106,68, 114,76); ColaX[3] := 8; ColaY[3] := 5;
   rectangle(118,68, 126,76); ColaX[2] := 9; ColaY[2] := 5;
   rectangle(130,68, 138,76); ColaX[1] := 10; ColaY[1] := 5;
   IncrmX := 1; IncrmY := 0; PosX := 11; PosY := 5; NumArray := 3;
   BolaX := 15; BolaY := 15; TipoMov := 'D'; basta := false;
   PtosTot := 0; PtosPar := 0; mejora := false;
end;

procedure PintaCabeza;
begin
   setcolor(9);
   rectangle(10+(PosX*12), 8+(PosY*12), 18+(PosX*12), 16+(PosY*12));
   setcolor(14);
   rectangle(10+(ColaX[1]*12), 8+(ColaY[1]*12), 18+(ColaX[1]*12), 16+(ColaY[1]*12));
end;

procedure BorraCola;
begin
   setcolor(0);
   rectangle(10+(ColaX[NumArray-1]*12), 8+(ColaY[NumArray-1]*12),
	     18+(ColaX[NumArray-1]*12), 16+(ColaY[NumArray-1]*12));
   for c := NumArray downto 1 do
   begin
      ColaX[c] := ColaX[c-1];
      ColaY[c] := ColaY[c-1];
   end;
   ColaX[1] := PosX; ColaY[1] := PosY;
end;

procedure DetectaColision;
   procedure AvisoChoque;
   var t : char;
   begin
      AbreVentana(200,140,250,100,'GAME OVER');
      setcolor(7); outtextxy(215,190,'­­Se ha chocado!!');
      if Sonido then begin
	 Sound(367); Delay(200*DLY); Sound(352); Delay(200*DLY);
	 Sound(330); Delay(200*DLY); Sound(313); Delay(455*DLY);
	 NoSound; end;
      outtextxy(215,210,'¨Desea jugar otra vez [S/N]?');
      repeat if Keypressed then begin
	 t := readkey; t := upcase(t); end;
      until (t='S') or (t='N');
      CompruebaMejora;
      if t = 'N' then begin FinJuego; end;
      if t = 'S' then basta := true;
   end;
var
   Num : shortint;
begin
   if ((PosX<1) or (PosX>50) or (PosY<1) or (PosY>37)) then
   begin
      setcolor(12);
      circle(14+(ColaX[1]*12), 12+(ColaY[1]*12), 5);
      AvisoChoque;
   end;
   Num := NumArray;
   repeat
      if ((ColaX[Num] = PosX) and (ColaY[Num] = PosY)) then
      begin
	 setcolor(12);
	 circle(14+(PosX*12), 12+(PosY*12), 5);
	 AvisoChoque;
	 break;
      end;
      Num := Num - 1;
   until Num<3;
   if Laberinto[((PosY-1)*50)+PosX] = true then begin
      setcolor(12); circle(14+(ColaX[1]*12), 12+(ColaY[1]*12),5);
      AvisoChoque; end;
end;

procedure PintaComida;
var
   NA : string[6];
begin
   setfillstyle(1,0);
   bar(478,4, 510,12);
   bar(14+(BolaX*12)-2, 12+(BolaY*12)-2, 14+(BolaX*12)+2, 12+(BolaY*12)+2);
   PtosTot := PtosPar + PtosTot; PtosPar := MaxPtosPar;
   str(PtosTot, NA);
   setcolor(15); outtextxy(479,5,NA);
   setfillstyle(1,10);
   repeat
      BolaX := random(49)+1; BolaY := random(36)+1;
   until Laberinto[((BolaY-1)*50)+BolaX] = false;
   bar(14+(BolaX*12)-2, 12+(BolaY*12)-2, 14+(BolaX*12)+2, 12+(BolaY*12)+2);
   if NumArray < 30 then NumArray := NumArray + 1;
   if NumArray > 30 then Rtraso := Rtraso - 1;
   if Sonido then begin
      Sound(1056); Delay(15*DLY); Sound(938); Delay(15*DLY); Sound(734);
      Delay(15*DLY); Sound(528); Delay(15*DLY); NoSound; end;
end;

procedure LeeTecla;
   procedure TeclaArriba;
   begin
      if TipoMov <> 'B' then begin
	 IncrmX := 0; IncrmY := -1; TipoMov := 'A' end
	 else begin if Sonido then begin
	    Sound(83); Delay(10*DLY); NoSound; end; end;
      if PtosPar > 0 then PtosPar := PtosPar - 1;
   end;
   procedure TeclaIzquierda;
   begin
      if TipoMov <> 'D' then begin
	 IncrmX := -1; IncrmY := 0; TipoMov := 'I' end
	 else begin if Sonido then begin
	    Sound(83); Delay(10*DLY); NoSound; end; end;
      if PtosPar > 0 then PtosPar := PtosPar - 1;
   end;
   procedure TeclaDerecha;
   begin
      if TipoMov <> 'I' then begin
	 IncrmX := 1; IncrmY := 0; TipoMov := 'D' end
	 else begin if Sonido then begin
	    Sound(83); Delay(10*DLY); NoSound; end; end;
      if PtosPar > 0 then PtosPar := PtosPar - 1;
   end;
   procedure TeclaAbajo;
   begin
      if TipoMov <> 'A' then begin
	 IncrmX := 0; IncrmY := 1; TipoMov := 'B' end
	 else begin if Sonido then begin
	    Sound(83); Delay(10*DLY); NoSound; end; end;
      if PtosPar > 0 then PtosPar := PtosPar - 1;
   end;
var
   t : char;
begin
   if Keypressed then
   begin
      t := readkey;
      case t of
	#72 : TeclaArriba;
	#75 : TeclaIzquierda;
	#77 : TeclaDerecha;
	#80 : TeclaAbajo;
	#27 : Menu;
      end;
   end;
end;

procedure Juego;
begin
   PintaCabeza;
   if (BolaX = PosX) and (BolaY = PosY) then
   begin
      PintaComida;
   end;
   LeeTecla;
   BorraCola;
   PosX := PosX + IncrmX; PosY := PosY + IncrmY;
   DetectaColision;
   LeeTecla;
   Delay(Rtraso*DLY);
end;
begin
   clrscr; randomize;
   IniciaVideo; Presentacion;
   repeat
      IniciaCampo; EligeLaberinto; CambiaNivel; BorraMenu; PintaComida;
      repeat Juego; until basta;
   until definal;
   closegraph;
end.