Unit Lsystems;
				InterFace
Uses Graph;

const
  MaxStack = 100;
  MaxBuf = 10000;

type
 PLsys = ^TLsys;
 PS    = ^String;
 TLsys = record
   Axiom    : string;
   Comment  : string;
   Turns    : integer;
   RulesTable : array [0..255] of PS;
 end;

 Tpos = record
   x, y, a : real;
 end;

Function  CreateLsys(aAxiom, aComment : string; aTurns : integer):PLsys;
Procedure AddRule(var aFrac : PLsys; aCh : char; aRule:string);
Procedure DestroyLsys(var aFrac : PLsys);
Function  Calculate(var aFrac:PLsys; aStage : integer):string;
Function  Advance(var aFrac:PLsys; PrevName : string):string;
Procedure DrawLsys(fName : string; var aFrac : PLsys);

			Implementation
Function CreateLsys;
var RET:PLsys;i:byte;
begin
  New(RET);
  RET^.Axiom := aAxiom;
  RET^.Comment := aComment;
  RET^.Turns := aTurns;
  for i:=0 to 255 do RET^.RulesTable[i]:=nil;
  CreateLsys := RET;
end;{CreateLsys}
{--------------------------------------------}
Procedure AddRule;
begin
  if aFrac = nil then begin writeln('AddRule Error: Fractal undefined'); halt(255);end;
  if aFrac^.RulesTable[Ord(aCh)] <> nil then Dispose(aFrac^.RulesTable[Ord(aCh)]);
  New(aFrac^.RulesTable[Ord(aCh)]);
  aFrac^.RulesTable[Ord(aCh)]^ := aRule;
end;{AddRule}
{--------------------------------------------}
Function Calculate;
var
 A    : FILE;
 CH   : char;
 N1   : string;
 I    : integer;
begin
  n1:='1.!!!';
  if odd(aStage) then Calculate := '2.!!!'
  else Calculate := '1.!!!';

  Assign(A,'1.!!!');
  Rewrite(A,1);
  BlockWrite(A,Ptr(Seg(aFrac^.Axiom),Ofs(aFrac^.Axiom)+1)^,Length(aFrac^.Axiom));
  Close(A);
  For i := 1 to aStage do
   begin
     N1:=Advance(aFrac,N1);
   end;
end;{Calculate}
{--------------------------------------------}
Function Advance;
type PFILE=^FILE;
var
 A,B  : PFILE;
 Out  : string;
 CH   : char;
 I    : integer;
begin
  New(A);NEW(B);
  if PrevName = '1.!!!' then out:='2.!!!'
  else out:='1.!!!';
  Advance := out;
  Assign(A^,PrevName);
  Assign(B^,Out);

  Reset(A^,1);
  Rewrite(B^,1);
  repeat
    BlockRead(A^,CH,1);
    if aFrac^.RulesTable[Ord(ch)] <> nil then BlockWrite(B^,Ptr(Seg(aFrac^.RulesTable[Ord(ch)]^),
      Ofs(aFrac^.RulesTable[Ord(ch)]^)+1)^,Length(aFrac^.RulesTable[Ord(ch)]^))
    else BlockWrite(B^,Ch,1);
  until EOF(A^);
  Close(A^);
  Close(B^);
  Erase(A^);
  Dispose(A);Dispose(B);
end;{Advance}
{--------------------------------------------}
Procedure DestroyLsys;
var i:byte;
begin
  for i:=0 to 255 do if aFrac^.RulesTable[i] <> nil then
    Dispose(aFrac^.RulesTable[i]);
  Dispose(aFrac);
end;{DestroyLsys}
{-------------------------------------------}
Procedure DrawLsys;
type TBuf = array [1..MaxBuf] of char;
Var
  Step : real;
  StackPos : integer;
  Stack : array [1..MaxStack] of Tpos;
  Buffer  : ^TBuf;
  BufPos,NumRead:1..MaxBuf;
  C : Tpos;
  Ip  : FILE;
  dx, dy,cx,cy : real;
  da  : real;
  MaxX,MinX,MaxY,MinY : real;
