MWS_2021/Unity Project/Assets/Scripts/LSystem/LSystemRule.cs
2021-04-17 22:09:48 +02:00

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);
}
}
}
}