Files
engine/Engine/Form1.cs
T

643 lines
25 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Engine
{
public partial class Form1 : Form
{
//Invert over all expression (i + 7) ^ 2 -> -(i + 7) ^ 2
private Stack<Node> Tree = new Stack<Node>();
private Dictionary<string, double> Symbols = new Dictionary<string, double>();
public Form1()
{
InitializeComponent();
}
private void Button1_Click(object sender, EventArgs e)
{
var s = textBox1.Text;
var f = FlattenInput(s);
PrintFlatList(f);
f.Reverse();
var stack = new Stack<Token>(f);
ActionsListView.Items.Clear();
button1.Text = "Result: " + NewCalc(stack);
//var f2 = GetSubExpressions(f);
//PrintSteps(f2);
//PrintSymbolsTable();
//var result = Calc(f2);
//button1.Text = $"Result: {result}";
//var result = Calc(FlattenInput(s));
}
void PrintSteps(List<List<Node>> expressions)
{
StepsListView.Items.Clear();
for(var i = 0; i < expressions.Count; i++)
{
var expression = expressions[i];
var item = new ListViewItem($"Step {i + 1}");
var ex = string.Empty;
foreach (var token in expression)
{
if (!token.IsCoefficent)
ex += token.Value + " ";
else
ex += token.Value;
}
item.SubItems.Add(ex);
StepsListView.Items.Add(item);
}
}
void PrintSymbolsTable()
{
SymbolsListView.Items.Clear();
foreach(var k in Symbols)
{
var item = new ListViewItem(k.Key);
item.SubItems.Add(k.Value.ToString());
SymbolsListView.Items.Add(item);
}
}
void PrintFlatList(List<Token> tokens)
{
ExpressionBreakdownListView.Items.Clear();
foreach(var token in tokens)
{
var item = new ListViewItem(token.Value);
if(!token.IsCoefficent) item.SubItems.Add(token.Type.ToString());
else item.SubItems.Add(token.Type.ToString() + " (Coefficent)");
ExpressionBreakdownListView.Items.Add(item);
}
}
double NewCalc(Stack<Token> tokens, double co = 1)
{
var previousToken = new Token() { Type = TokenType.Unknown };
var runningValue = 0d;
while(tokens.Count > 0)
{
var token = tokens.Pop();
if (token.Type == TokenType.ExpEnd)
{
if(tokens.Count > 0 && tokens.Peek().Type == TokenType.Power)
{
var op = tokens.Pop();
var powerOf = tokens.Pop();
if(powerOf.Type == TokenType.Constant)
{
ActionsListView.Items.Add($"Taking {runningValue} to the power of {powerOf.Value}.");
runningValue = Operate(runningValue, Convert.ToDouble(powerOf.Value), op.Type);
}
}
break;
}
if(token.Type == TokenType.ExpStart)
{
runningValue = NewCalc(tokens);
continue;
}
if(token.IsCoefficent)
{
var lookAHead = tokens.Pop();
if (lookAHead.Type == TokenType.Variable)
{
ActionsListView.Items.Add($"{token.Value} is a coeffiecent, multiplying it against {Symbols[lookAHead.Value]} (Symbol '{lookAHead.Value}').");
runningValue += Convert.ToDouble(token.Value) * Symbols[lookAHead.Value];
if (previousToken.Type != TokenType.Unknown) throw new Exception("Token shouldn't have a valid value!");
//2a(
if(tokens.Count != 0 && tokens.Peek().Type == TokenType.ExpStart)
{
runningValue += NewCalc(tokens, runningValue);
}
previousToken = new Token() { Type = TokenType.Constant, Value = runningValue.ToString(), IsCoefficent = false };
continue;
}
else if (lookAHead.Type == TokenType.ExpStart)
{
runningValue += NewCalc(tokens, Convert.ToDouble(token.Value));
previousToken = new Token() { Type = TokenType.Constant, Value = runningValue.ToString(), IsCoefficent = false };
continue;
}
else throw new Exception("Invalid grammar!");
}
//If token is an operator
if(GetOperator(token.Value[0]) != TokenType.Unknown)
{
//Operator found
var lookAHead = tokens.Pop();
if(lookAHead.Type == TokenType.Constant && !lookAHead.IsCoefficent)
{
var tmpValue = 0d;
while (tokens.Count > 0 && (tokens.Peek().Type == TokenType.Multiply || tokens.Peek().Type == TokenType.Divide || tokens.Peek().Type == TokenType.Power))
{
var op = tokens.Pop();
if (op.Type != TokenType.Power)
{
var next = tokens.Pop();
if (next.Type == TokenType.ExpStart)
{
var returnValue = NewCalc(tokens);
if (tmpValue != 0)
{
ActionsListView.Items.Add($"{GetOperatorVerb(op.Type)} {tmpValue} (tmp) and {returnValue} (returnValue).");
tmpValue = Operate(tmpValue, returnValue, op.Type);
lookAHead.Value = tmpValue.ToString();
}
else
{
ActionsListView.Items.Add($"{GetOperatorVerb(op.Type)} {Convert.ToDouble(lookAHead.Value) * co} (lookAHead) and {returnValue} (returnValue).");
tmpValue = Operate(Convert.ToDouble(lookAHead.Value) * co, returnValue, op.Type);
lookAHead.Value = tmpValue.ToString();
}
continue;
}
if (tmpValue != 0)
{
ActionsListView.Items.Add($"{GetOperatorVerb(op.Type)} {tmpValue} (tmp) and {Convert.ToDouble(next.Value) * co} (next).");
tmpValue = Operate(tmpValue, Convert.ToDouble(next.Value) * co, op.Type);
lookAHead.Value = tmpValue.ToString();
}
else
{
ActionsListView.Items.Add($"{GetOperatorVerb(op.Type)} {Convert.ToDouble(lookAHead.Value) *co} (lookAHead) and {next.Value} (next).");
tmpValue = Operate(Convert.ToDouble(lookAHead.Value) *co, Convert.ToDouble(next.Value) *co, op.Type);
lookAHead.Value = tmpValue.ToString();
}
}
else if (op.Type == TokenType.Power)
{
}
}
//if(tokens.Count > 0 && (tokens.Peek().Type == TokenType.Divide || tokens.Peek().Type == TokenType.Multiply || tokens.Peek().Type == TokenType.Power))
//{
// var op = tokens.Pop();
// var con = tokens.Pop();
// //TODO: check if "con" is a variable, right now we're assuming its a constant.
// ActionsListView.Items.Add($"{GetOperatorVerb(op.Type)} {Convert.ToDouble(lookAHead.Value) * co} and {Convert.ToDouble(con.Value) * co} (Oder of Operations).");
// var tmp = Operate(Convert.ToDouble(lookAHead.Value) * co, Convert.ToDouble(con.Value) * co, op.Type);
// ActionsListView.Items.Add($"{GetOperatorVerb(token.Type)} {Convert.ToDouble(previousToken.Value) * co} and {tmp}.");
// runningValue += Operate(Convert.ToDouble(previousToken.Value) * co, tmp, token.Type);
// previousToken = new Token { Type = TokenType.Unknown };
//}
//else
//{
if (previousToken.Type != TokenType.Unknown)
{
ActionsListView.Items.Add($"{GetOperatorVerb(token.Type)} {Convert.ToDouble(previousToken.Value) * co} and {Convert.ToDouble(lookAHead.Value) * co}.");
runningValue += Operate(Convert.ToDouble(previousToken.Value) * co, Convert.ToDouble(lookAHead.Value) * co, token.Type);
}
else
{
ActionsListView.Items.Add($"{GetOperatorVerb(token.Type)} {runningValue} and {Convert.ToDouble(lookAHead.Value) * co}.");
runningValue = Operate(runningValue, Convert.ToDouble(lookAHead.Value) * co, token.Type);
}
//}
}
}
else if(token.Type == TokenType.Constant)
{
previousToken = token;
}
}
return runningValue;
}
List<List<Node>> GetSubExpressions(List<Node> tokens)
{
var expressions = new List<List<Node>>();
var stack = new Stack<List<Node>>();
var tmp = new List<Node>();
var skipCount = 0;
var nestingLevel = 0;
for(var i = 0; i < tokens.Count; i++)
{
if(skipCount > 0)
{
skipCount--;
continue;
}
var token = tokens[i];
//if (stack.Count > 0 && nestingLevel == 0)
//{
// if (!stack.Peek()[0].IsCoefficent)
// {
// var offset = 0;
// while(stack.Count > 0)
// {
// expressions.Insert(0, stack.Pop());
// offset++;
// }
// }
//}
if (token.IsCoefficent)
{
//var lookAhead = tokens[i + 1];
//if(lookAhead.Type != Node.Token.ExpStart)
//{
if (tmp.Count > 0) expressions.Add(new List<Node>(tmp));
expressions.Add(new List<Node>() { token });
//}
//else
//{
// stack.Push(new List<Node>(tmp));
//}
tmp.Clear();
}
else if (token.Type == Node.Token.ExpStart)
{
nestingLevel++;
//if (i - 1 >= 0)
//{
// var lookBehind = tokens[i - 1];
// if (lookBehind.IsCoefficent)
// {
// tmp.Remove(tmp.Last());
// expressions.Add(new List<Node>(tmp));
// tmp.Clear();
// stack.Push(new List<Node> { lookBehind });
// //tmp.Add(token);
// continue;
// }
//}
if (tmp.Count > 0) expressions.Add(new List<Node>(tmp));
tmp.Clear();
tmp.Add(token);
}
else if(token.Type == Node.Token.ExpEnd)
{
nestingLevel--;
if (i + 1 < tokens.Count)
{
var lookAHead = tokens[i + 1];
if (lookAHead.Type == Node.Token.Power)
{
var toPowerOf = tokens[i + 2];
tmp.Add(token);
tmp.Add(lookAHead);
tmp.Add(toPowerOf);
expressions.Add(new List<Node>(tmp));
tmp.Clear();
skipCount = 2;
continue;
}
}
tmp.Add(token);
if (tmp.Count > 0) expressions.Add(new List<Node>(tmp));
tmp.Clear();
}
else
{
tmp.Add(token);
}
}
if(tmp.Count > 0)
{
expressions.Add(new List<Node>(tmp));
}
return expressions;
}
List<Token> FlattenInput(string expression)
{
//if (expression.Count(x => x == '(') == 1 && expression.Count(x => x == ')') == 1) throw new Exception("Unbalanced params!");
//if(expression.Count(x => x == '(') % 2 != 0 || expression.Count(x => x == ')') % 2 != 0) throw new Exception("Unbalanced params!");
Symbols.Clear();
var tokens = new List<Token>();
var tmp = string.Empty;
var parsingNumber = false;
for(var i = 0; i < expression.Length; i++)
{
var c = expression[i];
var op = GetOperator(c);
if (c == '.' || int.TryParse(c.ToString(), out int _))
{
if(tokens.Count > 1)
{
var lookBehind = tokens[tokens.Count - 1];
if(lookBehind.Type == TokenType.ExpEnd)
{
tokens.Add(new Token() { Value = "^", Type = TokenType.Power, IsCoefficent = false });
}
}
if((i + 1) == expression.Length)
{
tokens.Add(new Token() { Value = $"{tmp}{c}", Type = TokenType.Constant, IsCoefficent = false });//new Node($"{tmp}{c}", Node.Token.Constant));
}
parsingNumber = true;
tmp += c;
continue;
}
else if(c == '(')
{
if (parsingNumber)
{
tokens.Add(new Token() { Value = tmp, Type = TokenType.Constant, IsCoefficent = true });//new Node(tmp, Node.Token.Constant) { IsCoefficent = true });
}
tokens.Add(new Token() { Value = "(", Type = TokenType.ExpStart, IsCoefficent = false });//new Node("(", Node.Token.ExpStart));
parsingNumber = false;
tmp = string.Empty;
continue;
}
else if(c == ')')
{
if (parsingNumber)
{
tokens.Add(new Token() { Value = tmp, Type = TokenType.Constant, IsCoefficent = false }); //new Node(tmp, Node.Token.Constant));
}
tokens.Add(new Token() { Value = ")", Type = TokenType.ExpEnd, IsCoefficent = false }); //new Node(c.ToString(), Node.Token.ExpEnd));
parsingNumber = false;
tmp = string.Empty;
continue;
}
else if(op != TokenType.Unknown)
{
if(parsingNumber)
{
tokens.Add(new Token() { Value = tmp, Type = TokenType.Constant, IsCoefficent = false }); //new Node(tmp, Node.Token.Constant));
}
tokens.Add(new Token() { Value = c.ToString(), Type = op, IsCoefficent = false });//new Node(c.ToString(), op));
parsingNumber = false;
tmp = string.Empty;
continue;
}
else if(c != ' ')
{
if (!Symbols.ContainsKey(c.ToString()))
{
Symbols.Add(c.ToString(), 1);
}
else
{
Symbols[c.ToString()]++;
}
if (tokens.Count > 1)
{
var lookBehind = tokens[tokens.Count - 1];
if (lookBehind.Type == TokenType.ExpEnd)
{
tokens.Add(new Token() { Value = "^", Type = TokenType.Power, IsCoefficent = false });//new Node("^", Node.Token.Power));
}
}
if ((i + 1) < expression.Length)
{
var lookAHead = expression[i + 1];
if(lookAHead == '(')
{
tokens.Add(new Token() { Value = c.ToString(), Type = TokenType.Variable, IsCoefficent = true });
tmp = string.Empty;
parsingNumber = false;
continue;
}
}
if (parsingNumber)
{
tokens.Add(new Token() {Value = tmp, Type = TokenType.Constant, IsCoefficent = true });
}
tokens.Add(new Token() { Value = c.ToString(), Type = TokenType.Variable, IsCoefficent = false });
parsingNumber = false;
tmp = string.Empty;
}
}
return tokens;
}
//double Calc(List<List<Node>> expressions, double co = 1)
//{
// //Assumption: an operator is never last in the list.
// //double runningTotal = 0;
// double lastValue = 0;
// var next = true;
// Node previousToken = new Node("zzzz", Node.Token.Unknown);
// for(var i = 0; i < expressions.Count;)
// {
// if (!next) break;
// var tokens = expressions[i];
// expressions.RemoveAt(i);
// for (var j = 0; j < tokens.Count; j++)
// {
// var token = tokens[j];
// if(token.IsCoefficent)
// {
// if(tokens.Count == 1)
// {
// return Calc(expressions, Convert.ToDouble(token.Value));
// }
// }
// else if(token.Type == Node.Token.Constant)
// {
// previousToken = token;
// }
// else if(token.Type == Node.Token.Variable)
// {
// //TODO: do symbol lookup to get value for this variale.
// previousToken = new Node("666", Node.Token.Variable);
// }
// else if(GetOperator(token.Value[0]) != Node.Token.Unknown)
// {
// if(tokens.Count > j + 1)
// {
// j++;
// var lookAHead = tokens[j];
// if(lookAHead.Type == Node.Token.Constant)
// {
// if (previousToken.Type != Node.Token.Unknown)
// {
// lastValue = Operate(Convert.ToDouble(previousToken.Value) * co, Convert.ToDouble(lookAHead.Value) * co, token.Type);
// previousToken = new Node("zzzz", Node.Token.Unknown);
// }
// else
// lastValue = Operate(lastValue * co, Convert.ToDouble(lookAHead.Value) * co, token.Type);
// }
// }
// else
// {
// lastValue = Operate(Convert.ToDouble(previousToken.Value), Calc(expressions), token.Type);
// }
// }
// else if(token.Type == Node.Token.ExpStart)
// {
// }
// else if(token.Type == Node.Token.ExpEnd)
// {
// if(tokens.Count > j + 1)
// {
// var lookAHead = tokens[j + 1];
// if(lookAHead.Type == Node.Token.Power)
// {
// lookAHead = tokens[j + 2];
// lastValue = Operate(lastValue, Convert.ToDouble(lookAHead.Value), Node.Token.Power);
// }
// }
// next = false;
// }
// }
// }
// return lastValue;
//}
double Operate(double n1, double n2, TokenType operation)
{
switch(operation)
{
case TokenType.Add:
return n1 + n2;
case TokenType.Divide:
return n1 / n2;
case TokenType.Multiply:
return n1 * n2;
case TokenType.Power:
return Math.Pow(n1, n2);
case TokenType.Subtract:
return n1 - n2;
default:
throw new Exception("Token must be an operator!");
}
}
TokenType GetOperator(char c)
{
switch (c)
{
case '+':
return TokenType.Add;
case '-':
return TokenType.Subtract;
case '*':
return TokenType.Multiply;
case '^':
return TokenType.Power;
case '/':
return TokenType.Divide;
default:
return TokenType.Unknown;
}
}
string GetOperatorVerb(TokenType type)
{
switch (type)
{
case TokenType.Add:
return "Adding";
case TokenType.Divide:
return "Dividing";
case TokenType.Multiply:
return "Multiplying";
case TokenType.Power:
return "Raising";
case TokenType.Subtract:
return "Subtracting";
default:
throw new Exception("Token must be an operator!");
}
}
struct Token
{
public string Value;
public bool IsCoefficent;
public TokenType Type;
}
enum TokenType
{
Add,
Subtract,
Multiply,
Divide,
Power,
Variable,
Constant,
ExpStart,
ExpEnd,
SubScript,
SuperScript,
Unknown
}
}
}