begin
  Step := 100.0;
  da := 2*PI/aFrac^.Turns;
  New(Buffer);
  Assign(ip,fName);
  Reset(ip,1);
  BlockRead(ip,Buffer^,MaxBuf,NumRead);
  BufPos:=1;
  StackPos:=1;
  dx:=step;dy:=0;C.x:=0;c.y:=0;c.a:=0;
  MaxX:=0;MaxY:=0;MinX:=0;MinY:=0;
  repeat
    case Buffer^[BufPos] of
     'F': begin
            c.x := c.x + dx;
            c.y := c.y + dy;
            If C.X > MaxX then MaxX := c.x;
            If C.X < MinX then MinX := c.x;
            If C.Y > MaxY then MaxY := c.y;
            If C.Y < MinY then MinY := c.y;
          end;
     '+': begin
            c.a := c.a - da;
            if c.a > 2*PI then c.a:=c.a-2*Pi;
            if c.a < 0 then    c.a:=c.a+2*Pi;
            dx := cos(c.a)*Step;
            dy := sin(c.a)*Step;
          end;
     '-': begin
            c.a := c.a + da;
            if c.a > 2*PI then c.a:=c.a-2*Pi;
            if c.a < 0 then    c.a:=c.a+2*Pi;
            dx := cos(c.a)*Step;
            dy := sin(c.a)*Step;
          end;
     '[': begin
            If StackPos > MaxStack then
             begin
               CloseGraph;
               WriteLN('Stack overflow');
               Halt(210);
             end;
            Stack[StackPos] := C;
            Inc(StackPos);
          end;
     ']': begin
            If StackPos = 1 then
             begin
               CloseGraph;
               WriteLN('Stack error');
               Halt(200);
             end;
            Dec(StackPos);
            C:=Stack[StackPos];
            dx := cos(c.a)*Step;
            dy := sin(c.a)*Step;
          end;
    end;
    Inc(BufPos);
    if BufPos = NumRead+1 then
     begin
       BlockRead(ip,Buffer^,MaxBuf,NumRead);
       BufPos:=1;
     end;
    if NumRead = 0 then break;
  until false;
  if (MaxY=MinY) and (MaxX=MaxY) then
  begin
   Exit;
  end;
  if (MaxX-MinX)/(MaxY-MinY) > 4/3 then
    Step := 61300/(MaxX-MinX)
  else
    step := 46000/(MaxY-MinY);

  cx := (MaxX+MinX)*step/200;
  cy := (MaxY+MinY)*step/200;

  Seek(ip,0);
  BlockRead(ip,Buffer^,MaxBuf,NumRead);
  BufPos:=1;
  StackPos:=1;
  dx:=step;dy:=0;C.x:=0;c.y:=0;c.a:=0;
  OutTextXY(10,5,aFrac^.Comment);
  repeat
    case Buffer^[BufPos] of
     'F': begin
            moveto(round(320-cx+c.x),round(240+cy-c.y));
            c.x := c.x + dx;c.y := c.y + dy;
            LineTo(round(320-cx+c.x),round(240+cy-c.y))
          end;
     '+': begin
            c.a := c.a - da;
            if c.a > 2*PI then c.a:=c.a-2*Pi;
            if c.a < 0 then    c.a:=c.a+2*Pi;
            dx := cos(c.a)*Step;
            dy := sin(c.a)*Step;
          end;
     '-': begin
            c.a := c.a + da;
            if c.a > 2*PI then c.a:=c.a-2*Pi;
            if c.a < 0 then    c.a:=c.a+2*Pi;
            dx := cos(c.a)*Step;
            dy := sin(c.a)*Step;
          end;
     '[': begin
            If StackPos > MaxStack then
             begin
               WriteLN('Stack overflow');
               Halt(210);
             end;
            Stack[StackPos] := C;
            Inc(StackPos);
          end;
     ']': begin
            If StackPos = 1 then
             begin
               WriteLN('Stack error');
               Halt(200);
             end;
            Dec(StackPos);
            C:=Stack[StackPos];
            dx := cos(c.a)*Step;
            dy := sin(c.a)*Step;
          end;
    end;
    Inc(BufPos);
    if BufPos = NumRead+1 then
     begin
       BlockRead(ip,Buffer^,MaxBuf,NumRead);
       BufPos:=1;
     end;
    if NumRead = 0 then break;
  until false;
  close(ip);
  Dispose(Buffer);
end; {DrawLsys}
{--------------------------------------------}
END.



