using System.Collections; using System.Collections.Generic; using System.IO; using System.Text; using UnityEngine; public class LSystem : MonoBehaviour { public string Premise = "FFFA"; public string[] Rules = new string[] { "A=!\"[B]////[B]////B", "B=&FFFA" }; public string ContextIgnore = "F+-"; public float StepSize = 0.1f; public float StepSizeScale = 0.9f; public float Angle = 28.0f; public float AngleScale = 0.7f; public uint Generations = 7; private List> _branches = new List>(); // Use this for initialization void Start () { } private void OnValidate() { // RebuildTree(); } private string DrawReductionTree(GOLD.Reduction Root) { //This procedure starts the recursion that draws the parse tree. StringBuilder tree = new StringBuilder(); tree.AppendLine("+-" + Root.Parent.Text(false)); DrawReduction(tree, Root, 1); return tree.ToString(); } private void DrawReduction(StringBuilder tree, GOLD.Reduction reduction, int indent) { //This is a simple recursive procedure that draws an ASCII version of the parse //tree int n; string indentText = ""; for (n = 1; n <= indent; n++) { indentText += "| "; } //=== Display the children of the reduction for (n = 0; n < reduction.Count(); n++) { switch (reduction[n].Type()) { case GOLD.SymbolType.Nonterminal: GOLD.Reduction branch = (GOLD.Reduction)reduction[n].Data; tree.AppendLine(indentText + "+-" + branch.Parent.Text(false)); DrawReduction(tree, branch, indent + 1); break; default: string leaf = (string)reduction[n].Data; tree.AppendLine(indentText + "+-" + leaf); break; } } } public void RebuildTree(){ MyParser parser = new MyParser(); parser.Setup(); MemoryStream ms = new MemoryStream(System.Text.ASCIIEncoding.ASCII.GetBytes(@"F(x)=F(7+-x/2)")); StreamReader sr = new StreamReader(ms); parser.Parse(sr); var tree = parser.program; var treeTxt = DrawReductionTree(tree); Debug.Log(treeTxt); string result = Premise; for(uint g = 0; g < Generations; ++g) { string tmp = ""; for(int j = 0; j < result.Length; ++j) { string replacement = result[j].ToString(); foreach (var rule in Rules) { if(result[j] == rule[0]) { replacement = rule.Substring(2); break; } } tmp += replacement; } result = tmp; } Debug.Log("Final result: " + result); RunTurtle(result); } struct TurtleState { public Vector3 position; public Matrix4x4 mat; public List points; } void RunTurtle(string commandLine) { Stack states = new Stack(); TurtleState state = new TurtleState(); state.mat = Matrix4x4.identity; state.position = Vector3.zero; _branches.Clear(); state.points = new List(); state.points.Add(state.position); for(int i = 0; i < commandLine.Length; ++i) { char cmd = commandLine[i]; if(cmd == 'F') { state.position = state.position + state.mat.MultiplyVector(Vector3.up); state.points.Add(state.position); }else if(cmd == '+') { state.mat = state.mat * Matrix4x4.Rotate(Quaternion.Euler(0, 0, -Angle)) ; } else if (cmd == '-') { state.mat = state.mat * Matrix4x4.Rotate(Quaternion.Euler(0, 0, Angle)); } else if (cmd == '[') { states.Push(state); state.points = new List(); state.points.Add(state.position); } else if (cmd == ']') { state = states.Pop(); _branches.Add(state.points); } else if (cmd == '/') { state.mat = state.mat * Matrix4x4.Rotate(Quaternion.Euler(0, -Angle, 0)); } else if (cmd == '\\') { state.mat = state.mat * Matrix4x4.Rotate(Quaternion.Euler(0, Angle, 0)); } else if (cmd == '&') { state.mat = state.mat * Matrix4x4.Rotate(Quaternion.Euler(Angle, 0, 0)); } else if (cmd == '^') { state.mat = state.mat * Matrix4x4.Rotate(Quaternion.Euler(-Angle, 0, 0)); } } _branches.Add(state.points); } private void OnDrawGizmos() { Gizmos.matrix = transform.localToWorldMatrix; foreach(var branch in _branches) { if(branch.Count > 1) { for (int i = 0; i < branch.Count - 1; ++i) { Gizmos.DrawLine(branch[i], branch[i + 1]); } } } } // Update is called once per frame void Update () { } }