############################################################################
#
#	File:     linden.icn
#
#	Subject:  Program to generate sentences in 0L-systems
#
#	Author:   Ralph E. Griswold
#
#	Date:     June 21, 1999
#
############################################################################
#
#   This file is in the public domain.
#
############################################################################
#
#  This program reads in a 0L-system (Lindenmayer system) consisting of
#  rewriting rules in which a string is rewritten with every character
#  replaced simultaneously (conceptually) by a specified string of
#  symbols.
#
#  Rules have the form
#
#	S->SSS...
#
#  where S is a character.
#
#  In addition to rules, there are keywords that describe the system and how
#  to draw it.  These include the "axiom" on which rewriting is started and
#  optionally the angle in degrees between successive lines (default 90).
#  Other keywords may be present, but are ignored.
#
#  Keywords are followed by a colon.
#
#    An example 0L-system is:
#
#	X->-FX++FY-
#	Y->+FX--FY+
#	F->
#	-->-
#	+->+
#	axiom:FX
#	angle:45.0
#	xorg:100
#	yorg:100
#
#  Here, the initial string is "FX" and angular increment is 45 degrees.
#  Note that "-" is a legal character in a 0L-system -- context determines
#  whether it's 0L character or part of the "->" that stands for "is
#  replaced by".
#
#  If no rule is provided for a character, the character is not changed
#  by rewriting. Thus, the example above can be expressed more concisely
#  as
#
#	X->-FX++FY-
#	Y->+FX--FY+
#	F->
#	axiom:FX
#	angle:45.0
#
#  The recognized keywords are:
#
#	axiom	axiom for generation
#	angle	angular increment for turns
#	length	segment length
#	xorg	x origin
#	yorg	y origin
#	comment	comment; ignored
#
#  Distances increase from left to right in the x direction and from top
#  to bottom in the y direction.
#
#  As pure-production systems, the characters are symbolic and have no
#  meaning.  When interpreted for drawing, the characters have the
#  following meaning:
#
#	F	move forward by length
#	f	move backward by length
#	+	turn right by angle
#	-	turn left by angle
#	[	save current state
#	]	restore current state
#
#  The file containing the 0L-systems is read from standard input.
#
#  The command-line options are:
#
#	-g i	number of generations, default 3
#	-l i	length of line segments, default 5
#	-a i	angular increment in degrees (overrides angle given in
#		  the grammar)
#	-w i	window width
#	-h i	window height
#	-x i	initial x position, default mid-window
#	-y i	initial y position, default mid-window
#	-W	write out string instead of drawing
#	-s	take snapshot of image.
#	-d i	delay in milliseconds between symbol interpretations;
#		  default 0
#
#  NOTE:  The name option that supported multiple L-Systems in
#         one file has been eliminated on the grounds that it
#         introduced too much complexity in use.
#
############################################################################
#
#  References:
#
#     Formal Languages, Arto Salomaa, Academic Press, 1973. pp. 234-252.
#
#     The Algorithmic Beauty of Plants, Przemyslaw Prusinkiewicz and
#     Aristid Lindenmayer, Springer Verlag, 1990.
#
#     Lindenmayer Systems, Fractals, and Plants, Przemyslaw Prusinkiewicz and
#     James Hanan, Springer Verlag, 1989.
#
############################################################################
#
#  See linden.dat for an example of input data.
#
############################################################################
#
#  Requires:  graphics if drawing
#
############################################################################
#
#  Links: linddraw, options, wopen
#
############################################################################

link linddraw
link options
link wopen

procedure main(args)
   local line, gener, axiom, angle, opts, i, s, c, symbol, rewrite
   local allchars, rhs, value, spec, x, y, length, w, h, delay, name

   rewrite := table()
   allchars := ''			# cset of all rhs characters
 
   opts := options(args,"g+l+a+w+h+x+y+Wsd+")

   rhs := ''

   while line := read() do
      line ? {
         if symbol := move(1) & ="->" then {
            rhs := tab(0)
            rewrite[symbol] := rhs
            allchars ++:= rhs			# keep track of all characters
            }
         else if spec := tab(upto(':')) then {
            move(1)
            value := tab(0)
            case spec of {
               "axiom":    {
                  axiom := value
                  allchars ++:= rhs		# axiom might have strays
                  }
               "angle":    angle := value
               "xorg":     x := value
               "yorg":     y := value
               "comment":  &null		# ignore comments
               "length":   length := value   
               "gener":    gener := value   
               "name":     name := value
               }				# ignore others
            }
         else write(&errout, "malformed input: ", tab(0))
         }

#  At this point, we have the table to map characters, but it may lack
#  mappings for characters that "go into themselves" by default.  For
#  efficiency in rewriting, these mappings are added.

   every c := !allchars do
     /rewrite[c] := c

   h := \opts["h"] | 400
   w := \opts["w"] | 400

   angle := \opts["a"]			# command-line overrides
   length := \opts["l"]
   gener := \opts["g"]
   x := \opts["x"]
   y := \opts["y"]
   delay := \opts["d"]

   /angle := 90				# defaults
   /length := 5
   /gener := 3
   /x := 0
   /y := 0
   /delay := 0
   /name := "intitled"

   if /axiom then stop("*** no axiom")

   if /opts["W"] then {
      WOpen("size=" || w || "," || h, "dx=" || (w / 2),
      "dy=" || (h / 2)) | stop("*** cannot open window")
      linddraw(x, y, axiom, rewrite, length, angle, gener, delay)
      if \opts["s"] then WriteImage(name || ".gif")
      WDone()
      }
   else {
      every writes(lindgen(!axiom, rewrite, gener))
      write()
      }

end
