2021-03-13 17:35:25 +01:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
2021-03-26 21:33:33 +01:00
|
|
|
|
using System.Linq;
|
2021-03-13 17:35:25 +01:00
|
|
|
|
using System.Text;
|
|
|
|
|
|
|
|
|
|
namespace ConsoleLSystem {
|
|
|
|
|
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 {
|
2021-03-26 21:33:33 +01:00
|
|
|
|
abstract public bool is_aplicable(LSystemNode processed_node, String[] ignored);
|
|
|
|
|
abstract public LSystemNode rewrite(LSystemNode processed_node, String[] ignored);
|
2021-03-13 17:35:25 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class LSystemRuleBasic : LSystemRule {
|
|
|
|
|
LSystemNodeLiteral input;// { get; }
|
|
|
|
|
LSystemNode output;
|
|
|
|
|
|
|
|
|
|
public LSystemRuleBasic(LSystemNodeLiteral input, LSystemNode output) {
|
|
|
|
|
this.input = input;
|
|
|
|
|
this.output = output;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-26 21:33:33 +01:00
|
|
|
|
override public bool is_aplicable(LSystemNode processed_node, String[] ignored) {
|
2021-03-13 17:35:25 +01:00
|
|
|
|
if (processed_node.literal == input) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-03-26 21:33:33 +01:00
|
|
|
|
override public LSystemNode rewrite(LSystemNode processed_node, String[] ignored) {
|
|
|
|
|
if (is_aplicable(processed_node, ignored)) {
|
2021-03-13 17:35:25 +01:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-26 21:33:33 +01:00
|
|
|
|
public override bool is_aplicable(LSystemNode processed_node, String[] ignored) {
|
2021-03-13 17:35:25 +01:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-26 21:33:33 +01:00
|
|
|
|
public override LSystemNode rewrite(LSystemNode processed_node, String[] ignored) {
|
|
|
|
|
if (is_aplicable(processed_node, ignored)) {
|
2021-03-13 17:35:25 +01:00
|
|
|
|
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 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 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 Random();
|
|
|
|
|
|
|
|
|
|
}
|
2021-03-26 21:33:33 +01:00
|
|
|
|
public override bool is_aplicable(LSystemNode processed_node, String[] ignored) {
|
2021-03-13 17:35:25 +01:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-26 21:33:33 +01:00
|
|
|
|
public override LSystemNode rewrite(LSystemNode processed_node, String[] ignored) {
|
2021-03-13 17:35:25 +01:00
|
|
|
|
var result = random.NextDouble();
|
|
|
|
|
int consequent_index = 0;
|
|
|
|
|
for (int i = 0; i < probabilities.Length; i++) {
|
|
|
|
|
if (result < probabilities[i]) {
|
|
|
|
|
consequent_index = i;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-03-26 21:33:33 +01:00
|
|
|
|
if (is_aplicable(processed_node, ignored)) {
|
2021-03-13 17:35:25 +01:00
|
|
|
|
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 child { get; set; }
|
|
|
|
|
public LSystemNodeLiteral mid { get; set; }
|
|
|
|
|
bool isPreceding = false;
|
|
|
|
|
bool isSucceeding = false;
|
|
|
|
|
|
|
|
|
|
public LSystemContext(LSystemNodeLiteral parent, LSystemNodeLiteral child) {
|
|
|
|
|
this.parent = parent;
|
|
|
|
|
this.child = child;
|
|
|
|
|
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 child) {
|
|
|
|
|
this.child = child;
|
|
|
|
|
this.isPreceding = false;
|
|
|
|
|
this.isSucceeding = true;
|
|
|
|
|
}
|
2021-03-26 21:33:33 +01:00
|
|
|
|
public bool isAplicable(LSystemNode node, String[] ignored, out float[] variables) {
|
2021-03-13 17:35:25 +01:00
|
|
|
|
var variables_list = new List<float>();
|
2021-03-26 21:33:33 +01:00
|
|
|
|
var currentParent = node.parent;
|
|
|
|
|
while (ignored.Contains(currentParent.literal.name)) {
|
|
|
|
|
currentParent = currentParent.parent;
|
|
|
|
|
}
|
|
|
|
|
if (isPreceding && parent != currentParent.literal) {
|
2021-03-13 17:35:25 +01:00
|
|
|
|
variables = new float[0];
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (isPreceding) {
|
2021-03-26 21:33:33 +01:00
|
|
|
|
variables_list.AddRange(currentParent.literal.values);
|
2021-03-13 17:35:25 +01:00
|
|
|
|
}
|
|
|
|
|
variables_list.AddRange(node.literal.values);
|
|
|
|
|
if (isSucceeding) {
|
|
|
|
|
var result = false;
|
|
|
|
|
LSystemNodeLiteral childLiteral;
|
2021-03-26 21:33:33 +01:00
|
|
|
|
Queue<LSystemNode> ignoredChildren = new Queue<LSystemNode>();
|
2021-03-13 17:35:25 +01:00
|
|
|
|
foreach(var child in node.getAllChildren()) {
|
2021-03-26 21:33:33 +01:00
|
|
|
|
if (ignored.Contains(child.literal.name)) {
|
|
|
|
|
ignoredChildren.Enqueue(child);
|
|
|
|
|
}
|
2021-03-13 17:35:25 +01:00
|
|
|
|
if (child.literal == this.child) {
|
|
|
|
|
childLiteral = child.literal;
|
|
|
|
|
result = true;
|
|
|
|
|
variables_list.AddRange(child.literal.values);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-03-26 21:33:33 +01:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-03-13 17:35:25 +01:00
|
|
|
|
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;
|
|
|
|
|
}
|
2021-03-26 21:33:33 +01:00
|
|
|
|
public override bool is_aplicable(LSystemNode processed_node,String[] ignored) {
|
2021-03-13 17:35:25 +01:00
|
|
|
|
if (processed_node.literal.name != predecesor.name || processed_node.literal.values_number != predecesor.values_number) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
var variables = new float[0];
|
2021-03-26 21:33:33 +01:00
|
|
|
|
if (!context.isAplicable(processed_node, ignored, out variables)) {
|
2021-03-13 17:35:25 +01:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
foreach (var condition in conditions) {
|
|
|
|
|
if (!condition.eval(variables)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2021-03-26 21:33:33 +01:00
|
|
|
|
bool is_aplicable(LSystemNode processed_node, String[] ignored, out float[] variables) {
|
2021-03-13 17:35:25 +01:00
|
|
|
|
variables = new float[0];
|
|
|
|
|
if (processed_node.literal.name != predecesor.name || processed_node.literal.values_number != predecesor.values_number) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2021-03-26 21:33:33 +01:00
|
|
|
|
if (!context.isAplicable(processed_node, ignored, out variables)) {
|
2021-03-13 17:35:25 +01:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
foreach (var condition in conditions) {
|
|
|
|
|
if (!condition.eval(variables)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-26 21:33:33 +01:00
|
|
|
|
public override LSystemNode rewrite(LSystemNode processed_node, String[] ignored) {
|
2021-03-13 17:35:25 +01:00
|
|
|
|
var result = random.NextDouble();
|
|
|
|
|
int consequent_index = 0;
|
|
|
|
|
for (int i = 0; i < probabilities.Length; i++) {
|
|
|
|
|
if (result < probabilities[i]) {
|
|
|
|
|
consequent_index = i;
|
2021-03-26 21:33:33 +01:00
|
|
|
|
break;
|
2021-03-13 17:35:25 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
float[] variables;
|
2021-03-26 21:33:33 +01:00
|
|
|
|
if (is_aplicable(processed_node, ignored, out variables)) {
|
2021-03-13 17:35:25 +01:00
|
|
|
|
return consequents[consequent_index].eval(variables);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
return new LSystemNode(processed_node.literal);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|