program o1game;
{ I have some ideas, but it doesn't work...

....sorry for my bad english :) }
uses crt;

 const const_output = 'output.pos';

 type data = array [ 0..5 , 0..5 ] of byte;
      data_goal = array [ 1..4 , 1..4 ] of byte;

      files = text;

 var
      desk : data;
      goal : data_goal;

      input_file  : string;  { path for input }
      output_file : string;  { path for output }

      ifile,                 {input  file}
      ofile       : files;   {output file}

      par1,                  { switch }
      par2        : string;  { filename }

{----------------------------------------------------------------------------
  there is some kind of error and program will be terminated
}
 procedure error(r : string);
   begin
     writeln(r);
     halt(0);
   end;
{----------------------------------------------------------------------------
  - fill identificators
  - check if entry is in rightdirection
  - fill the goal
}
 procedure init;
 var i,j:byte;
   begin
     par1 := paramstr(1);
     if par1[1] = '-' then
       par2 := paramstr(2)
       else
         begin
           par2 := par1;
           par1 := 'not identify'
         end;

     if par2='' then error('Ussage: 01game [-solve/-show] <filename>');
     if (par1<>'-show')and(par1<>'-solve')and(par1<>'not identify') then error('Ussage: 01game [-solve/-show] <filename>');

     input_file := par2;
     output_file := const_output;

     writeln('switch      :  ',par1);
     writeln('input file  :  ',input_file);
     writeln('output file :  ',output_file);


                                   { fill the goal }
     for i:=0 to 5 do              { desk if separated by [40] }
        for j:=0 to 5 do
          begin
           desk [i,j]:=40;
           goal [i,j]:=40;
          end;

     for j:=0 to 3 do
        for i:=1 to 4 do
           goal [i,j+1]:=(j*4)+i;
     goal[4,4]:=0;                 { end of fill }

   end;
{----------------------------------------------------------------------------}
 procedure write_desk;
 var i,j:byte;
   begin
     for i:=1 to 4 do
      begin
        for j:=1 to 4 do
          write( desk [j,i],' ');
        writeln;
      end;
   end;
{----------------------------------------------------------------------------
  - check the filename
  - read input file
}
 procedure read_input;
 var ch : char;
      i,j,number,number2 : byte;

   begin
     assign( ifile, input_file );
   {$I-}
     reset( ifile );
     if ioresult <> 0 then error('<filename> is valid');
   {$I+}

     i:=0;
     j:=1;
     number:=0;
     number2:=0;

     while not( eof(ifile) ) do
       begin
         read( ifile, ch);
         number := ord(ch)-48;
         if (number>0) and (number<50) then
           begin
             i:=i+1;
             if i>4 then begin j:=j+1; i:=1 end;
             if (number=40) then number:=0
               else begin
                      read( ifile, ch );
                      number2 := ord(ch)-48;
                      if (number2 >=0) and (number2 <20)then number:=10 + number2;
                    end;
             desk [ i,j ] := number;
           end;
       end;
     close( ifile );
   end;
{----------------------------------------------------------------------------}
 procedure solve;
 var
     index_zerox,index_zeroy : byte;   { index of zero }
     p : byte;                         { index of zero }

     key : char;
     ac,bc,cc,dc : byte;               { control i. }
     poc : longint;                    { number of moves }

   procedure find_zero;
   { find zero in desk = find empty field }
   var i,j:byte;
     begin
       for j:=1 to 4 do
         for i:=1 to 4 do
           if desk[ i,j ] = 0 then
             begin
               index_zerox := i;
               index_zeroy := j;
             end;
     end;

   function my_abs(a,b:byte):byte;
   var c:integer;
     begin
       c := a - b;
       if c<0 then c:= c * -1;
       my_abs := c;
     end;

   function desk_goal: boolean;
   { is true if desk is the same as goal }
   var i,j:byte;
     begin
       desk_goal := true;
       for j:=1 to 4 do
         for i:=1 to 4 do
           if desk[ i,j ] <> goal[ i,j ] then desk_goal := false;
     end;


   procedure move;
   { one move }
   var a,b,c,d : byte;
     begin
       { get index of zero }
       p:= goal[index_zerox,index_zeroy];
       { get absolute distances of fields which lies about zero }
       a:= ac + my_abs(desk[ index_zerox   , index_zeroy -1 ],p);
       b:= bc + my_abs(desk[ index_zerox   , index_zeroy +1 ],p);
       c:= cc + my_abs(desk[ index_zerox -1, index_zeroy    ],p);
       d:= dc + my_abs(desk[ index_zerox +1, index_zeroy    ],p);

       { compare, which field has the smallest abs with zero and move it }
       if (a<=b)and(a<=c)and(a<=d) then begin
                                       desk[ index_zerox , index_zeroy ]:=
                                       desk[ index_zerox   , index_zeroy -1 ];
                                       desk[ index_zerox   , index_zeroy -1 ]:=0;
                                       ac:=0; bc:=20; cc:=0; dc:=0;
                                       writeln( ofile, 'UP');
                                     end else

       if (b<=a)and(b<=c)and(b<=d) then begin
                                       desk[ index_zerox , index_zeroy ]:=
                                       desk[ index_zerox   , index_zeroy +1 ];
                                       desk[ index_zerox   , index_zeroy +1 ]:=0;
                                       ac:=20; bc:=0; cc:=0; dc:=0;
                                       writeln( ofile, 'DOWN');
                                     end else

       if (c<=a)and(c<=b)and(c<=d) then begin
                                       desk[ index_zerox , index_zeroy ]:=
                                       desk[ index_zerox -1, index_zeroy  ];
                                       desk[ index_zerox -1, index_zeroy  ]:=0;
                                       ac:=0; bc:=0; cc:=0; dc:=20;
                                       writeln( ofile, 'LEFT');
                                     end else

       if (d<=a)and(d<=b)and(d<=c) then begin
                                       desk[ index_zerox , index_zeroy ]:=
                                       desk[ index_zerox +1, index_zeroy  ];
                                       desk[ index_zerox +1, index_zeroy  ]:=0;
                                       ac:=0; bc:=0; cc:=20; dc:=0;
                                       writeln( ofile, 'RIGHT');
                                     end;
     end;

   begin
     assign( ofile, output_file );
     rewrite( ofile );
     writeln( ofile, ' ');
     p:=0;
     ac:=0; bc:=0; cc:=0; dc:=0;
     poc:=0;

     repeat
       clrscr;
       poc:=poc+1;
       writeln(poc);
       find_zero;
       write_desk;
       move;
       delay(1000);
     until (keypressed)or(desk_goal);

     reset( ofile );
     writeln( ofile,poc );
     close( ofile );
   end;
{----------------------------------------------------------------------------}
 procedure show;
   begin
     writeln(' hmmm... I have nothing to show...');
   end;
{----------------------------------------------------------------------------}
 procedure find;
   begin
     writeln('data in processing..');
     delay(1000);
     writeln(' hmmm... I don`t have the answer, maybe it is possible.... ');
   end;
{----------------------------------------------------------------------------}



begin
  clrscr;
  init;
  read_input;
  if par1 = '-solve' then solve;
  if par1 = '-show' then show;
  if par1 = 'not identify' then find;
end.
