{ Starting number - 01
  Supported levels - 1,2,3,4 (all)
  No modules used
    in fact two modules can be easily recognized - MOUSE one and VIDEO one,
    implementing them into one program is easier and more clear, although
    not generalised enough.
}

{ Color description : }
{ 0 - background - no region
  1..239 - regions
  240-254 - unused
  255 - boeder

  while making the "wave" 254 is used as color which indicates a passed point
}

{ ALGORITHM - all regions are printed on the screen and then when clicking on
a specific region is to get the region color (current point) and to check all
of the screen when that region is (specified by CRANGE) and then to "fill"
i.e. to make boeders around all unboerdered points. Each unbordered point
(of course each unbordered point means a point which is in a unbordered
region) is being "bordered" by FILL procedure and the whole region by DOIT.
This algorithm is dependable neighter on map level, neighter on number of
areas in the input file as it uses the map itself.
}

{ It is possible if maps are too simple to obtain bordering many times with a
single click - that is to show the speed of the algorithm }

{ Compiler options }
{$A+,B-,D+,E-,F-,G+,I-,L+,N-,O-,P-,Q-,R-,S-,T-,V-,X+,Y-}
{$M 65520,0,655360}

uses dos,crt;
type tarr=array[0..199,0..319] of byte;  { Two types of indexing - }
     tarr2=array[0..64000-1] of byte;    { with coordinates or linear }
     parr=^tarr2;
