forked from andkok/MWS_2021
204 lines
9.4 KiB
C#
204 lines
9.4 KiB
C#
|
using System;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.Globalization;
|
|||
|
using System.Linq;
|
|||
|
using System.Text;
|
|||
|
|
|||
|
namespace ConsoleLSystem {
|
|||
|
public class MathExpressionComparison{
|
|||
|
MathExpression leftSide;
|
|||
|
MathExpression rightSide;
|
|||
|
Func<float, float,bool> comparisonFunction;
|
|||
|
|
|||
|
public MathExpressionComparison(MathExpression leftSide, MathExpression rightSide, Func<float, float, bool> comparisonFunction) {
|
|||
|
this.leftSide = leftSide;
|
|||
|
this.rightSide = rightSide;
|
|||
|
this.comparisonFunction = comparisonFunction;
|
|||
|
}
|
|||
|
public bool eval(float[] variables) {
|
|||
|
return comparisonFunction(leftSide.eval(variables), rightSide.eval(variables));
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
public class MathExpressionNode {
|
|||
|
Func<float[], float[], float> function;
|
|||
|
MathExpressionNode[] childNodes;
|
|||
|
|
|||
|
public MathExpressionNode(Func<float[], float[], float> function, MathExpressionNode[] childNodes) {
|
|||
|
this.function = function;
|
|||
|
this.childNodes = childNodes;
|
|||
|
}
|
|||
|
|
|||
|
public float eval(float[] variables) {
|
|||
|
var x = childNodes.Select(node => node.eval(variables)).ToArray();
|
|||
|
return function(x, variables);
|
|||
|
}
|
|||
|
}
|
|||
|
public class MathExpression {
|
|||
|
private static Random random = new Random();
|
|||
|
|
|||
|
private static Dictionary<char, int> expression_hierarchy = new Dictionary<char, int>{
|
|||
|
{'*', 3},
|
|||
|
{'/', 3},
|
|||
|
{'+', 1},
|
|||
|
{'-', 1},
|
|||
|
};
|
|||
|
MathExpressionNode rootNode;
|
|||
|
public float eval(float [] variables) {
|
|||
|
return rootNode.eval(variables);
|
|||
|
}
|
|||
|
private static float negate(float[] children, float[] variables) {
|
|||
|
return -children[0];
|
|||
|
}
|
|||
|
private static float mulitply(float[] children, float[] variables) {
|
|||
|
return children[0] * children[1];
|
|||
|
}
|
|||
|
private static float divide(float[] children, float[] variables) {
|
|||
|
return children[0] / children[1];
|
|||
|
}
|
|||
|
private static float add(float[] children, float[] variables) {
|
|||
|
return children[0] + children[1];
|
|||
|
}
|
|||
|
private static float subtract(float[] children, float[] variables) {
|
|||
|
return children[0] - children[1];
|
|||
|
}
|
|||
|
|
|||
|
//private MathExpressionNode parse(Dictionary<string, int> variableNames, string expression_string) {
|
|||
|
|
|||
|
|
|||
|
// var read_characters = 0;
|
|||
|
// var node = new MathExpressionNode();
|
|||
|
// if (expression_string[0] == '(') {
|
|||
|
// var length = LSystemFileParser.countParenthesisEnd(expression_string, '(', ')');
|
|||
|
// if (length == expression_string.Length - 2) {
|
|||
|
// return parse(variableNames, expression_string.Substring(1, length));
|
|||
|
// }
|
|||
|
|
|||
|
// var left_child_node = parse(variableNames, expression_string.Substring(1, length));
|
|||
|
// read_characters += length + 2;
|
|||
|
|
|||
|
// node.function = getFunction(expression_string[read_characters]);
|
|||
|
// read_characters += 1;
|
|||
|
|
|||
|
// if (expression_string[read_characters] == '(')
|
|||
|
// }
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//}
|
|||
|
|
|||
|
private static MathExpressionNode parse(Dictionary<string, int> variableNames, string expression_string) {
|
|||
|
expression_string = expression_string.Trim();
|
|||
|
var expression_pos = -1;
|
|||
|
var current_level = 1000;
|
|||
|
for (int i = 0; i < expression_string.Length; i++) {
|
|||
|
if (expression_string[i] == '(') {
|
|||
|
var length = LSystemFileParser.countParenthesisEnd(expression_string.Substring(i), '(', ')');
|
|||
|
if (length == expression_string.Length - 2) {
|
|||
|
return parse(variableNames, expression_string.Substring(1, length));
|
|||
|
}
|
|||
|
//skip parenthesis
|
|||
|
// if expression is covered in ( )
|
|||
|
if (i == 0 && length == expression_string.Length - 2) {
|
|||
|
return parse(variableNames, expression_string.Substring(1, length));
|
|||
|
}
|
|||
|
else {
|
|||
|
i += length + 1;
|
|||
|
continue;
|
|||
|
}
|
|||
|
}
|
|||
|
int new_level;
|
|||
|
if (expression_hierarchy.TryGetValue(expression_string[i],out new_level)) {
|
|||
|
if (i>0 && !(i - 1 == expression_pos && expression_string[i] == '-')) {
|
|||
|
if (new_level <= current_level) {
|
|||
|
current_level = new_level;
|
|||
|
expression_pos = i;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
if (expression_pos > 0) {
|
|||
|
var left_node = parse(variableNames, expression_string.Substring(0, expression_pos));
|
|||
|
var right_node = parse(variableNames, expression_string.Substring(expression_pos + 1));
|
|||
|
MathExpressionNode[] child_nodes = { left_node, right_node };
|
|||
|
switch (expression_string[expression_pos]) {
|
|||
|
case '*':
|
|||
|
return new MathExpressionNode(mulitply, child_nodes);
|
|||
|
break;
|
|||
|
case '/':
|
|||
|
return new MathExpressionNode(divide, child_nodes);
|
|||
|
break;
|
|||
|
case '+':
|
|||
|
return new MathExpressionNode(add, child_nodes);
|
|||
|
break;
|
|||
|
case '-':
|
|||
|
return new MathExpressionNode(subtract, child_nodes);
|
|||
|
break;
|
|||
|
default:
|
|||
|
throw new Exception(String.Format("unknown operation {0} in {1}", expression_string[expression_pos], expression_string));
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
else if (expression_string[0] == '-') {
|
|||
|
MathExpressionNode[] a = { parse(variableNames, expression_string.Substring(1)) };
|
|||
|
return new MathExpressionNode(negate, a);
|
|||
|
}
|
|||
|
else {
|
|||
|
int index;
|
|||
|
if (expression_string == "RANDOM") {
|
|||
|
return new MathExpressionNode((float[] children, float[] arguments) => (float)random.NextDouble(), new MathExpressionNode[0]);
|
|||
|
}
|
|||
|
if (variableNames.TryGetValue(expression_string.Trim(),out index)){
|
|||
|
return new MathExpressionNode((float[] children, float[] arguments) => arguments[index], new MathExpressionNode[0]);
|
|||
|
}
|
|||
|
else {
|
|||
|
try {
|
|||
|
float value = float.Parse(expression_string, NumberStyles.Any, CultureInfo.InvariantCulture);
|
|||
|
return new MathExpressionNode((float[] children, float[] arguments) => value, new MathExpressionNode[0]);
|
|||
|
}
|
|||
|
catch (Exception) {
|
|||
|
|
|||
|
throw new Exception(String.Format("can't parse ``{0}``. It's not a number nor a known variable", expression_string));
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
public MathExpression(Dictionary<string,int> variableNames, string expression_string) {
|
|||
|
rootNode = parse(variableNames, expression_string);
|
|||
|
}
|
|||
|
}
|
|||
|
public class MathExpressionComparasionParser {
|
|||
|
private static bool le(float a, float b) { return a < b; }
|
|||
|
private static bool leq(float a, float b) { return a <= b; }
|
|||
|
private static bool eq(float a, float b) { return a == b; }
|
|||
|
|
|||
|
public static MathExpressionComparison parse(Dictionary<string, int> variableNames, string expression_string) {
|
|||
|
//var operations = new string[]{ "<=", ">=", "<", ">"};
|
|||
|
if (expression_string.Contains("<=")) {
|
|||
|
|
|||
|
var parts = expression_string.Split(new string[] { "<=" }, StringSplitOptions.None).Select(s => s.Trim()).ToArray();
|
|||
|
return new MathExpressionComparison(new MathExpression(variableNames, parts[0]), new MathExpression(variableNames, parts[1]), leq);
|
|||
|
}
|
|||
|
if (expression_string.Contains(">=")) {
|
|||
|
var parts = expression_string.Split(new string[] { ">=" }, StringSplitOptions.None).Select(s => s.Trim()).ToArray();
|
|||
|
return new MathExpressionComparison(new MathExpression(variableNames, parts[1]), new MathExpression(variableNames, parts[0]), leq);
|
|||
|
}
|
|||
|
if (expression_string.Contains("==")) {
|
|||
|
var parts = expression_string.Split(new string[] { "==" }, StringSplitOptions.None).Select(s => s.Trim()).ToArray();
|
|||
|
return new MathExpressionComparison(new MathExpression(variableNames, parts[1]), new MathExpression(variableNames, parts[0]), eq);
|
|||
|
}
|
|||
|
if (expression_string.Contains("<")) {
|
|||
|
var parts = expression_string.Split('<').Select(s => s.Trim()).ToArray();
|
|||
|
return new MathExpressionComparison(new MathExpression(variableNames, parts[0]), new MathExpression(variableNames, parts[1]), le);
|
|||
|
}
|
|||
|
if (expression_string.Contains(">")) {
|
|||
|
var parts = expression_string.Split('>').Select(s => s.Trim()).ToArray();
|
|||
|
return new MathExpressionComparison(new MathExpression(variableNames, parts[1]), new MathExpression(variableNames, parts[0]), le);
|
|||
|
}
|
|||
|
|
|||
|
throw new Exception(String.Format("comparison operation not recognized in {}", expression_string));
|
|||
|
}
|
|||
|
}
|
|||
|
}
|