346 lines
14 KiB
C#
346 lines
14 KiB
C#
|
using System;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.Linq;
|
|||
|
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 {
|
|||
|
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 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();
|
|||
|
|
|||
|
}
|
|||
|
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);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
}
|