using System; using System.Collections.Generic; using System.IO; using System.Linq; namespace SBRL.Algorithms.LSystem { public class Rule { public string Find; public string Replace; public Rule(string inFind, string inReplace) { Find = inFind; Replace = inReplace; } } /// /// Simulates an L-System. /// Implemented according to http://www.cs.unm.edu/~joel/PaperFoldingFractal/L-system-rules.html /// public class LSystemEngine { public readonly string Root; private List rules = new List(); public int GenerationCount { get; private set; } public string CurrentGeneration { get; private set; } public Dictionary Definitions { get; private set; } public LSystemEngine(string inRoot) { CurrentGeneration = Root = inRoot; Definitions = new Dictionary(); } public void AddRule(string find, string replace) { rules.Add(new Rule(find, replace)); } public string Simulate() { List> rulePositions = new List>(); // Find all the current positions foreach(Rule rule in rules) { IEnumerable positions = AllIndexesOf(CurrentGeneration, rule.Find); foreach (int pos in positions) rulePositions.Add(new KeyValuePair(pos, rule)); } rulePositions.Sort(compareRulePairs); string nextGeneration = CurrentGeneration; int replaceOffset = 0; foreach(KeyValuePair rulePos in rulePositions) { int nextPos = rulePos.Key + replaceOffset; nextGeneration = nextGeneration.Substring(0, nextPos) + rulePos.Value.Replace + nextGeneration.Substring(nextPos + rulePos.Value.Find.Length); replaceOffset += rulePos.Value.Replace.Length - rulePos.Value.Find.Length; } CurrentGeneration = nextGeneration; GenerationCount++; return CurrentGeneration; } private int compareRulePairs(KeyValuePair a, KeyValuePair b) { return a.Key - b.Key; } /// /// From http://stackoverflow.com/a/2641383/1460422 /// /// /// /// private IEnumerable AllIndexesOf(string str, string value) { if (String.IsNullOrEmpty(value)) throw new ArgumentException("the string to find may not be empty", nameof(value)); for (int index = 0; ; index += value.Length) { index = str.IndexOf(value, index); if (index == -1) break; yield return index; } } public static LSystemEngine FromFile(string filename) { return FromStream(new StreamReader(filename)); } public static LSystemEngine FromStream(StreamReader source) { LSystemEngine resultSystem = new LSystemEngine(source.ReadLine()); string nextLine = string.Empty; while (true) { nextLine = source.ReadLine(); if (nextLine == null) break; if (!nextLine.Contains("=") || nextLine.StartsWith("#") || nextLine.Trim().Length == 0) continue; string[] parts = nextLine.Split(new char[]{'='}, 2); if(parts[0].StartsWith("!")) { // This is a definition resultSystem.Definitions.Add(parts[0].Trim('!'), parts[1]); } else { resultSystem.AddRule(parts[0].Trim(), parts[1].Trim()); } } return resultSystem; } } }