USES
 BMPreader,graph,crt;

CONST
 name='FORGAME.BMP';
 razm=171;
 wX:integer = 400;
 wY:integer = 30;

TYPE
 myarray =array [0..5,0..5] of integer;

VAR
 grdriver,grmode:integer;
 h,w:integer;
 startX,startY : integer;
 p1,p2,p3 : pointer;
 curX,curY,x,y : integer;
 pole,obr : myarray;

PROCEDURE clearkeybuff;
 BEGIN
  while keypressed do readkey;
 END;

PROCEDURE obmen(var A,B:integer);
 VAR
  buff : integer;
 BEGIN
  buff:=A;
  A:=B;
  B:=buff;
 END;

FUNCTION win:boolean;
 BEGIN
  win:=FALSE;
  for h:=1 to 4 do
   for w:=1 to 4 do
    if pole[h,w]<>obr[h,w] then exit;
  win:=TRUE;
 END;

PROCEDURE beep;
 BEGIN
  sound(250);
  delay(2700);
  nosound;
 END;

PROCEDURE keybsong(tone:integer);
 CONST
  melody:array[0..51,1..2] of integer=(
         (0,0),(1046,200),(1046,200),(1174,400),(1046,400),
         (1398,400),(1318,800),(1046,200),(1046,200),(1174,400),
         (1046,400),(1568,400),(1398,800),(1046,200),(1046,200),
         (2092,400),(1760,400),(1398,400),(1318,400),(1174,800),
         (1864,200),(1864,200),(1760,400),(1398,400),(1668,400),
         (1398,800),(1046,200),(1046,200),(1174,400),(1046,400),
         (1398,400),(1318,800),(1046,200),(1046,200),(1174,400),
         (1046,400),(1568,400),(1398,800),(1046,200),(1046,200),
         (2092,400),(1760,400),(1398,400),(1318,400),(1174,800),
         (1864,200),(1864,200),(1760,400),(1398,400),(1568,400),
         (1398,800),(0,0));
 VAR
  i : integer;
 BEGIN
  sound(melody[tone][1]-600);
  for i:=1 to 4 do delay(melody[tone][2]*40);
 END;

PROCEDURE _keybsong(tone:integer);
 CONST
  melody : array[0..59,1..2] of integer =(
           (0,200),(0,200),(262,100),(220,100),(262,100),(220,100),
           (0,50),(247,50),(262,50),(220,100),(175,100),(262,100),
           (175,100),(0,50),(247,50),(262,50),(220,100),(175,100),(0,50),
           (175,50),(175,50),(175,50),(175,50),(220,50),(175,100),
           (262,100),(220,100),(220,100),(220,100),(0,50),(175,50),
           (175,50),(175,50),(175,50),(220,50),(175,100),(262,100),
           (220,100),(220,100),(220,100),(196,50),(220,50),(196,50),
           (220,50),(196,50),(220,50),(196,100),(196,50),(220,50),
           (247,50),(220,50),(196,50),(175,50),(196,100),(262,100),
           (220,100),(262,100),(220,100),(262,200),(0,200));
 VAR
  i : integer;
 BEGIN
  sound(melody[tone][1]+300);
  for i:=1 to 10 do delay(melody[tone][2]*40);
  nosound;
 END;

PROCEDURE _jingle;
 VAR
  k : integer;
 BEGIN
  k:=0;
  repeat
   _keybsong(k);
   k:=(k+1) mod 60;
  until keypressed;
 END;

PROCEDURE jingle;
 VAR
  k : integer;
 BEGIN
  k:=0;
  repeat
   keybsong(k);
   k:=(k+1) mod 51;
  until keypressed;
 END;

