423 lines
13 KiB
C#
423 lines
13 KiB
C#
|
using System;
|
||
|
using System.Collections.Generic;
|
||
|
using System.Linq;
|
||
|
|
||
|
public class LSystemNodeLiteralVariable : LSystemNodeLiteral
|
||
|
{
|
||
|
public Dictionary<string, int> variableIndex { get; }
|
||
|
|
||
|
public LSystemNodeLiteralVariable(string name, int values_number, Dictionary<string, int> variableIndex) : base(name, values_number)
|
||
|
{
|
||
|
this.variableIndex = variableIndex;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
public class LSystemNodeGenerator : LSystemNode
|
||
|
{
|
||
|
MathExpression[] math_expressions;
|
||
|
|
||
|
public LSystemNodeGenerator(string name, int arguments) : base(new LSystemNodeLiteral(name, arguments))
|
||
|
{
|
||
|
}
|
||
|
public void fillArguments(MathExpression[] math_expressions)
|
||
|
{
|
||
|
this.math_expressions = math_expressions;
|
||
|
}
|
||
|
public LSystemNode eval(float[] values)
|
||
|
{
|
||
|
var literal = new LSystemNodeLiteral(this.literal.name, this.literal.values_number);
|
||
|
for (int i = 0; i < literal.values_number; i++)
|
||
|
{
|
||
|
literal.values[i] = math_expressions[i].eval(values);
|
||
|
}
|
||
|
var result = new LSystemNode(literal);
|
||
|
foreach (LSystemNodeGenerator child in children)
|
||
|
{
|
||
|
var _child = child.eval(values);
|
||
|
_child.parent = result;
|
||
|
result.children.Add(_child);
|
||
|
|
||
|
}
|
||
|
if (mainChild != null)
|
||
|
{
|
||
|
var _mainChild = ((LSystemNodeGenerator)mainChild).eval(values);
|
||
|
_mainChild.parent = result;
|
||
|
result.mainChild = _mainChild;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
result.mainChild = null;
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
abstract public class LSystemRule
|
||
|
{
|
||
|
abstract public bool is_aplicable(LSystemNode processed_node, String[] ignored);
|
||
|
abstract public LSystemNode rewrite(LSystemNode processed_node, String[] ignored);
|
||
|
}
|
||
|
|
||
|
public class LSystemRuleBasic : LSystemRule
|
||
|
{
|
||
|
LSystemNodeLiteral input;// { get; }
|
||
|
LSystemNode output;
|
||
|
|
||
|
public LSystemRuleBasic(LSystemNodeLiteral input, LSystemNode output)
|
||
|
{
|
||
|
this.input = input;
|
||
|
this.output = output;
|
||
|
}
|
||
|
|
||
|
override public bool is_aplicable(LSystemNode processed_node, String[] ignored)
|
||
|
{
|
||
|
if (processed_node.literal == input)
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
override public LSystemNode rewrite(LSystemNode processed_node, String[] ignored)
|
||
|
{
|
||
|
if (is_aplicable(processed_node, ignored))
|
||
|
{
|
||
|
return output.deep_copy();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return new LSystemNode(processed_node.literal);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public class LSystemRuleParametric : LSystemRule
|
||
|
{
|
||
|
LSystemNodeLiteralVariable predecesor;// { get; }
|
||
|
LSystemNodeGenerator consequent;
|
||
|
MathExpressionComparison[] conditions;
|
||
|
|
||
|
public LSystemRuleParametric(LSystemNodeLiteralVariable predecesor, MathExpressionComparison[] conditions, LSystemNodeGenerator consequent)
|
||
|
{
|
||
|
this.predecesor = predecesor;
|
||
|
this.consequent = consequent;
|
||
|
this.conditions = conditions;
|
||
|
}
|
||
|
|
||
|
public override bool is_aplicable(LSystemNode processed_node, String[] ignored)
|
||
|
{
|
||
|
if (processed_node.literal.name != predecesor.name || processed_node.literal.values_number != predecesor.values_number)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
foreach (var condition in conditions)
|
||
|
{
|
||
|
if (!condition.eval(processed_node.literal.values))
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
public override LSystemNode rewrite(LSystemNode processed_node, String[] ignored)
|
||
|
{
|
||
|
if (is_aplicable(processed_node, ignored))
|
||
|
{
|
||
|
return consequent.eval(processed_node.literal.values);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return new LSystemNode(processed_node.literal);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public class LSystemRuleParametricStochastic : LSystemRule
|
||
|
{
|
||
|
protected LSystemNodeLiteralVariable predecesor;// { get; }
|
||
|
protected LSystemNodeGenerator[] consequents;
|
||
|
protected float[] probabilities;
|
||
|
protected MathExpressionComparison[] conditions;
|
||
|
protected System.Random random;
|
||
|
|
||
|
public LSystemRuleParametricStochastic(LSystemNodeLiteralVariable predecesor, MathExpressionComparison[] conditions, LSystemNodeGenerator[] consequents, float[] probabilities)
|
||
|
{
|
||
|
this.predecesor = predecesor;
|
||
|
this.consequents = consequents;
|
||
|
this.conditions = conditions;
|
||
|
float probabilities_sum = 0;
|
||
|
foreach (var probability in probabilities) { probabilities_sum += probability; }
|
||
|
float acumulator = 0;
|
||
|
this.probabilities = new float[consequents.Length];
|
||
|
for (int i = 0; i < consequents.Length; i++)
|
||
|
{
|
||
|
var probability = probabilities[i] / probabilities_sum;
|
||
|
this.probabilities[i] = probability + acumulator;
|
||
|
acumulator += probability;
|
||
|
}
|
||
|
random = new System.Random();
|
||
|
|
||
|
}
|
||
|
public LSystemRuleParametricStochastic(LSystemNodeLiteralVariable predecesor, MathExpressionComparison[] conditions, LSystemNodeGenerator consequent)
|
||
|
{
|
||
|
this.predecesor = predecesor;
|
||
|
this.consequents = new LSystemNodeGenerator[] { consequent };
|
||
|
this.conditions = conditions;
|
||
|
float probabilities_sum = 0;
|
||
|
probabilities = new float[1] { 1 };
|
||
|
random = new System.Random();
|
||
|
|
||
|
}
|
||
|
public override bool is_aplicable(LSystemNode processed_node, String[] ignored)
|
||
|
{
|
||
|
if (processed_node.literal.name != predecesor.name || processed_node.literal.values_number != predecesor.values_number)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
foreach (var condition in conditions)
|
||
|
{
|
||
|
if (!condition.eval(processed_node.literal.values))
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
public override LSystemNode rewrite(LSystemNode processed_node, String[] ignored)
|
||
|
{
|
||
|
var result = random.NextDouble();
|
||
|
int consequent_index = 0;
|
||
|
for (int i = 0; i < probabilities.Length; i++)
|
||
|
{
|
||
|
if (result < probabilities[i])
|
||
|
{
|
||
|
consequent_index = i;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (is_aplicable(processed_node, ignored))
|
||
|
{
|
||
|
return consequents[consequent_index].eval(processed_node.literal.values);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return new LSystemNode(processed_node.literal);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
public class LSystemContext
|
||
|
{
|
||
|
public LSystemNodeLiteral parent { get; set; }
|
||
|
public LSystemNodeLiteral[] children { get; set; }
|
||
|
public LSystemNodeLiteral mid { get; set; }
|
||
|
bool isPreceding = false;
|
||
|
bool isSucceeding = false;
|
||
|
|
||
|
public LSystemContext(LSystemNodeLiteral parent, LSystemNodeLiteral[] children)
|
||
|
{
|
||
|
this.parent = parent;
|
||
|
this.children = children;
|
||
|
this.isPreceding = true;
|
||
|
this.isSucceeding = true;
|
||
|
}
|
||
|
public LSystemContext()
|
||
|
{
|
||
|
|
||
|
}
|
||
|
public void setOnlyPreceding(LSystemNodeLiteral parent)
|
||
|
{
|
||
|
this.parent = parent;
|
||
|
this.mid = mid;
|
||
|
this.isPreceding = true;
|
||
|
this.isSucceeding = false;
|
||
|
}
|
||
|
public void setOnlySucceeding(LSystemNodeLiteral[] children)
|
||
|
{
|
||
|
this.children = children;
|
||
|
this.isPreceding = false;
|
||
|
this.isSucceeding = true;
|
||
|
}
|
||
|
void _purgeIgnoredRecursive(LSystemNode node, HashSet<String> ignored, ref List<LSystemNode> results)
|
||
|
{
|
||
|
if (ignored.Contains(node.literal.name))
|
||
|
{
|
||
|
foreach (var child in node.getAllChildren())
|
||
|
{
|
||
|
_purgeIgnoredRecursive(child, ignored, ref results);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
results.Add(node);
|
||
|
}
|
||
|
}
|
||
|
List<LSystemNode> _purgeIgnored(LSystemNode node, HashSet<String> ignored)
|
||
|
{
|
||
|
List<LSystemNode> results = new List<LSystemNode>();
|
||
|
foreach (var child in node.getAllChildren())
|
||
|
{
|
||
|
_purgeIgnoredRecursive(child, ignored, ref results);
|
||
|
}
|
||
|
return results;
|
||
|
}
|
||
|
public bool isAplicable(LSystemNode node, String[] ignored, out float[] variables)
|
||
|
{
|
||
|
var variables_list = new List<float>();
|
||
|
var currentParent = node.parent;
|
||
|
while (ignored.Contains(currentParent.literal.name))
|
||
|
{
|
||
|
currentParent = currentParent.parent;
|
||
|
}
|
||
|
if (isPreceding && parent != currentParent.literal)
|
||
|
{
|
||
|
variables = new float[0];
|
||
|
return false;
|
||
|
}
|
||
|
if (isPreceding)
|
||
|
{
|
||
|
variables_list.AddRange(currentParent.literal.values);
|
||
|
}
|
||
|
variables_list.AddRange(node.literal.values);
|
||
|
if (isSucceeding)
|
||
|
{
|
||
|
LSystemNodeLiteral childLiteral;
|
||
|
Queue<LSystemNode> ignoredChildren = new Queue<LSystemNode>();
|
||
|
|
||
|
var nodeChildren = _purgeIgnored(node, new HashSet<String>(ignored)).ToArray();
|
||
|
var result = children.Length == nodeChildren.Length;
|
||
|
|
||
|
if (result)
|
||
|
{
|
||
|
for (int i = 0; i < children.Length; i++)
|
||
|
{
|
||
|
if (nodeChildren[i].literal == children[i])
|
||
|
{
|
||
|
variables_list.AddRange(nodeChildren[i].literal.values);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
result = false;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
//foreach(var child in node.getAllChildren()) {
|
||
|
// if (ignored.Contains(child.literal.name)) {
|
||
|
// ignoredChildren.Enqueue(child);
|
||
|
// }
|
||
|
// if (child.literal == this.child) {
|
||
|
// childLiteral = child.literal;
|
||
|
// result = true;
|
||
|
// variables_list.AddRange(child.literal.values);
|
||
|
// break;
|
||
|
// }
|
||
|
//}
|
||
|
//while (!result && ignoredChildren.Count>0) {
|
||
|
// var ignoredChild = ignoredChildren.Dequeue();
|
||
|
// foreach (var child in ignoredChild.getAllChildren()) {
|
||
|
// if (ignored.Contains(child.literal.name)) {
|
||
|
// ignoredChildren.Enqueue(child);
|
||
|
// }
|
||
|
// if (child.literal == this.child) {
|
||
|
// childLiteral = child.literal;
|
||
|
// result = true;
|
||
|
// variables_list.AddRange(child.literal.values);
|
||
|
// break;
|
||
|
// }
|
||
|
// }
|
||
|
//}
|
||
|
if (!result)
|
||
|
{
|
||
|
variables = new float[0];
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
variables = variables_list.ToArray();
|
||
|
return true;
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
public class LSystemRuleParametricStochasticContext : LSystemRuleParametricStochastic
|
||
|
{
|
||
|
LSystemContext context;
|
||
|
public LSystemRuleParametricStochasticContext(LSystemNodeLiteralVariable predecesor, MathExpressionComparison[] conditions, LSystemNodeGenerator[] consequents, float[] probabilities, LSystemContext context) : base(predecesor, conditions, consequents, probabilities)
|
||
|
{
|
||
|
this.context = context;
|
||
|
}
|
||
|
public LSystemRuleParametricStochasticContext(LSystemNodeLiteralVariable predecesor, MathExpressionComparison[] conditions, LSystemNodeGenerator consequent, LSystemContext context) : base(predecesor, conditions, consequent)
|
||
|
{
|
||
|
this.context = context;
|
||
|
}
|
||
|
public override bool is_aplicable(LSystemNode processed_node, String[] ignored)
|
||
|
{
|
||
|
if (processed_node.literal.name != predecesor.name || processed_node.literal.values_number != predecesor.values_number)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
var variables = new float[0];
|
||
|
if (!context.isAplicable(processed_node, ignored, out variables))
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
foreach (var condition in conditions)
|
||
|
{
|
||
|
if (!condition.eval(variables))
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
bool is_aplicable(LSystemNode processed_node, String[] ignored, out float[] variables)
|
||
|
{
|
||
|
variables = new float[0];
|
||
|
if (processed_node.literal.name != predecesor.name || processed_node.literal.values_number != predecesor.values_number)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
if (!context.isAplicable(processed_node, ignored, out variables))
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
foreach (var condition in conditions)
|
||
|
{
|
||
|
if (!condition.eval(variables))
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
public override LSystemNode rewrite(LSystemNode processed_node, String[] ignored)
|
||
|
{
|
||
|
var result = random.NextDouble();
|
||
|
int consequent_index = 0;
|
||
|
for (int i = 0; i < probabilities.Length; i++)
|
||
|
{
|
||
|
if (result < probabilities[i])
|
||
|
{
|
||
|
consequent_index = i;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
float[] variables;
|
||
|
if (is_aplicable(processed_node, ignored, out variables))
|
||
|
{
|
||
|
return consequents[consequent_index].eval(variables);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return new LSystemNode(processed_node.literal);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|