var
   fi:Text;                             { input file }
   fin:string;                          { it's name }
   s:string;
   x,y:longint;                         { temporary varibles }
   x1,x2,y1,y2:word;                    { Rectangle coordinates }
   crange:array[1..239] of record xx,xy,nx,ny:word;end;
                                        { the maXimal & miNimal coordinates }
                                        { of a specific color - speed up }
                                        { the boedering much }
   c:byte;                              { Current region color }

   r:registers;                         { used by all interrupts }

   mx,my:word;                          { last mouse click coordinates }

   q1,q2:array[1..10000] of word;       { queue, used for the wave }
   q1s,q2s:longint;                     { size of the queue }

var ccycle:byte;                        { used by palette cycling }
    delay:longint;
    first:boolean;                       { the appearing color }
    crand:byte;                          { current random color }
    rr,rg,rb:byte;                       { random color boeders }

{ VIDEO PART }
var
   pix:tarr absolute $a000:0000;        { the screen itself, indexed twice }
   pix2:tarr2 absolute $a000:0000;
   image:parr;
   work:parr;

   map:array[0..255] of record r,g,b:byte;end;            { Pallete map }

procedure initvga;
{ Initializes the video hardware }
 begin
  with r do
       begin
        ah:=0;
        al:=$13;
       end;
  intr($10,r);
 end;

procedure bar(x1,y1,x2,y2:word;c:byte);
{ Draws a filled rectangle with the specified color }
var y:word;
 begin
  if x2>=x1 then
  for y:=y1 to y2 do
      fillchar(pix[y,x1],x2+1-x1,c);
 end;

procedure setrgb;
{ Sets initialy the whole palette }
var i:word;
 begin
  map[0].r:=0;map[0].g:=0;map[0].b:=0;
  for i:=1 to 239 do
      begin
       map[i].r:=((i shr 5)*63)div 7;
       map[i].g:=(((i shr 2) and 7)*63)div 7;
       map[i].b:=((i and 3)*63)div 3;
      end;
  map[255].r:=63;map[255].g:=63;map[255].b:=63;
  with r do
       begin
        ax:=$1012;
        bx:=0;
        cx:=256;
        es:=seg(map);
        dx:=ofs(map);
       end;
  intr($10,r);
 end;

procedure singlergb(c,cr,cg,cb:byte);
{ Sets a single palette register }
 begin
  with r do
       begin
        ax:=$1010;
        bx:=c;
        ch:=cg;
        cl:=cb;
        dh:=cr;
       end;
  intr($10,r);
 end;

{ MOUSE PART }
function initmouse:boolean;
{ Checks for mouse driver and initializes it if exist }
 begin
  r.ax:=0;
  intr($33,r);
  initmouse:=r.ax=$ffff;
 end;

procedure smk;
{ Shows mouse pointer }
 begin
  r.ax:=1;
  intr($33,r);
 end;
procedure hmk;
{ Hides mouse pointer }
 begin
  r.ax:=2;
  intr($33,r);
 end;

function mstatus:word;
{ Gets the mouse status and returns the buttons one }
 begin
  r.ax:=3;
  intr($33,r);
  mx:=r.cx div 2;
  my:=r.dx;
  mstatus:=r.bx;
 end;

{ MAIN PART }
procedure fill(dx,dy:word);
{ Draws a boeder around a single area (not only rectangular one) }
var x,cq:word;
    a:byte;
    boed:boolean;
 begin
  q1s:=1;
  q1[1]:=dx+dy*320; { initialy the queue consists only of the first point }
  pix2[q1[1]]:=254;
  while q1s>0 do { while there are more unprocessed points }
        begin
         q2s:=0;
         for x:=1 to q1s do
             begin { one by one checks all points in the queue }
              boed:=false;
              cq:=q1[x];
              { each neighbour is checked if it is unprocessed in order to be processed }
              { y-1 }
              if (cq>320) then
                 begin
                  if (pix2[cq-320]>=0) and (pix2[cq-320]<240) then
                     if pix2[cq-320]=c
                        then
                            begin
                             inc(q2s);
                             q2[q2s]:=cq-320;
                             pix2[cq-320]:=254;
                            end
                        else boed:=true;
                 end else boed:=true;
              { x-1 }
              if (cq mod 320<>0) then
                 begin
                  if (pix2[cq-1]>=0) and (pix2[cq-1]<240) then
                     if pix2[cq-1]=c
                        then
                            begin
                             inc(q2s);
                             q2[q2s]:=cq-1;
                             pix2[cq-1]:=254;
                            end
                        else boed:=true;
                 end else boed:=true;
              { x+1 }
              if (cq mod 320<>319) then
                 begin
                  if (pix2[cq+1]>=0) and (pix2[cq+1]<240) then
                     if pix2[cq+1]=c
                        then
                            begin
                             inc(q2s);
                             q2[q2s]:=cq+1;
                             pix2[cq+1]:=254;
                            end
                        else boed:=true;
                 end else boed:=true;
              { y+1 }
              if (cq<199*320) then
                 begin
                  if (pix2[cq+320]>=0) and (pix2[cq+320]<240) then
                      if pix2[cq+320]=c
                         then
                             begin
                              inc(q2s);
                              q2[q2s]:=cq+320;
                              pix2[cq+320]:=254;
                             end
                         else boed:=true;
                 end else boed:=true;

              if boed then work^[cq]:=255;
             end;
         { new points (Q2) become current (Q1) }
         move(q2[1],q1[1],q2s*sizeof(q2[1]));
         q1s:=q2s;
        end;
 end; { fill }

procedure doit;
{ Finds all the boeders }
var x,y:longint;
 begin
  if pix[my,mx]=0
     then
         begin
          hmk;
          pix2:=image^;                      { clear the boeder }
          smk;
          exit;
         end;
  if pix[my,mx]<240 then c:=pix[my,mx];

  first:=true;                                  { used to appear the boedering }
  crand:=random(7);                             { generates a random boeder }
  ccycle:=22;
  singlergb(255,21,21,21);
  { A little bit out of the regulations but is also white and soon becomes white }
  hmk;
  pix2:=image^;
  work^:=image^;
  singlergb(254,map[c].r,map[c].g,map[c].b);    { Hiding the wave process }

  { Creating all region boeders }
  with crange[c] do
  for x:=nx to xx do
      begin
       y:=ny;
       while y<=xy do
             begin
              while (y<=xy) and (pix[y,x]<240) and (pix[y,x]<>c) do inc(y);
              if y>xy then continue;
              if pix[y,x]=c
                 then
                     begin { we have an unprocessed point }
                      pix2:=work^;
                      fill(x,y);
                     end;
              while (y<=xy) and (pix[y,x]>=240) do inc(y);
              if y>xy then continue;
              { all points after boeder one are processed }
              while (y<=xy) and (pix[y,x]=c) do inc(y);
              if y>xy then continue;
              inc(y);
             end;
      end;

  pix2:=work^; { the working array is assigned to the screen }
  smk;
 end; { doit }

begin { main }
 { initialization }
 randomize;
 getmem(image,sizeof(image^));
 getmem(work,sizeof(work^));
 if not initmouse then
    begin
     writeln('No mouse installed.');
     halt;
    end;
 fin:=paramstr(1);
 for x1:=1 to 239 do
     with crange[x1] do
          begin
           xx:=0;xy:=0;
           nx:=319;ny:=199;
          end;
 initvga;
 setrgb;

 assign(fi,fin);
 reset(fi);
 readln(fi,s);
 bar(0,0,319,199,0);
 while not seekeof(fi) do
       begin
        readln(fi,c,x1,y1,x2,y2);
        if x1<crange[c].nx then crange[c].nx:=x1;
        if y1<crange[c].ny then crange[c].ny:=y1;
        if x2>crange[c].xx then crange[c].xx:=x2;
        if y2>crange[c].xy then crange[c].xy:=y2;
        bar(x1,y1,x2,y2,c);
       end;
 close(fi);

 image^:=pix2;
 smk;
 repeat { realises the idle function in order to check mouse, palette, keyboard }
  inc(delay);delay:=delay mod 5000;
  if delay=0 { the computer is so fast so we have to delay it when cycling }
     then
         begin
          if first
             then
                 begin
                  singlergb(255,ccycle*2-23,ccycle*2-23,ccycle*2-23);
                  inc(ccycle);
                  if ccycle>=44 then begin first:=false;ccycle:=0;end;
                 end
             else
                 begin
                  if ccycle<22
                     then
                         begin
                          if crand and 1<>0
                             then rr:=63
                             else rr:=63-ccycle*3;
                          if crand and 2<>0
                             then rg:=63
                             else rg:=63-ccycle*3;
                          if crand and 4<>0
                             then rb:=63
                             else rb:=63-ccycle*3;
                          singlergb(255,rr,rg,rb);
                         end
                     else
                         begin
                          if crand and 1<>0
                             then rr:=63
                             else rr:=ccycle*3-66;
                          if crand and 2<>0
                             then rg:=63
                             else rg:=ccycle*3-66;
                          if crand and 4<>0
                             then rb:=63
                             else rb:=ccycle*3-66;
                          singlergb(255,rr,rg,rb);
                         end;
                  inc(ccycle);ccycle:=ccycle mod 44;
                  end;
         end;
  if keypressed and (readkey=#27) then begin textmode(3);halt;end;
  if (mstatus<>0) then doit;
 until false;
end.