PROCEDURE mix;
 CONST
  max = 300;
 VAR
  xx,yy,i : integer;
  nx,ny : integer;
 BEGIN
  for yy:=1 to 4 do
   for xx:=1 to 4 do
    if pole[xx,yy]=0 then break;
  nx:=xx;
  ny:=yy;
  for i:=1 to max do
   begin
    case random(4) of
     0 : if nx>1 then dec(nx);
     1 : if ny>1 then dec(ny);
     2 : if nx<4 then inc(nx);
     3 : if ny<4 then inc(ny);
    end;
    obmen(pole[nx,ny],pole[xx,yy]);
    getimage((XX-1)*razm+startX,(YY-1)*razm+startY,XX*razm+startX,YY*razm+startY,p2^);
    getimage((nX-1)*razm+startX,(nY-1)*razm+startY,nX*razm+startX,nY*razm+startY,p3^);
    putimage((nX-1)*razm+startX,(nY-1)*razm+startY,p2^,copyput);
    putimage((XX-1)*razm+startX,(YY-1)*razm+startY,p3^,copyput);
    xx:=nx;
    yy:=ny;
   end;
 END;

BEGIN
 randomize;
 fillchar(pole,sizeof(pole),100);
 for h:=1 to 4 do
  for w:=1 to 4 do
   pole[h,w]:=(h-1)*4+w;
 pole[4,4]:=0;
 obr:=pole;
 grdriver:=installuserdriver('SVGA256',nil);
 grmode:=6;
 initgraph(grdriver,grmode,'');
 getmem(p1,imagesize(startX,startY,startX+razm,startY+razm));
 getmem(p2,imagesize(startX,startY,startX+razm,startY+razm));
 getmem(p3,imagesize(startX,startY,startX+razm,startY+razm));
 setcolor(white);
 setlinestyle(solidln,0,thickwidth);
 rectangle(1,1,razm-1,razm-1);
 rectangle(2,2,razm-2,razm-2);
 rectangle(3,3,razm-3,razm-3);
 rectangle(4,4,razm-4,razm-4);
 rectangle(5,5,razm-5,razm-5);
 rectangle(6,6,razm-6,razm-6);
 rectangle(7,7,razm-7,razm-7);
 rectangle(9,9,razm-9,razm-9);
 getimage(0,0,razm,razm,p1^);
 h:=getBMPfileheight(name);
 w:=getBMPfilewidth(name);
 clearviewport;
 startX:=(getmaxx div 2)-(w div 2);
 startY:=(getmaxy-h) div 2;
 drawBMP(name,startX,startY,TRUE);
 curX:=1;curY:=1;X:=1;Y:=1;
 mix;
 repeat
  repeat
   beep;
   X:=curX;
   Y:=curY;
   getimage((curX-1)*razm+startX,(curY-1)*razm+startY,curX*razm+startX,curY*razm+startY,p2^);
   putimage((curX-1)*razm+startX,(curY-1)*razm+startY,p1^,orput);
   case readkey of
    #72 : begin
           dec(curY);
           if curY=0 then curY:=4;
          end;
    #75 : begin
           dec(curX);
           if curX=0 then curX:=4;
          end;
    #77 : begin
           inc(curX);
           if curX=5 then curX:=1;
          end;
    #80 : begin
           inc(curY);
           if curY=5 then curY:=1;
          end;
    #13 : break;
    #27 : begin
           drawBMP('LOSE.BMP',wX-100,Wy,TRUE);
           clearkeybuff;
           _jingle;
           nosound;
           closegraph;
           exit;
          end;
   end;
   putimage((X-1)*razm+startX,(Y-1)*razm+startY,p2^,copyput);
  until FALSE;
  putimage((X-1)*razm+startX,(Y-1)*razm+startY,p2^,copyput);
  if pole[x-1,y]=0 then dec(X)
   else if pole[x+1,y]=0 then inc(X)
    else if pole[x,y+1]=0 then inc(Y)
     else if pole[x,y-1]=0 then dec(Y);
  getimage((curX-1)*razm+startX,(curY-1)*razm+startY,curX*razm+startX,curY*razm+startY,p2^);
  setcolor(0);setfillstyle(solidfill,0);
  bar((curX-1)*razm+startX,(curY-1)*razm+startY,curX*razm+startX,curY*razm+startY);
  putimage((X-1)*razm+startX,(Y-1)*razm+startY,p2^,copyput);
  obmen(pole[X,Y],pole[curX,curY]);
 until win;
 drawBMP('WIN.BMP',wX-50,Wy,TRUE);
 clearkeybuff;
 jingle;
 nosound;
 closegraph;
END.