program Minhoca;
uses crt,dfs;


{Graficos}
const
GameOverLinhas=9;
GameOverColunas=58;
GameOverStr:array[0..GameOverLinhas-1] of string[GameOverColunas]=(
'                                                          ',
' @@@@@  @@@@@  @   @  @@@@@    @@@@@  @   @  @@@@@  @@@@@ ',
' @   @  @   @  @@ @@  @        @   @  @   @  @      @   @ ',
' @      @   @  @ @ @  @        @   @  @   @  @      @   @ ',
' @ @@@  @@@@@  @ @ @  @@@@@    @   @  @   @  @@@@@  @@@@@ ',
' @   @  @   @  @   @  @        @   @  @   @  @      @ @   ',
' @   @  @   @  @   @  @        @   @   @ @   @      @  @  ',
' @@@@@  @   @  @   @  @@@@@    @@@@@    @    @@@@@  @   @ ',
'                                                          ');


{Importantes}
const
  TelaTamX=48; {Precisa ser menor que 255}
  TelaTamY=48; {Precisa ser menor que 255}
  TelaX=1;
  TelaY=1;

  TamMax=2000;

  CharCorpo='#';
  CorCorpo =  2;

  CharFundo=' ';
  CorFundo = 15;

  CharMaca ='@';
  CorMaca  = 12;

  NumMacas=10;


var
  {Minhoca}
  a  : array[0..TamMax] of word; {Array principal com as posicoes da minhoca}
  ap : Pointer;               {Ponteiro para ele, acima}

  tam    : word;    {Indica o tamanho da minhoca}
  cabeca : word;    {Indica a posicao da cabeca no array}
  cauda  : word;    {Indica a posicao da cauda no array}
  direcao: byte;    {Indica para onde ela esta se movendo}
                    {0 ->    1 v     2 <-    3 ^     }
  colisao: boolean; {Indica se houve uma colisao}
  comeu  : boolean; {Indica se a minhoca acabou de comer uma maca}

  {Outros}
  key    : char; {Readkey}
  tempo  : word;


function getX(coord:word):byte;assembler;
{Eh o mesmo que Lo(coord)}
asm
  mov ax,[coord]
  add al,TelaX
end;


function getY(coord:word):byte;assembler;
{Eh o mesmo que Hi(coord)}
asm
  mov ax,[coord]
  mov al,ah
  add al,TelaX
end;


procedure contorno;
var i:byte;
begin
  putchar(TelaX-1,TelaY-1,#201);
  for i:=1 to TelaTamX do
    putchar(TelaX+i-1,TelaY-1,#205);
  putchar(TelaX+TelaTamX,TelaY-1,#187);

  for i:=1 to TelaTamY do begin
    putchar(TelaX-1,TelaY+i-1,#186);
    putchar(TelaX+TelaTamX,TelaY+i-1,#186);
  end;

  putchar(TelaX-1,TelaY+TelaTamY,#200);
  for i:=1 to TelaTamX do
    putchar(TelaX+i-1,TelaY+TelaTamY,#205);
  putchar(TelaX+TelaTamX,TelaY+TelaTamY,#188);
end;


procedure showinfo;
begin
end;


procedure showinfoestatica;
begin
  putPChar(51, 5,'    Jogo da Minhoca');
  putPChar(51, 9,'Criado por');
  putPChar(51,10,'        Denilson');

  putPChar(51,40,'Setas - Comandam a minhoca');
  putPChar(51,41,'F2    - Recoma‡a o jogo');
end;


procedure criarmaca;
var x,y:byte;
begin
  repeat
    x:=random(TelaTamX);
    y:=random(TelaTamY);
  until getchar(x+TelaX,y+TelaY)=CharFundo;
  putcharcor(x+TelaX,y+TelaY,CharMaca,CorMaca);
end;


procedure iniciar;
var i:byte;
begin
  {Inicializacao de variaveis}
  tam:=1;
  cabeca:=0;
  cauda:=0;
  direcao:=0;
  colisao:=false;
  comeu:=false;
  tempo:=100;
  a[0]:=(TelaTamY div 2) shl 8 + (TelaTamX div 2);

  {Prepara a tela}
  limpatela80x50(CharFundo,15);
  contorno;
  showinfoestatica;
  putcharcor(getX(a[cabeca]),getY(a[cabeca]),CharCorpo,CorCorpo);
  for i:=1 to NumMacas do criarmaca
end;


procedure gameover;
var i,x,y:byte;
begin
  x:=(80-GameOverColunas) shr 1; {"shr 1" = "div 2"}
  y:=(50-GameOverLinhas ) shr 1; {"shr 1" = "div 2"}
  for i:=0 to GameOverLinhas-1 do
    putstrcor(x,y+i,GameOverStr[i],$03);
end;


procedure comemaca;
begin
  inc(tam);
  dec(cauda);
  comeu:=true;
  criarmaca;
end;


procedure colisoes;
var x,y:byte;
begin
{Esta ‚ a forma mais simples possˇvel}

  x:=getX(a[cabeca]);
  y:=getY(a[cabeca]);

  if (lo(a[cabeca])>=TelaTamX) OR (hi(a[cabeca])>=TelaTamY) then colisao:=true
  else if getchar(x,y) = CharMaca then comemaca
  else if getchar(x,y) <> CharFundo then colisao:=true;
end;


procedure vaiminhoca;
var old:word;
begin
  old:=a[cabeca];
  inc(cabeca);
  if cabeca=TamMax then cabeca:=0;
  case direcao of
    0 : a[cabeca]:=old+1;
    1 : a[cabeca]:=old+$100;
    2 : a[cabeca]:=old-1;
    3 : a[cabeca]:=old-$100;
  end;

  colisoes;

  if NOT colisao then begin
    putcharcor(getX(a[cabeca]),getY(a[cabeca]),CharCorpo,CorCorpo);
    if comeu then comeu:=false
    else putcharcor(getX(a[cauda]),getY(a[cauda]),CharFundo,CorFundo);
  end;

  inc(cauda);
  if cauda=TamMax then cauda:=0;
end;


procedure comandaminhoca;
var novadir:byte;
begin
  novadir:=direcao;
  pausar(tempo);
  while keypressed do begin
    key:=readkey;

    case key of
{Esc} #27 : break;

      #0  : begin
        key:=readkey;
        case key of
{F2}      #60 : begin iniciar; break; end;

          #77 : begin novadir:=0; end;
          #80 : begin novadir:=1; end;
          #75 : begin novadir:=2; end;
          #72 : begin novadir:=3; end;
        end; {case 2}
      end; {key=#0}

    end; {case 1}

  end; {while true}

       if (direcao=0) AND NOT (novadir=2) then direcao:=novadir
  else if (direcao=1) AND NOT (novadir=3) then direcao:=novadir
  else if (direcao=2) AND NOT (novadir=0) then direcao:=novadir
  else if (direcao=3) AND NOT (novadir=1) then direcao:=novadir;

end;


BEGIN

SetText80x50;
Randomize;
Iniciar;

{INICIO}
repeat
  comandaminhoca;
  vaiminhoca;
  showinfo;
  if colisao then gameover;
until key=#27;

{Finalizacao do programa}
SetText80x25;

END.
