SplitterParser now allows for multiple symbols

added ternary operator to Equation
This commit is contained in:
CreepyCre 2021-02-16 14:19:42 +01:00
parent 0080a971b5
commit 4f9d554a14
2 changed files with 122 additions and 39 deletions

View file

@ -1,12 +1,9 @@
package org.dimdev.dimdoors.util.math; package org.dimdev.dimdoors.util.math;
import java.util.ArrayList; import java.util.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.BiFunction; import java.util.function.BiFunction;
import net.minecraft.util.Pair;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
@ -55,42 +52,40 @@ public interface Equation {
}); });
// some logic first // some logic first
// ? :
parseRules.add(new SplitterParser()
.add((variableMap, equations) -> equations[0].asBoolean(variableMap) ? equations[1].apply((variableMap)) : equations[2].apply(variableMap), "?", ":"));
// || // ||
Map<String, TriFunction<Map<String, Double>, Equation, Equation, Double>> or = new HashMap<>(); parseRules.add(new SplitterParser()
or.put("||", (stringDoubleMap, first, second) -> toDouble(first.asBoolean(stringDoubleMap) || second.asBoolean(stringDoubleMap))); .add((variableMap, equations) -> toDouble(equations[0].asBoolean(variableMap) || equations[1].asBoolean((variableMap))), "||"));
parseRules.add(new SplitterParser(or));
// && // &&
Map<String, TriFunction<Map<String, Double>, Equation, Equation, Double>> and = new HashMap<>(); parseRules.add(new SplitterParser()
and.put("&&", (stringDoubleMap, first, second) -> toDouble(first.asBoolean(stringDoubleMap) && second.asBoolean(stringDoubleMap))); .add((variableMap, equations) -> toDouble(equations[0].asBoolean(variableMap) && equations[1].asBoolean((variableMap))), "&&"));
parseRules.add(new SplitterParser(and));
// ==, <=, >=, <, > // ==, <=, >=, <, >
Map<String, TriFunction<Map<String, Double>, Equation, Equation, Double>> comparators = new HashMap<>(); parseRules.add(new SplitterParser()
comparators.put("==", (stringDoubleMap, first, second) -> toDouble(first.apply(stringDoubleMap) == second.apply(stringDoubleMap))); .add((variableMap, equations) -> toDouble(equations[0].apply(variableMap) == equations[1].apply((variableMap))), "==")
comparators.put("<=", (stringDoubleMap, first, second) -> toDouble(first.apply(stringDoubleMap) <= second.apply(stringDoubleMap))); .add((variableMap, equations) -> toDouble(equations[0].apply(variableMap) <= equations[1].apply((variableMap))), "<=")
comparators.put(">=", (stringDoubleMap, first, second) -> toDouble(first.apply(stringDoubleMap) >= second.apply(stringDoubleMap))); .add((variableMap, equations) -> toDouble(equations[0].apply(variableMap) >= equations[1].apply((variableMap))), ">=")
comparators.put("<", (stringDoubleMap, first, second) -> toDouble(first.apply(stringDoubleMap) < second.apply(stringDoubleMap))); .add((variableMap, equations) -> toDouble(equations[0].apply(variableMap) < equations[1].apply((variableMap))), "<")
comparators.put(">", (stringDoubleMap, first, second) -> toDouble(first.apply(stringDoubleMap) > second.apply(stringDoubleMap))); .add((variableMap, equations) -> toDouble(equations[0].apply(variableMap) > equations[1].apply((variableMap))), ">"));
parseRules.add(new SplitterParser(comparators));
// +, - // +, -
Map<String, TriFunction<Map<String, Double>, Equation, Equation, Double>> sumOperations = new HashMap<>(); parseRules.add(new SplitterParser()
sumOperations.put("+", (stringDoubleMap, first, second) -> first.apply(stringDoubleMap) + second.apply(stringDoubleMap)); .add((variableMap, equations) -> equations[0].apply(variableMap) + equations[1].apply((variableMap)), "+")
sumOperations.put("-", (stringDoubleMap, first, second) -> first.apply(stringDoubleMap) - second.apply(stringDoubleMap)); .add((variableMap, equations) -> equations[0].apply(variableMap) - equations[1].apply((variableMap)), "-"));
parseRules.add(new SplitterParser(sumOperations));
// *, /, % // *, /, %
Map<String, TriFunction<Map<String, Double>, Equation, Equation, Double>> dotOperations = new HashMap<>(); parseRules.add(new SplitterParser()
dotOperations.put("*", (stringDoubleMap, first, second) -> first.apply(stringDoubleMap) * second.apply(stringDoubleMap)); .add((variableMap, equations) -> equations[0].apply(variableMap) * equations[1].apply((variableMap)), "*")
dotOperations.put("/", (stringDoubleMap, first, second) -> first.apply(stringDoubleMap) / second.apply(stringDoubleMap)); .add((variableMap, equations) -> equations[0].apply(variableMap) / equations[1].apply((variableMap)), "/")
dotOperations.put("%", (stringDoubleMap, first, second) -> first.apply(stringDoubleMap) % second.apply(stringDoubleMap)); .add((variableMap, equations) -> equations[0].apply(variableMap) % equations[1].apply((variableMap)), "%"));
parseRules.add(new SplitterParser(dotOperations));
// x^y // x^y
Map<String, TriFunction<Map<String, Double>, Equation, Equation, Double>> exponentOperations = new HashMap<>(); parseRules.add(new SplitterParser()
exponentOperations.put("^", (stringDoubleMap, first, second) -> Math.pow(first.apply(stringDoubleMap), second.apply(stringDoubleMap))); .add((variableMap, equations) -> Math.pow(equations[0].apply(variableMap), equations[1].apply(variableMap)), "^"));
parseRules.add(new SplitterParser(exponentOperations));
// H with H(0) = 1: https://en.wikipedia.org/wiki/Heaviside_step_function // H with H(0) = 1: https://en.wikipedia.org/wiki/Heaviside_step_function
parseRules.add(new FunctionParser("H", 1, 1, ((stringDoubleMap, equations) -> equations[0].apply(stringDoubleMap) >= 0 ? 1d : 0d))); parseRules.add(new FunctionParser("H", 1, 1, ((stringDoubleMap, equations) -> equations[0].apply(stringDoubleMap) >= 0 ? 1d : 0d)));
@ -151,10 +146,17 @@ public interface Equation {
} }
private static class SplitterParser implements EquationParser { private static class SplitterParser implements EquationParser {
private final Map<String, TriFunction<Map<String, Double>, Equation, Equation, Double>> operations; private final Map<String, Pair<String[], BiFunction<Map<String, Double>, Equation[], Double>>> operations;
public SplitterParser(Map<String, TriFunction<Map<String, Double>, Equation, Equation, Double>> operations) { public SplitterParser() {
this.operations = operations; this.operations = new HashMap<>();
}
public SplitterParser add(BiFunction<Map<String, Double>, Equation[], Double> function, String... symbols) {
List<String> symbolList = Arrays.asList(symbols);
Collections.reverse(symbolList);
operations.put(symbolList.get(0), new Pair<>(symbolList.toArray(new String[0]), function));
return this;
} }
@Override @Override
@ -164,12 +166,41 @@ public interface Equation {
String substring = toParse.substring(i); String substring = toParse.substring(i);
if (substring.startsWith(")")) depth++; if (substring.startsWith(")")) depth++;
else if (substring.startsWith("(")) depth--; else if (substring.startsWith("(")) depth--;
for (String symbol : this.operations.keySet()) { for (String currentSymbol : this.operations.keySet()) {
if (substring.startsWith(symbol) && depth == 0) { if (depth == 0 && substring.startsWith(currentSymbol)) {
final TriFunction<Map<String, Double>, Equation, Equation, Double> operation = this.operations.get(symbol); final Pair<String[], BiFunction<Map<String, Double>, Equation[], Double>> operation = this.operations.get(currentSymbol);
final Equation first = Equation.parse(toParse.substring(0, i)); final String[] symbols = operation.getLeft();
final Equation second = Equation.parse(toParse.substring(i + 1)); List<Pair<Integer, Integer>> partIndices = new ArrayList<>(symbols.length + 1);
return Optional.of(stringDoubleMap -> operation.apply(stringDoubleMap, first, second)); partIndices.add(new Pair<>(i + currentSymbol.length(), toParse.length()));
int symbolPointer = 1;
if (symbolPointer < symbols.length) currentSymbol = symbols[symbolPointer];
int endIndex = i;
int innerDepth = 0;
for (int j = i - 1; j >= 1 && symbolPointer < symbols.length; j--) {
String innerSubstring = toParse.substring(j);
if (innerSubstring.startsWith(")")) innerDepth++;
else if (innerSubstring.startsWith("(")) innerDepth--;
if (innerDepth == 0 && innerSubstring.startsWith(currentSymbol)) {
partIndices.add(new Pair<>(j + currentSymbol.length(), endIndex));
endIndex = j;
symbolPointer++;
if (symbolPointer < symbols.length) currentSymbol = symbols[symbolPointer];
}
}
if (symbolPointer < symbols.length) continue;
partIndices.add(new Pair<>(0, endIndex));
Equation[] equations = new Equation[partIndices.size()];
for (int j = 0; j < partIndices.size(); j++) {
Pair<Integer, Integer> pair = partIndices.get(j);
equations[partIndices.size() - j - 1] = Equation.parse(toParse.substring(pair.getLeft(), pair.getRight()));
}
return Optional.of(stringDoubleMap -> operation.getRight().apply(stringDoubleMap, equations));
} }
} }
} }

View file

@ -0,0 +1,52 @@
package org.dimdev.dimdoors.util.math;
import org.junit.jupiter.api.Test;
import java.util.HashMap;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.*;
class EquationTest {
@Test
void parseAndApply() throws Equation.EquationParseException {
Map<String, Double> empty = new HashMap<>();
double expected;
String equation;
assertThrows(Equation.EquationParseException.class, () -> Equation.parse("."));
expected = 15d;
equation = Double.toString(expected);
assertEquals(expected, Equation.parse(equation).apply(empty));
expected = 4d;
equation = "2 + 2";
assertEquals(expected, Equation.parse(equation).apply(empty));
expected = 1;
equation = "1 ? 1 : 0";
assertEquals(expected, Equation.parse(equation).apply(empty));
expected = 0;
equation = "0 ? 1 : 0";
assertEquals(expected, Equation.parse(equation).apply(empty));
expected = 1;
equation = (Math.random() + 1d) + "? 1 : 0";
assertEquals(expected, Equation.parse(equation).apply(empty));
expected = 1;
equation = (Math.random() - 1d) + "? 1 : 0";
assertEquals(expected, Equation.parse(equation).apply(empty));
}
void parseAndAsBoolean() throws Equation.EquationParseException {
Map<String, Double> empty = new HashMap<>();
}
}