summaryrefslogtreecommitdiff
path: root/BJC-Utils2/src/main/java/bjc
diff options
context:
space:
mode:
Diffstat (limited to 'BJC-Utils2/src/main/java/bjc')
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/dice/ast/DiceASTFlattener.java83
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/dice/ast/DiceASTParser.java78
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/dice/ast/IDiceASTNode.java5
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/dice/ast/LiteralDiceNode.java23
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/dice/ast/OperatorDiceNode.java31
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/dice/ast/VariableDiceNode.java23
6 files changed, 243 insertions, 0 deletions
diff --git a/BJC-Utils2/src/main/java/bjc/utils/dice/ast/DiceASTFlattener.java b/BJC-Utils2/src/main/java/bjc/utils/dice/ast/DiceASTFlattener.java
new file mode 100644
index 0000000..3cf1d4e
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/dice/ast/DiceASTFlattener.java
@@ -0,0 +1,83 @@
+package bjc.utils.dice.ast;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.BinaryOperator;
+
+import org.apache.commons.lang3.StringUtils;
+
+import bjc.utils.dice.BindingDiceExpression;
+import bjc.utils.dice.ComplexDice;
+import bjc.utils.dice.CompoundDice;
+import bjc.utils.dice.CompoundDiceExpression;
+import bjc.utils.dice.DiceExpressionType;
+import bjc.utils.dice.IDiceExpression;
+import bjc.utils.dice.ReferenceDiceExpression;
+import bjc.utils.dice.ScalarDie;
+import bjc.utils.parserutils.AST;
+
+public class DiceASTFlattener {
+ public static IDiceExpression flatten(AST<IDiceASTNode> ast,
+ Map<String, IDiceExpression> env) {
+ Map<IDiceASTNode, BinaryOperator<IDiceExpression>> opCollapsers = buildOperations(
+ env);
+
+ return ast.collapse((nod) -> {
+ if (nod instanceof LiteralDiceNode) {
+ return expFromLiteral((LiteralDiceNode) nod);
+ } else {
+ return new ReferenceDiceExpression(
+ ((VariableDiceNode) nod).getVariable(), env);
+ }
+ } , opCollapsers, (r) -> r);
+ }
+
+ private static Map<IDiceASTNode, BinaryOperator<IDiceExpression>> buildOperations(
+ Map<String, IDiceExpression> env) {
+ Map<IDiceASTNode, BinaryOperator<IDiceExpression>> opCollapsers = new HashMap<>();
+ opCollapsers.put(OperatorDiceNode.ADD, (left, right) -> {
+ return new CompoundDiceExpression(right, left,
+ DiceExpressionType.ADD);
+ });
+ opCollapsers.put(OperatorDiceNode.SUBTRACT, (left, right) -> {
+ return new CompoundDiceExpression(right, left,
+ DiceExpressionType.SUBTRACT);
+ });
+ opCollapsers.put(OperatorDiceNode.MULTIPLY, (left, right) -> {
+ return new CompoundDiceExpression(right, left,
+ DiceExpressionType.MULTIPLY);
+ });
+ opCollapsers.put(OperatorDiceNode.DIVIDE, (left, right) -> {
+ return new CompoundDiceExpression(right, left,
+ DiceExpressionType.DIVIDE);
+ });
+ opCollapsers.put(OperatorDiceNode.ASSIGN, (left, right) -> {
+ return new BindingDiceExpression(left, right, env);
+ });
+ opCollapsers.put(OperatorDiceNode.COMPOUND, (left, right) -> {
+ return new CompoundDice(left, right);
+ });
+ opCollapsers.put(OperatorDiceNode.GROUP, (left, right) -> {
+ return new ComplexDice(left, right);
+ });
+
+ return opCollapsers;
+ }
+
+ private static IDiceExpression expFromLiteral(LiteralDiceNode tok) {
+ String data = tok.getData();
+
+ if (StringUtils.countMatches(data, 'c') == 1
+ && !data.equalsIgnoreCase("c")) {
+ String[] strangs = data.split("c");
+
+ return new CompoundDice(ComplexDice.fromString(strangs[0]),
+ ComplexDice.fromString(strangs[1]));
+ } else if (StringUtils.countMatches(data, 'd') == 1
+ && !data.equalsIgnoreCase("d")) {
+ return ComplexDice.fromString(data);
+ } else {
+ return new ScalarDie(Integer.parseInt(data));
+ }
+ }
+}
diff --git a/BJC-Utils2/src/main/java/bjc/utils/dice/ast/DiceASTParser.java b/BJC-Utils2/src/main/java/bjc/utils/dice/ast/DiceASTParser.java
new file mode 100644
index 0000000..d56ad0e
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/dice/ast/DiceASTParser.java
@@ -0,0 +1,78 @@
+package bjc.utils.dice.ast;
+
+import org.apache.commons.lang3.StringUtils;
+
+import bjc.utils.funcdata.FunctionalList;
+import bjc.utils.funcdata.FunctionalStringTokenizer;
+import bjc.utils.parserutils.AST;
+import bjc.utils.parserutils.ShuntingYard;
+import bjc.utils.parserutils.TreeConstructor;
+
+public class DiceASTParser {
+ private static ShuntingYard<String> yard;
+
+ static {
+ yard = new ShuntingYard<>();
+
+ yard.addOp("d", 5); // dice operator: use for creating variable
+ // size dice groups
+ yard.addOp("c", 6); // compound operator: use for creating compound
+ // dice from expressions
+ yard.addOp(":=", 0); // binding operator: Bind a name to a variable
+ // expression
+ }
+
+ public AST<IDiceASTNode> buildAST(String exp) {
+ FunctionalList<String> tokens = FunctionalStringTokenizer
+ .fromString(exp).toList((s) -> s);
+
+ FunctionalList<String> shunted = yard.postfix(tokens, (s) -> s);
+
+ AST<String> rawAST = TreeConstructor.constructTree(shunted,
+ this::isOperator);
+
+ AST<IDiceASTNode> bakedAST = rawAST.transmuteAST((tok) -> {
+ if (isOperator(tok)) {
+ return OperatorDiceNode.fromString(tok);
+ } else if (isLiteral(tok)) {
+ return new LiteralDiceNode(tok);
+ } else {
+ return new VariableDiceNode(tok);
+ }
+ });
+
+ return bakedAST;
+ }
+
+ private boolean isOperator(String tok) {
+ switch (tok) {
+ case ":=":
+ case "+":
+ case "-":
+ case "*":
+ case "/":
+ case "c":
+ case "d":
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ private boolean isLiteral(String tok) {
+ if (StringUtils.countMatches(tok, 'c') == 1
+ && !tok.equalsIgnoreCase("c")) {
+ return true;
+ } else if (StringUtils.countMatches(tok, 'd') == 1
+ && !tok.equalsIgnoreCase("d")) {
+ return true;
+ } else {
+ try {
+ Integer.parseInt(tok);
+ return true;
+ } catch (NumberFormatException nfx) {
+ return false;
+ }
+ }
+ }
+}
diff --git a/BJC-Utils2/src/main/java/bjc/utils/dice/ast/IDiceASTNode.java b/BJC-Utils2/src/main/java/bjc/utils/dice/ast/IDiceASTNode.java
new file mode 100644
index 0000000..3fb14fe
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/dice/ast/IDiceASTNode.java
@@ -0,0 +1,5 @@
+package bjc.utils.dice.ast;
+
+public interface IDiceASTNode {
+ public boolean isOperator();
+}
diff --git a/BJC-Utils2/src/main/java/bjc/utils/dice/ast/LiteralDiceNode.java b/BJC-Utils2/src/main/java/bjc/utils/dice/ast/LiteralDiceNode.java
new file mode 100644
index 0000000..5bfbc85
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/dice/ast/LiteralDiceNode.java
@@ -0,0 +1,23 @@
+package bjc.utils.dice.ast;
+
+public class LiteralDiceNode implements IDiceASTNode {
+ private String data;
+
+ public LiteralDiceNode(String data) {
+ this.data = data;
+ }
+
+ @Override
+ public boolean isOperator() {
+ return false;
+ }
+
+ /**
+ * Get the data stored in this AST node
+ *
+ * @return the data stored in this AST node
+ */
+ public String getData() {
+ return data;
+ }
+}
diff --git a/BJC-Utils2/src/main/java/bjc/utils/dice/ast/OperatorDiceNode.java b/BJC-Utils2/src/main/java/bjc/utils/dice/ast/OperatorDiceNode.java
new file mode 100644
index 0000000..84f45aa
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/dice/ast/OperatorDiceNode.java
@@ -0,0 +1,31 @@
+package bjc.utils.dice.ast;
+
+public enum OperatorDiceNode implements IDiceASTNode {
+ ASSIGN, ADD, SUBTRACT, MULTIPLY, DIVIDE, GROUP, COMPOUND;
+
+ @Override
+ public boolean isOperator() {
+ return true;
+ }
+
+ public static OperatorDiceNode fromString(String s) {
+ switch(s) {
+ case ":=":
+ return ASSIGN;
+ case "+":
+ return ADD;
+ case "-":
+ return SUBTRACT;
+ case "*":
+ return MULTIPLY;
+ case "/":
+ return DIVIDE;
+ case "d":
+ return GROUP;
+ case "c":
+ return COMPOUND;
+ default:
+ throw new IllegalArgumentException(s + " is not a valid operator node");
+ }
+ }
+}
diff --git a/BJC-Utils2/src/main/java/bjc/utils/dice/ast/VariableDiceNode.java b/BJC-Utils2/src/main/java/bjc/utils/dice/ast/VariableDiceNode.java
new file mode 100644
index 0000000..1d3a63c
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/dice/ast/VariableDiceNode.java
@@ -0,0 +1,23 @@
+package bjc.utils.dice.ast;
+
+public class VariableDiceNode implements IDiceASTNode {
+ private String var;
+
+ public VariableDiceNode(String data) {
+ this.var = data;
+ }
+
+ @Override
+ public boolean isOperator() {
+ return false;
+ }
+
+ /**
+ * Get the variable referenced by this AST node
+ *
+ * @return the variable referenced by this AST node
+ */
+ public String getVariable() {
+ return var;
+ }
+}