{
{ Pouring sand simulator - by Marcin Borkowski 2:480/25.
  VGA and patience required. Program simulates sand poured
  from some height on a flat surface. There are different
  grain densities and different grain colors - denser grains
  are darker. I saw something similar this year during winter
  vacation done from tho pieces of glass, water and sand - this
  program tries to simulate physical effects taking place in
  a real system. Denser grains falls faster and they form flatter
  slopes. ESC ends simulation. }

const
  maxgrains = 199;

type
  data   = (x,y,c);

var
  sand   : array[0..maxgrains,x..c]of integer;
  bottom : array[0..639,0..1]of integer;
  grains,source : integer;

procedure movedown(i : integer);
var
  moved : boolean;
  j : integer;

  procedure totheleft;
  var
    j : integer;
  begin
    for j:=1 to sand[i,c] do
      if (sand[i,y]>bottom[sand[i,x]-j,0]+1) and (sand[i,x]>8) then
      begin
        dec(sand[i,x],j);
        sand[i,y]:=bottom[sand[i,x],0]+1;
        moved:=true;
        EXIT
      end;
  end;

  procedure totheright;
  var
    j : integer;
  begin
    for j:=1 to sand[i,c] do
      if (sand[i,y]>bottom[sand[i,x]+j,0]+1) and (sand[i,x]<632)  then
      begin
        inc(sand[i,x],j);
        sand[i,y]:=bottom[sand[i,x],0]+1;  {}
        moved:=true;
        EXIT
      end;
  end;

begin
  moved:=false;
  if random(2)<>0 then
  begin
    totheleft;
    if not moved then totheright;
  end
  else
  begin
    totheright;
    if not moved then totheleft;
  end;
  if moved then movedown(i)
end;

procedure pour;
var
  i : integer;
  addr : word;
  dummy : byte;
  px,py,pc : integer;
begin
  for i:=0 to grains do
  begin
    dec(sand[i,y],sand[i,c]);
    if sand[i,y] shr 4<=bottom[sand[i,x],0] then
    begin
      sand[i,y]:=bottom[sand[i,x],0]+1;
      movedown(i);
      px:=sand[i,x];
      py:=sand[i,y];
      pc:=sand[i,c];
      bottom[px,0]:=py;
      bottom[px,1]:=pc;
      Port[$3CE]:=08;
      Port[$3CF]:=$80 shr (px and 7);   { Bit Mask }
      addr:=80*(480-py)+px shr 3;
      dummy:=mem[$A000:addr];           { load latches }
      mem[$A000:addr]:=Lo(17-pc shl 1); { PutPixel - write mode #2 }
      move(sand[grains],sand[i],6);
      dec(grains);
    end;
  end;
  while grains<maxgrains do
  begin
    inc(grains);
    sand[grains,x]:=source;
    sand[grains,y]:=16*400;
    sand[grains,c]:=1+random(8);
  end;
end;

procedure colors16;
var
  i : integer;
begin
  Port[$3C8]:=0;
  for i:=0 to 15 do
  begin
    Port[$3C9]:=3+4*i;
    Port[$3C9]:=3+4*i;
    Port[$3C9]:=3+4*i;
    port[$3C0]:=i;
    port[$3C0]:=i;
  end;
  port[$3C0]:=$30;
end;

begin
  asm mov ax,12h; int 10h end;
  randomize;
  colors16;
  Port[$3C4]:=02;  Port[$3C5]:=$0F;
  Port[$3CE]:=05;  Port[$3CF]:=(Port[$3CF] and $FD) or 2;
  fillchar(sand,sizeof(sand),#0);
  fillchar(bottom,sizeof(bottom),#0);
  grains:=0;
  source:=30+random(600);
  sand[grains,x]:=source;
  sand[grains,y]:=16*400;
  sand[grains,c]:=1;
  repeat
    pour;
    if random(10000)>9997 then source:=30+random(600)
  until port[$60]=1;
  asm mov ax,03h; int 10h end;
end.
