ZMWSLI0-SL2021-GR11/Projekt/MWSProjekt/Assets/Scripts/MathExpression.cs

248 lines
9.3 KiB
C#

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
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 System.Random random = new System.Random();
private static Dictionary<char, int> expression_hierarchy = new Dictionary<char, int>{
{'^', 4},
{'*', 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 power(float[] children, float[] variables)
{
return (float)Math.Pow(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;
case '^':
return new MathExpressionNode(power, 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));
}
}