ZMWSLI0-SL2021-GR11/Projekt/MWSProjekt/Assets/Scripts/LSystemParser.cs

420 lines
15 KiB
C#

using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
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 parseContextLiteral(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 LSystemNodeLiteralVariable[] parseSuccessorsContext(string line)
{
List<LSystemNodeLiteralVariable> result = new List<LSystemNodeLiteralVariable>();
bool bracketStarted = false;
int bracketStartedIndex = 0;
for (int i = 0; i < line.Length; i++)
{
if (line[i] == ']')
{
if (!bracketStarted)
{
throw new Exception("invalid syntax");
}
else
{
result.Add(parseContextLiteral(line.Substring(bracketStartedIndex, i - bracketStartedIndex)));
bracketStarted = false;
}
}
else if (line[i] == '[')
{
if (bracketStarted)
{
throw new Exception("invalid syntax");
}
else
{
bracketStarted = true;
bracketStartedIndex = i + 1;
}
}
else if (!bracketStarted)
{
result.Add(parseContextLiteral(line.Substring(i)));
break;
}
}
return result.ToArray();
}
//private static String[] parseIgnore(string line) {
// var items = line.Trim().Split(' ');
// var resut = List
//}
public static LSystemEvaluator parseLSystem(StreamReader sr)
{
string line;
int line_number = 0;
var ignored = new String[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().Split(' ')[0].Trim() == "#ignore")
{
ignored = line.Trim().Split(' ').Where(x => x != "#ignore" && x.Length > 0).Select(x => x.Trim()).ToArray();
}
if (line.Trim() == "#rules")
{
rules = parseLSystemRules(sr);
}
}
return new LSystemEvaluator(axiom, rules, ignored);
}
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[] children = null;
predecesor = LSystemFileParser.parseContextLiteral(mid_context_str);
if (partent_context_str != null)
{
parent = LSystemFileParser.parseContextLiteral(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;
children = LSystemFileParser.parseSuccessorsContext(child_context_str);
int offset = 0;
foreach (var child in children)
{
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 + offset);
}
offset += child.variableIndex.Count;
}
}
if (child_context_str != null)
{
if (partent_context_str != null)
{
context = new LSystemContext(parent, children);
}
else
{
context = new LSystemContext();
context.setOnlySucceeding(children);
}
}
else if (partent_context_str != null)
{
context = new LSystemContext();
context.setOnlyPreceding(parent);
}
else
{
context = null;
}
}
}