(* desenează o variantă de triunghi Sierpinski în format SVG
 * vezi https://en.wikipedia.org/wiki/L-system
 * compilează: ocamlc fisier.ml    
 * rulează ./a.out > fisier.svg (Linux) sau ./a > fisier.svg (Windows) *)

open Printf

module M = Map.Make(Char)
                        
let pi3 = acos 0.5
let len = 3.        (* dimensiunea unui segment *)

(* scrie comanda SVG l dx dy pentru o linie la unghiul dat, returnează unghiul *)
let line phi = printf "l %.1f %.1f " (len *. cos phi) (len *. sin phi); phi

(* o literă neterminal e asociată cu o regulă de rescriere *)
let gram = M.singleton 'A' ['B';'-';'A';'-';'B']
           |> M.add 'B'['A';'+';'B';'+';'A']

(* o literă reprezintă o acțiune în functie de starea curentă (unghi):
   poate desena ceva, și returnează o nouă stare -- aici, noul unghi *)
let actions = M.singleton 'A' line |> M.add 'B' line
              |> M.add '+' ((+.) pi3)        (* întoarce la stânga *)
              |> M.add '-' ((+.) (-.pi3))  (* întoarce la dreapta *)

(* expandează recursiv de n ori un caracter după regulile din dicționar
 * pentru terminali și în final execută acțiunea din dicționar *)
let rec expand n state c = 
  if n = 0 then state |> M.find c actions        (* gata: deseneaza *)
  else try M.find c gram |> List.fold_left (expand (n-1)) state
       with Not_found -> state |> M.find c actions (* terminal: deseneaza *)

(* începe cu 'A' sau 'B', ca să deseneze în jos; ignoră unghiul rezultate *)
let fractal n = expand n 0. (if n mod 2 = 0 then 'A' else 'B') |> ignore
              
let () = (        (* antet SVG, fractal, apoi încheie SVG *)
    print_string "<?xml version=\"1.0\"?>\n\
                  <svg version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">\n\
                  <path fill=\"none\" stroke=\"blue\" d=\"M 0 0 ";
    fractal 8;        (* desenul *)
    print_string "\"/>\n</svg>"
)

This document was generated using caml2html