304 lines
14 KiB
C#
304 lines
14 KiB
C#
|
using System;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.Globalization;
|
|||
|
using System.IO;
|
|||
|
using System.Linq;
|
|||
|
using System.Text;
|
|||
|
using System.Text.RegularExpressions;
|
|||
|
|
|||
|
|
|||
|
//TODO add parsing for more than single letter
|
|||
|
|
|||
|
namespace ConsoleLSystem {
|
|||
|
abstract public class LSystemGeneralWordBuilder {
|
|||
|
abstract public LSystemNode createLSystemNode(string name, int values_number);
|
|||
|
abstract public void fillArguments(LSystemNode node, string[] arguments_strings);
|
|||
|
}
|
|||
|
public class LSystemWordBuilder : LSystemGeneralWordBuilder {
|
|||
|
public override LSystemNode createLSystemNode(string name, int values_number) {
|
|||
|
return new LSystemNode(new LSystemNodeLiteral(name, values_number));
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
public override void fillArguments(LSystemNode node, string[] arguments_strings) {
|
|||
|
for (int i = 0; i < arguments_strings.Length; i++) {
|
|||
|
node.literal.values[i] = float.Parse(arguments_strings[i], NumberStyles.Any, CultureInfo.InvariantCulture);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public class LSystemWordGeneratorBuilder : LSystemGeneralWordBuilder {
|
|||
|
public Dictionary<string, int> variableIndex { get;}
|
|||
|
public LSystemWordGeneratorBuilder(Dictionary<string,int> variable_index) {
|
|||
|
this.variableIndex = variable_index;
|
|||
|
}
|
|||
|
public override LSystemNode createLSystemNode(string name, int values_number) {
|
|||
|
return new LSystemNodeGenerator(name, values_number);
|
|||
|
}
|
|||
|
|
|||
|
public override void fillArguments(LSystemNode node, string[] arguments_strings) {
|
|||
|
MathExpression[] expressions = arguments_strings.Select(argument => new MathExpression(variableIndex, argument)).ToArray();
|
|||
|
LSystemNodeGenerator ng = (LSystemNodeGenerator)node;
|
|||
|
ng.fillArguments(expressions);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
public class LSystemFileParser {
|
|||
|
//LSystemWordParser wordParser;
|
|||
|
//LSystemRulesParser ruleParser;
|
|||
|
|
|||
|
//public LSystemFileParser(LSystemWordParser wordParser, LSystemRulesParser ruleParser) {
|
|||
|
// this.wordParser = wordParser;
|
|||
|
// this.ruleParser = ruleParser;
|
|||
|
//}
|
|||
|
public static int countParenthesisEnd(string line,char opening_char, char closing_char) {
|
|||
|
var parenthesises_number = 1;
|
|||
|
var length = -1;
|
|||
|
while (parenthesises_number > 0) {
|
|||
|
length++;
|
|||
|
var c = line[1 + length];
|
|||
|
if (c == opening_char) {
|
|||
|
parenthesises_number++;
|
|||
|
}
|
|||
|
if (c == closing_char) {
|
|||
|
parenthesises_number--;
|
|||
|
}
|
|||
|
}
|
|||
|
return length;
|
|||
|
}
|
|||
|
public static bool parenthesisCheck(string line) {
|
|||
|
var parenthesises_number = 0;
|
|||
|
var brackets_number = 0;
|
|||
|
foreach (var s in line) {
|
|||
|
if (s == '(') {
|
|||
|
parenthesises_number++;
|
|||
|
}
|
|||
|
if (s == ')') {
|
|||
|
parenthesises_number--;
|
|||
|
}
|
|||
|
if (s == '[') {
|
|||
|
brackets_number++;
|
|||
|
}
|
|||
|
if (s == ']') {
|
|||
|
brackets_number--;
|
|||
|
}
|
|||
|
if (brackets_number<0 || parenthesises_number < 0) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
return (brackets_number == 0 && parenthesises_number == 0);
|
|||
|
}
|
|||
|
|
|||
|
public static LSystemNode parseWord(string line, LSystemGeneralWordBuilder builder) {
|
|||
|
var read_characters = 0;
|
|||
|
LSystemNode node;
|
|||
|
if (line[0] == '[') {
|
|||
|
node = builder.createLSystemNode("", 0);
|
|||
|
}
|
|||
|
else {
|
|||
|
var literal_name = line.Substring(0, 1);
|
|||
|
if (line.Length>1 && line[1] == '(') {
|
|||
|
var length = countParenthesisEnd(line.Substring(1), '(', ')');
|
|||
|
var values_string = line.Substring(2, length).Split(',');
|
|||
|
node = builder.createLSystemNode(literal_name, values_string.Length);
|
|||
|
|
|||
|
builder.fillArguments(node, values_string);
|
|||
|
//Leter and: (, )
|
|||
|
read_characters += length + 3;
|
|||
|
|
|||
|
}
|
|||
|
else {
|
|||
|
read_characters += 1;
|
|||
|
node = builder.createLSystemNode(line.Substring(0,1),0);
|
|||
|
}
|
|||
|
}
|
|||
|
while (line.Length > read_characters && line[read_characters] == '[') {
|
|||
|
|
|||
|
var brackets_number = 1;
|
|||
|
var length = countParenthesisEnd(line.Substring(read_characters), '[', ']');
|
|||
|
var child_node = parseWord(line.Substring(read_characters + 1, length),builder);
|
|||
|
read_characters += length + 2;
|
|||
|
child_node.parent = node;
|
|||
|
node.children.Add(child_node);
|
|||
|
}
|
|||
|
if (read_characters < line.Length) {
|
|||
|
var child_node = parseWord(line.Substring(read_characters),builder);
|
|||
|
child_node.parent = node;
|
|||
|
node.mainChild = (child_node);
|
|||
|
}
|
|||
|
return node;
|
|||
|
}
|
|||
|
|
|||
|
public static LSystemNodeLiteralVariable parsePredecesor(string line) {
|
|||
|
var name = line.Substring(0, 1);
|
|||
|
var varable_index = new Dictionary<string, int>();
|
|||
|
if (line.Length > 1) {
|
|||
|
foreach (var i in line.Substring(2, line.Length - 3).Split(',').Select((_name, Index) => new { _name, Index })) {
|
|||
|
varable_index.Add(i._name, i.Index);
|
|||
|
};
|
|||
|
}
|
|||
|
return new LSystemNodeLiteralVariable(name, varable_index.Count, varable_index);
|
|||
|
}
|
|||
|
|
|||
|
public static LSystemEvaluator parseLSystem(StreamReader sr) {
|
|||
|
string line;
|
|||
|
int line_number = 0;
|
|||
|
LSystemNode axiom = null;
|
|||
|
List<LSystemRule> rules = null;
|
|||
|
while ((line = sr.ReadLine()) != null) {
|
|||
|
line_number++;
|
|||
|
if (line.Trim() == "#axiom") {
|
|||
|
line = sr.ReadLine();
|
|||
|
if (!parenthesisCheck(line)) {
|
|||
|
throw new Exception(String.Format("In line {0} invalid syntax", line_number));
|
|||
|
}
|
|||
|
axiom = parseWord(line,new LSystemWordBuilder());
|
|||
|
}
|
|||
|
if (line.Trim() == "#rules") {
|
|||
|
rules = parseLSystemRules(sr);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
return new LSystemEvaluator(axiom, rules);
|
|||
|
}
|
|||
|
|
|||
|
private static List<LSystemRule> parseLSystemRules(StreamReader sr) {
|
|||
|
List<LSystemRule> rules = new List<LSystemRule>();
|
|||
|
Regex separator = new Regex(@"-(\d*\.?\d*){1}>");
|
|||
|
Regex weight_regex = new Regex(@"p=(\d+\.?\d*){1}");
|
|||
|
string line;
|
|||
|
while ((line = sr.ReadLine()) != null && line.Trim() != "#rules end") {
|
|||
|
try {
|
|||
|
if (line.Length == 0 || line[0] == '#') {
|
|||
|
continue;
|
|||
|
}
|
|||
|
MathExpressionComparison[] conditions = new MathExpressionComparison[0];
|
|||
|
var split = separator.Match(line);
|
|||
|
var line_parts = line.Split(new string[] { split.Value }, StringSplitOptions.None);
|
|||
|
// check conditions;
|
|||
|
//parse predecesor
|
|||
|
var _t = line_parts[0].Split(':');
|
|||
|
var predecesor_string = _t[0];
|
|||
|
LSystemNodeLiteralVariable predecesor;
|
|||
|
LSystemContext context;
|
|||
|
//check if contains < or >
|
|||
|
|
|||
|
// check context
|
|||
|
getPredecesorContext(predecesor_string, out predecesor, out context);
|
|||
|
|
|||
|
if (_t.Length > 1) {
|
|||
|
conditions = _t[1].Trim().Split(';').Select(text => MathExpressionComparasionParser.parse(predecesor.variableIndex, text.Trim())).ToArray();
|
|||
|
}
|
|||
|
// tochastic rule parsing
|
|||
|
var sucsessor_string = line_parts[1];
|
|||
|
var probabilities_list = new List<float>();
|
|||
|
var consequents_list = new List<LSystemNodeGenerator>();
|
|||
|
if (sucsessor_string.Trim() == "#stochastic") {
|
|||
|
while ((line = sr.ReadLine()) != null && line.Trim() != "#stochastic end") {
|
|||
|
if (line[0] == '#') {
|
|||
|
continue;
|
|||
|
}
|
|||
|
var weight_string = weight_regex.Match(line);
|
|||
|
var weight = float.Parse(weight_string.Value.Substring(2), NumberStyles.Any, CultureInfo.InvariantCulture);
|
|||
|
probabilities_list.Add(weight);
|
|||
|
|
|||
|
var prob_len = weight_string.Value.Length;
|
|||
|
consequents_list.Add((LSystemNodeGenerator)parseWord(line.Substring(prob_len).Trim(), new LSystemWordGeneratorBuilder(predecesor.variableIndex)));
|
|||
|
}
|
|||
|
}
|
|||
|
else {
|
|||
|
consequents_list.Add((LSystemNodeGenerator)parseWord(sucsessor_string.Trim(), new LSystemWordGeneratorBuilder(predecesor.variableIndex)));
|
|||
|
}
|
|||
|
//context
|
|||
|
if (context != null) {
|
|||
|
if (consequents_list.Count > 1) {
|
|||
|
rules.Add(new LSystemRuleParametricStochasticContext(predecesor, conditions, consequents_list.ToArray(), probabilities_list.ToArray(), context));
|
|||
|
}
|
|||
|
else {
|
|||
|
rules.Add(new LSystemRuleParametricStochasticContext(predecesor, conditions, consequents_list[0], context));
|
|||
|
}
|
|||
|
}
|
|||
|
else {
|
|||
|
if (consequents_list.Count > 1) {
|
|||
|
rules.Add(new LSystemRuleParametricStochastic(predecesor, conditions, consequents_list.ToArray(), probabilities_list.ToArray()));
|
|||
|
}
|
|||
|
else {
|
|||
|
rules.Add(new LSystemRuleParametric(predecesor, conditions, consequents_list[0]));
|
|||
|
}
|
|||
|
}
|
|||
|
//var conditions = parts[0];
|
|||
|
//var result
|
|||
|
}
|
|||
|
catch (Exception e) {
|
|||
|
sr.Close();
|
|||
|
throw new Exception(String.Format("error in {0} with a message \n {1}", line,e.Message));
|
|||
|
}
|
|||
|
}
|
|||
|
return rules;
|
|||
|
}
|
|||
|
|
|||
|
private static void getPredecesorContext(string predecesor_string, out LSystemNodeLiteralVariable predecesor, out LSystemContext context) {
|
|||
|
string partent_context_str = null;
|
|||
|
string child_context_str = null;
|
|||
|
string mid_context_str = null;
|
|||
|
int mid_start = 0;
|
|||
|
|
|||
|
for (int i = 0; i < predecesor_string.Length; i++) {
|
|||
|
if (predecesor_string[i] == '<' && partent_context_str == null) {
|
|||
|
partent_context_str = predecesor_string.Substring(0, i).Trim();
|
|||
|
mid_start = i+1;
|
|||
|
//Console.WriteLine(i);
|
|||
|
}
|
|||
|
if (predecesor_string[i] == '>' && child_context_str == null) {
|
|||
|
child_context_str = predecesor_string.Substring(i + 1).Trim();
|
|||
|
mid_context_str = predecesor_string.Substring(mid_start, i - mid_start).Trim();
|
|||
|
//Console.WriteLine(i);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
if (mid_context_str == null) {
|
|||
|
mid_context_str = predecesor_string.Substring(mid_start).Trim();
|
|||
|
}
|
|||
|
LSystemNodeLiteralVariable parent = null;
|
|||
|
LSystemNodeLiteralVariable child = null;
|
|||
|
predecesor = LSystemFileParser.parsePredecesor(mid_context_str);
|
|||
|
if (partent_context_str != null) {
|
|||
|
parent = LSystemFileParser.parsePredecesor(partent_context_str);
|
|||
|
foreach (KeyValuePair<string, int> kvp in new Dictionary<string, int>(predecesor.variableIndex)) {
|
|||
|
//textBox3.Text += ("Key = {0}, Value = {1}", kvp.Key, kvp.Value);
|
|||
|
predecesor.variableIndex[kvp.Key] = kvp.Value + parent.variableIndex.Count;
|
|||
|
}
|
|||
|
foreach (KeyValuePair<string, int> kvp in parent.variableIndex) {
|
|||
|
//textBox3.Text += ("Key = {0}, Value = {1}", kvp.Key, kvp.Value);
|
|||
|
predecesor.variableIndex.Add(kvp.Key, kvp.Value);
|
|||
|
}
|
|||
|
}
|
|||
|
if (child_context_str != null) {
|
|||
|
int size = predecesor.variableIndex.Count;
|
|||
|
child = LSystemFileParser.parsePredecesor(child_context_str);
|
|||
|
foreach (KeyValuePair<string, int> kvp in child.variableIndex) {
|
|||
|
//textBox3.Text += ("Key = {0}, Value = {1}", kvp.Key, kvp.Value);
|
|||
|
predecesor.variableIndex.Add(kvp.Key, kvp.Value + size);
|
|||
|
}
|
|||
|
}
|
|||
|
if (child_context_str != null) {
|
|||
|
if (partent_context_str != null) {
|
|||
|
context = new LSystemContext(parent, child);
|
|||
|
}
|
|||
|
else {
|
|||
|
context = new LSystemContext();
|
|||
|
context.setOnlySucceeding(child);
|
|||
|
}
|
|||
|
}
|
|||
|
else if (partent_context_str != null) {
|
|||
|
context = new LSystemContext();
|
|||
|
context.setOnlyPreceding(parent);
|
|||
|
}
|
|||
|
else {
|
|||
|
context = null;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|