aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoman / Linnea Gräf <roman.graef@gmail.com>2023-06-19 19:23:43 +0200
committerGitHub <noreply@github.com>2023-06-19 19:23:43 +0200
commita82819ec18bed8212fa73fda987cff951b810450 (patch)
tree2e18b55a6870ce5bd75516dd140ab3e6441054e5
parent7fd26d14e742c974ec50686c375ccdfd9c968faf (diff)
downloadNotEnoughUpdates-a82819ec18bed8212fa73fda987cff951b810450.tar.gz
NotEnoughUpdates-a82819ec18bed8212fa73fda987cff951b810450.tar.bz2
NotEnoughUpdates-a82819ec18bed8212fa73fda987cff951b810450.zip
Add variables to calculator (#721)
* Add variables to calculator * Fix unary minus for variables
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscgui/NeuSearchCalculator.java14
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/Calculator.java58
-rw-r--r--src/main/kotlin/io/github/moulberry/notenoughupdates/commands/misc/MiscCommands.kt3
-rw-r--r--src/test/java/io/github/moulberry/notenoughupdates/util/CalculatorTest.java33
4 files changed, 88 insertions, 20 deletions
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/NeuSearchCalculator.java b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/NeuSearchCalculator.java
index f7306f2a..71dedb12 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/NeuSearchCalculator.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/NeuSearchCalculator.java
@@ -20,10 +20,14 @@
package io.github.moulberry.notenoughupdates.miscgui;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.auction.APIManager;
+import io.github.moulberry.notenoughupdates.util.ApiUtil;
import io.github.moulberry.notenoughupdates.util.Calculator;
+import javax.swing.text.html.Option;
import java.math.BigDecimal;
import java.text.DecimalFormat;
+import java.util.Optional;
public class NeuSearchCalculator {
@@ -43,7 +47,7 @@ public class NeuSearchCalculator {
if (!lastInput.equals(input)) {
lastInput = input;
try {
- BigDecimal calculate = Calculator.calculate(input);
+ BigDecimal calculate = Calculator.calculate(input, PROVIDE_LOWEST_BIN);
lastResult = new DecimalFormat("#,##0.##").format(calculate);
} catch (Calculator.CalculatorException ignored) {
lastResult = null;
@@ -52,4 +56,12 @@ public class NeuSearchCalculator {
return lastResult;
}
+
+ public static Calculator.VariableProvider PROVIDE_LOWEST_BIN = name -> {
+ double bazaarOrBin = NotEnoughUpdates.INSTANCE.manager.auctionManager.getBazaarOrBin(name, false);
+ if (bazaarOrBin < 0)
+ return Optional.empty();
+ return Optional.of(BigDecimal.valueOf(bazaarOrBin));
+ };
+
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/Calculator.java b/src/main/java/io/github/moulberry/notenoughupdates/util/Calculator.java
index 4d57d92f..a58fc8a6 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/util/Calculator.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/Calculator.java
@@ -27,16 +27,26 @@ import java.util.Deque;
import java.util.List;
import java.util.Locale;
import java.util.NoSuchElementException;
+import java.util.Optional;
public class Calculator {
+ public interface VariableProvider {
+ Optional<BigDecimal> provideVariable(String name) throws CalculatorException;
+ }
+
+ public static BigDecimal calculate(String source, VariableProvider variables) throws CalculatorException {
+ return evaluate(variables, shuntingYard(lex(source)));
+ }
+
public static BigDecimal calculate(String source) throws CalculatorException {
- source = source.toLowerCase(Locale.ROOT);
- return evaluate(shuntingYard(lex(source)));
+ return calculate(source, (ignored) -> Optional.empty());
}
+
///<editor-fold desc="Lexing Time">
public enum TokenType {
- NUMBER, BINOP, LPAREN, RPAREN, POSTOP, PREOP
+ NUMBER, BINOP, LPAREN, RPAREN, POSTOP, PREOP, VARIABLE
}
+
public static class Token {
public TokenType type;
String operatorValue;
@@ -49,6 +59,7 @@ public class Calculator {
static String binops = "+-*/^x";
static String postops = "mkbts%";
static String digits = "0123456789";
+ static String nameCharacters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_";
static void readDigitsInto(Token token, String source, boolean decimals) {
int startIndex = token.tokenStart + token.tokenLength;
@@ -103,7 +114,7 @@ public class Calculator {
} else if (binops.indexOf(c) != -1) {
token.tokenLength = 1;
token.type = TokenType.BINOP;
- token.operatorValue = c + "";
+ token.operatorValue = String.valueOf(c);
if (c == '*' && i + 1 < source.length() && source.charAt(i + 1) == '*') {
token.tokenLength++;
token.operatorValue = "^";
@@ -111,7 +122,7 @@ public class Calculator {
} else if (postops.indexOf(c) != -1) {
token.tokenLength = 1;
token.type = TokenType.POSTOP;
- token.operatorValue = c + "";
+ token.operatorValue = String.valueOf(c).toLowerCase(Locale.ROOT);
} else if (c == ')') {
token.tokenLength = 1;
token.type = TokenType.RPAREN;
@@ -127,6 +138,30 @@ public class Calculator {
if (token.tokenLength == 1) {
throw new CalculatorException("Invalid number literal", i, 1);
}
+ } else if ('$' == c) {
+ token.tokenLength = 1;
+ token.type = TokenType.VARIABLE;
+ token.operatorValue = "";
+ boolean inParenthesis = false;
+ if (i + 1 < source.length() && source.charAt(i + 1) == '{') {
+ token.tokenLength++;
+ inParenthesis = true;
+ }
+ for (int j = token.tokenStart + token.tokenLength; j < source.length(); j++) {
+ char d = source.charAt(j);
+ if (inParenthesis) {
+ if (d == '}') {
+ token.tokenLength++;
+ inParenthesis = false;
+ break;
+ }
+ } else if (nameCharacters.indexOf(d) == -1) break;
+ token.operatorValue += d;
+ token.tokenLength++;
+ }
+ if (token.operatorValue.length() == 0 || inParenthesis) {
+ throw new CalculatorException("Unterminated variable literal", token.tokenStart, token.tokenLength);
+ }
} else if (digits.indexOf(c) != -1) {
token.type = TokenType.NUMBER;
readDigitsInto(token, source, false);
@@ -140,7 +175,7 @@ public class Calculator {
} else {
throw new CalculatorException("Unknown thing " + c, i, 1);
}
- justParsedNumber = token.type == TokenType.NUMBER;
+ justParsedNumber = token.type == TokenType.NUMBER || token.type == TokenType.VARIABLE;
tokens.add(token);
i += token.tokenLength;
}
@@ -174,6 +209,7 @@ public class Calculator {
for (Token currentlyShunting : toShunt) {
switch (currentlyShunting.type) {
case NUMBER:
+ case VARIABLE:
out.add(currentlyShunting);
break;
case BINOP:
@@ -230,11 +266,19 @@ public class Calculator {
/// </editor-fold>
///<editor-fold desc="Evaluating Time">
- public static BigDecimal evaluate(List<Token> rpnTokens) throws CalculatorException {
+ public static BigDecimal evaluate(VariableProvider provider, List<Token> rpnTokens) throws CalculatorException {
Deque<BigDecimal> values = new ArrayDeque<>();
try {
for (Token command : rpnTokens) {
switch (command.type) {
+ case VARIABLE:
+ values.push(provider.provideVariable(command.operatorValue)
+ .orElseThrow(() -> new CalculatorException(
+ "Unknown variable " + command.operatorValue,
+ command.tokenStart,
+ command.tokenLength
+ )));
+ break;
case PREOP:
values.push(values.pop().negate());
break;
diff --git a/src/main/kotlin/io/github/moulberry/notenoughupdates/commands/misc/MiscCommands.kt b/src/main/kotlin/io/github/moulberry/notenoughupdates/commands/misc/MiscCommands.kt
index caa57909..64ee444b 100644
--- a/src/main/kotlin/io/github/moulberry/notenoughupdates/commands/misc/MiscCommands.kt
+++ b/src/main/kotlin/io/github/moulberry/notenoughupdates/commands/misc/MiscCommands.kt
@@ -28,6 +28,7 @@ import io.github.moulberry.notenoughupdates.events.RegisterBrigadierCommandEvent
import io.github.moulberry.notenoughupdates.miscgui.CalendarOverlay
import io.github.moulberry.notenoughupdates.miscgui.DynamicLightItemsEditor
import io.github.moulberry.notenoughupdates.miscgui.GuiItemCustomize
+import io.github.moulberry.notenoughupdates.miscgui.NeuSearchCalculator
import io.github.moulberry.notenoughupdates.util.Calculator
import io.github.moulberry.notenoughupdates.util.Calculator.CalculatorException
import io.github.moulberry.notenoughupdates.util.MinecraftExecutor
@@ -51,7 +52,7 @@ class MiscCommands {
thenArgumentExecute("calculation", RestArgumentType) { calculation ->
val calculation = this[calculation]
try {
- val calculate = Calculator.calculate(calculation)
+ val calculate = Calculator.calculate(calculation, NeuSearchCalculator.PROVIDE_LOWEST_BIN)
val formatter = DecimalFormat("#,##0.##")
val formatted = formatter.format(calculate)
reply("$WHITE$calculation $YELLOW= $GREEN$formatted")
diff --git a/src/test/java/io/github/moulberry/notenoughupdates/util/CalculatorTest.java b/src/test/java/io/github/moulberry/notenoughupdates/util/CalculatorTest.java
index 66ba5442..eff4a8de 100644
--- a/src/test/java/io/github/moulberry/notenoughupdates/util/CalculatorTest.java
+++ b/src/test/java/io/github/moulberry/notenoughupdates/util/CalculatorTest.java
@@ -21,21 +21,32 @@ package io.github.moulberry.notenoughupdates.util;
import java.math.BigDecimal;
import java.util.List;
+import java.util.Optional;
+import java.util.Scanner;
public class CalculatorTest {
public static void main(String[] args) throws Calculator.CalculatorException {
- List<Calculator.Token> lex = Calculator.lex("10k + 3 * 4m");
- List<Calculator.Token> shunted = Calculator.shuntingYard(lex);
- for (Calculator.Token rawToken : shunted) {
- System.out.printf(
- "%s(%s)",
- rawToken.type,
- rawToken.operatorValue == null ? rawToken.numericValue + " * 10 ^ " + rawToken.exponent : rawToken.operatorValue
- );
+ Scanner s = new Scanner(System.in);
+ while (true) {
+ try {
+ List<Calculator.Token> lex = Calculator.lex(s.nextLine());
+ List<Calculator.Token> shunted = Calculator.shuntingYard(lex);
+ for (Calculator.Token rawToken : shunted) {
+ System.out.printf(
+ "%s(%s)",
+ rawToken.type,
+ rawToken.operatorValue == null
+ ? rawToken.numericValue + " * 10 ^ " + rawToken.exponent
+ : rawToken.operatorValue
+ );
+ }
+ System.out.println();
+ BigDecimal evaluate = Calculator.evaluate(name -> Optional.of(BigDecimal.valueOf(16)), shunted);
+ System.out.println("Eval: " + evaluate);
+ } catch (Calculator.CalculatorException e) {
+ e.printStackTrace();
+ }
}
- System.out.println();
- BigDecimal evaluate = Calculator.evaluate(shunted);
- System.out.println("Eval: " + evaluate);
}
}