summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dice-lang/src/bjc/dicelang/v2/DiceBox.java585
-rw-r--r--dice-lang/src/bjc/dicelang/v2/DiceLangEngine.java1
-rw-r--r--dice-lang/src/bjc/dicelang/v2/Evaluator.java22
-rw-r--r--dice-lang/src/bjc/dicelang/v2/EvaluatorResult.java15
-rw-r--r--dice-lang/src/bjc/dicelang/v2/Token.java5
-rw-r--r--dice-lang/src/bjc/dicelang/v2/dice/CompoundDie.java31
-rw-r--r--dice-lang/src/bjc/dicelang/v2/dice/CompoundingDie.java63
-rw-r--r--dice-lang/src/bjc/dicelang/v2/dice/DiceBox.java142
-rw-r--r--dice-lang/src/bjc/dicelang/v2/dice/Die.java9
-rw-r--r--dice-lang/src/bjc/dicelang/v2/dice/DieExpression.java30
-rw-r--r--dice-lang/src/bjc/dicelang/v2/dice/DieList.java8
-rw-r--r--dice-lang/src/bjc/dicelang/v2/dice/ExplodingDice.java70
-rw-r--r--dice-lang/src/bjc/dicelang/v2/dice/FudgeDie.java37
-rw-r--r--dice-lang/src/bjc/dicelang/v2/dice/MathDie.java74
-rw-r--r--dice-lang/src/bjc/dicelang/v2/dice/ScalarDie.java29
-rw-r--r--dice-lang/src/bjc/dicelang/v2/dice/SimpleDie.java60
-rw-r--r--dice-lang/src/bjc/dicelang/v2/dice/SimpleDieList.java48
17 files changed, 627 insertions, 602 deletions
diff --git a/dice-lang/src/bjc/dicelang/v2/DiceBox.java b/dice-lang/src/bjc/dicelang/v2/DiceBox.java
deleted file mode 100644
index 361b766..0000000
--- a/dice-lang/src/bjc/dicelang/v2/DiceBox.java
+++ /dev/null
@@ -1,585 +0,0 @@
-package bjc.dicelang.v2;
-
-import java.util.Arrays;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Random;
-import java.util.function.Predicate;
-import java.util.regex.Pattern;
-
-public class DiceBox {
- private static final Random rng = new Random();
-
- public interface Die {
- boolean canOptimize();
- long optimize();
-
- long roll();
- long rollSingle();
- }
-
- public interface DieList {
- boolean canOptimize();
- long[] optimize();
-
- long[] roll();
- }
-
- public static class DieExpression {
- public final boolean isList;
-
- public Die scalar;
- public DieList list;
-
- public DieExpression(Die scal) {
- isList = false;
- scalar = scal;
- }
-
- public DieExpression(DieList lst) {
- isList = true;
- list = lst;
- }
-
- public String toString() {
- if(isList) return list.toString();
- else return scalar.toString();
- }
-
- public String value() {
- if(isList) return Arrays.toString(list.roll());
- else return Long.toString(scalar.roll());
- }
- }
-
- public static class ScalarDie implements Die {
- private long val;
-
- public ScalarDie(long vl) {
- val = vl;
- }
-
- public boolean canOptimize() {
- return true;
- }
-
- public long optimize() {
- return val;
- }
-
- public long roll() {
- return val;
- }
-
- public long rollSingle() {
- return val;
- }
-
- public String toString() {
- return Long.toString(val);
- }
- }
-
- public static class SimpleDie implements Die {
- private Die numDice;
- private Die diceSize;
-
- public SimpleDie(long nDice, long size) {
- numDice = new ScalarDie(nDice);
- diceSize = new ScalarDie(size);
- }
-
- public SimpleDie(Die nDice, long size) {
- numDice = nDice;
- diceSize = new ScalarDie(size);
- }
-
- public SimpleDie(long nDice, Die size) {
- numDice = new ScalarDie(nDice);
- diceSize = size;
- }
-
- public SimpleDie(Die nDice, Die size) {
- numDice = nDice;
- diceSize = size;
- }
-
- public boolean canOptimize() {
- if(diceSize.canOptimize() && (diceSize.optimize() <= 1)) {
- return numDice.canOptimize();
- } else return false;
- }
-
- public long optimize() {
- long optSize = diceSize.optimize();
-
- if(optSize == 0) return 0;
- else return numDice.optimize();
- }
-
- public long roll() {
- long total = 0;
-
- long nDice = numDice.roll();
- long dSize = diceSize.roll();
-
- for(int i = 0; i < nDice; i++) {
- total += (Math.abs(rng.nextLong()) % dSize) + 1;
- }
-
- return total;
- }
-
- public long rollSingle() {
- return (Math.abs(rng.nextLong()) % diceSize.roll()) + 1;
- }
-
- public String toString() {
- return numDice + "d" + diceSize;
- }
- }
-
- public static class FudgeDie implements Die {
- private Die numDice;
-
- public FudgeDie(long nDice) {
- numDice = new ScalarDie(nDice);
- }
-
- public boolean canOptimize() {
- return numDice.canOptimize() && numDice.optimize() == 0;
- }
-
- public long optimize() {
- return 0;
- }
-
- public long roll() {
- long res = 0;
-
- long nDice = numDice.roll();
-
- for(int i = 0; i < nDice; i++) {
- res += rollSingle();
- }
-
- return res;
- }
-
- public long rollSingle() {
- return rng.nextInt(3) - 1;
- }
-
- public String toString() {
- return numDice + "dF";
- }
- }
-
- public static class CompoundDie implements Die {
- private Die left;
- private Die right;
-
- public CompoundDie(Die lft, Die rght) {
- left = lft;
- right = rght;
- }
-
- public boolean canOptimize() {
- return left.canOptimize() && right.canOptimize();
- }
-
- public long optimize() {
- return Long.parseLong(left.optimize() + "" + right.optimize());
- }
-
- public long roll() {
- return Long.parseLong(left.roll() + "" + right.roll());
- }
-
- public long rollSingle() {
- return roll();
- }
-
- public String toString() {
- return left.toString() + "c" + right.toString();
- }
- }
-
- public static class CompoundingDie implements Die {
- private Die source;
-
- private Predicate<Long> compoundOn;
- private String compoundPattern;
-
- public CompoundingDie(Die src, Predicate<Long> compound) {
- this(src, compound, null);
- }
-
- public CompoundingDie(Die src, Predicate<Long> compound, String patt) {
- source = src;
-
- compoundOn = compound;
- compoundPattern = patt;
- }
-
- public boolean canOptimize() {
- return source.canOptimize() && source.optimize() == 0;
- }
-
- public long optimize() {
- return 0;
- }
-
- public long roll() {
- long res = source.roll();
- long oldRes = res;
-
- while(compoundOn.test(oldRes)) {
- oldRes = source.rollSingle();
-
- res += oldRes;
- }
-
- return res;
- }
-
- public long rollSingle() {
- long res = source.rollSingle();
- long oldRes = res;
-
- while(compoundOn.test(oldRes)) {
- oldRes = source.rollSingle();
-
- res += oldRes;
- }
-
- return res;
- }
-
- public String toString() {
- if(compoundPattern == null) {
- return source + "!!";
- } else {
- return source + "!!" + compoundPattern;
- }
- }
- }
-
- public static class MathDie implements Die {
- public static enum MathOp {
- ADD, SUBTRACT, MULTIPLY;
-
- public String toString() {
- switch(this) {
- case ADD:
- return "+";
- case SUBTRACT:
- return "-";
- case MULTIPLY:
- return "*";
- default:
- return this.name();
- }
- }
- }
-
- private MathOp type;
-
- private Die left;
- private Die right;
-
- public MathDie(MathOp op, Die lft, Die rght) {
- type = op;
-
- left = lft;
- right = rght;
- }
-
- public boolean canOptimize() {
- return left.canOptimize() && right.canOptimize();
- }
-
- private long performOp(long lft, long rght) {
- switch(type) {
- case ADD:
- return lft + rght;
- case SUBTRACT:
- return lft - rght;
- case MULTIPLY:
- return lft * rght;
- default:
- return 0;
- }
- }
-
- public long optimize() {
- long lft = left.optimize();
- long rght = right.optimize();
-
- return performOp(lft, rght);
- }
-
- public long roll() {
- long lft = left.roll();
- long rght = right.roll();
-
- return performOp(lft, rght);
- }
-
- public long rollSingle() {
- long lft = left.rollSingle();
- long rght = right.rollSingle();
-
- return performOp(lft, rght);
- }
-
- public String toString() {
- return left.toString() + " " + type.toString() + " " + right.toString();
- }
- }
-
- public static class SimpleDieList implements DieList {
- private Die numDice;
- private Die size;
-
- public SimpleDieList(Die nDice, Die sze) {
- numDice = nDice;
- size = sze;
- }
-
- public boolean canOptimize() {
- if(size.canOptimize() && size.optimize() <= 1) {
- return numDice.canOptimize();
- } else {
- return false;
- }
- }
-
- public long[] optimize() {
- int sze = (int)numDice.optimize();
- long res = size.optimize();
-
- long[] ret = new long[sze];
-
- for(int i = 0; i < sze; i++) {
- ret[i] = res;
- }
-
- return ret;
- }
-
- public long[] roll() {
- int num = (int)numDice.roll();
-
- long[] ret = new long[num];
-
- for(int i = 0; i < num; i++) {
- ret[i] = size.roll();
- }
-
- return ret;
- }
-
- public String toString() {
- return numDice.toString() + "dl" + size.toString();
- }
- }
-
- public static class ExplodingDice implements DieList {
- private Die source;
-
- private Predicate<Long> explodeOn;
- private String explodePattern;
- private boolean explodePenetrates;
-
- public ExplodingDice(Die src, Predicate<Long> explode) {
- this(src, explode, null, false);
- }
-
- public ExplodingDice(Die src, Predicate<Long> explode, boolean penetrate) {
- this(src, explode, null, penetrate);
- }
-
- public ExplodingDice(Die src, Predicate<Long> explode, String patt,
- boolean penetrate) {
- source = src;
- explodeOn = explode;
- explodePattern = patt;
- explodePenetrates = penetrate;
- }
-
- public boolean canOptimize() {
- return false;
- }
-
- public long[] optimize() {
- return new long[0];
- }
-
- public long[] roll() {
- long res = source.roll();
- long oldRes = res;
-
- List<Long> resList = new LinkedList<>();
-
- while(explodeOn.test(oldRes)) {
- oldRes = source.rollSingle();
-
- if(explodePenetrates) oldRes -= 1;
- resList.add(oldRes);
- }
-
- long[] newRes = new long[resList.size() + 1];
- newRes[0] = res;
-
- int i = 1;
- for(long rll : resList) {
- newRes[i] = rll;
- i += 1;
- }
-
- return newRes;
- }
-
- public String toString() {
- if(explodePattern == null) {
- return source + (explodePenetrates ? "p" : "") + "!";
- } else {
- return source + (explodePenetrates ? "p" : "") + "!" + explodePattern;
- }
- }
- }
-
- public static DieExpression parseExpression(String exp) {
- if(!isValidExpression(exp)) return null;
-
- if(scalarDiePattern.matcher(exp).matches()) {
- Die scal = new ScalarDie(Long.parseLong(exp.substring(0, exp.indexOf('s'))));
-
- return new DieExpression(scal);
- } else if(simpleDiePattern.matcher(exp).matches()) {
- String[] dieParts = exp.split("d");
-
- long right = Long.parseLong(dieParts[1]);
- if(dieParts[0].equals("")) {
- Die scal = new SimpleDie(1, right);
- return new DieExpression(scal);
- } else {
- Die scal = new SimpleDie(Long.parseLong(dieParts[0]), right);
- return new DieExpression(scal);
- }
- } else if(fudgeDiePattern.matcher(exp).matches()) {
- String nDice = exp.substring(0, exp.indexOf('d'));
-
- return new DieExpression(new FudgeDie(Long.parseLong(nDice)));
- } else if(compoundDiePattern.matcher(exp).matches()) {
- String[] dieParts = exp.split("c");
-
- DieExpression left = parseExpression(dieParts[0]);
- DieExpression right = parseExpression(dieParts[1]);
-
- return new DieExpression(new CompoundDie(left.scalar, right.scalar));
- } else if(compoundingDiePattern.matcher(exp).matches()) {
- String[] dieParts = exp.split("!!");
-
- DieExpression left = parseExpression(dieParts[0]);
- Predicate<Long> right = deriveCond(dieParts[1]);
-
- Die scal = new CompoundingDie(left.scalar, right, dieParts[1]);
- return new DieExpression(scal);
- } else if(explodingDiePattern.matcher(exp).matches()) {
- String[] dieParts = exp.split("!");
-
- DieExpression left = parseExpression(dieParts[0]);
- Predicate<Long> right = deriveCond(dieParts[1]);
-
- DieList lst = new ExplodingDice(left.scalar, right, dieParts[1], false);
- return new DieExpression(lst);
- } else if(penetratingDiePattern.matcher(exp).matches()) {
- String[] dieParts = exp.split("p!");
-
- DieExpression left = parseExpression(dieParts[0]);
- Predicate<Long> right = deriveCond(dieParts[1]);
-
- DieList lst = new ExplodingDice(left.scalar, right, dieParts[1], true);
- return new DieExpression(lst);
- } else if(diceListPattern.matcher(exp).matches()) {
- String[] dieParts = exp.split("dl");
-
- DieExpression left = parseExpression(dieParts[0]);
- DieExpression right = parseExpression(dieParts[1]);
-
- DieList lst = new SimpleDieList(left.scalar, right.scalar);
- return new DieExpression(lst);
- }
-
- // @TODO give a specific error message
- return null;
- }
-
- private static final String comparePoint = "[<>=]\\d+";
-
- private static final String scalarDie = "[\\+\\-]?\\d+sd";
- private static final Pattern scalarDiePattern = Pattern.compile("\\A" + scalarDie + "\\Z");
-
- private static final String simpleDie = "(?:\\d+)?d\\d+";
- private static final Pattern simpleDiePattern = Pattern.compile("\\A" + simpleDie + "\\Z");
-
- private static final String fudgeDie = "(?:\\d+)?dF";
- private static final Pattern fudgeDiePattern = Pattern.compile("\\A" + fudgeDie + "\\Z");
-
- private static final String compoundDie = simpleDie + "c(?:(?:" + simpleDie + ")|(?:\\d+))";
- private static final Pattern compoundDiePattern = Pattern.compile("\\A" + compoundDie + "\\Z");
-
- private static final String compoundGroup = "(?:(?:" + scalarDie + ")|(?:" + simpleDie + ")|(?:"
- + compoundDie + ")|(?:" + fudgeDie +"))";
-
- private static final String compoundingDie = compoundGroup + "!!" + comparePoint;
- private static final Pattern compoundingDiePattern = Pattern.compile("\\A" + compoundingDie + "\\Z");
-
- private static final String explodingDie = compoundGroup + "!" + comparePoint;
- private static final Pattern explodingDiePattern = Pattern.compile("\\A" + explodingDie + "\\Z");
-
- private static final String penetratingDie = compoundGroup + "!" + comparePoint;
- private static final Pattern penetratingDiePattern = Pattern.compile("\\A" + penetratingDie + "\\Z");
-
- private static final String diceList = compoundGroup + "dl" + compoundGroup;
- private static final Pattern diceListPattern = Pattern.compile("\\A" + diceList + "\\Z");
-
- public static boolean isValidExpression(String exp) {
- if(scalarDiePattern.matcher(exp).matches()) {
- return true;
- } else if(simpleDiePattern.matcher(exp).matches()) {
- return true;
- } else if(fudgeDiePattern.matcher(exp).matches()) {
- return true;
- } else if(compoundDiePattern.matcher(exp).matches()) {
- return true;
- } else if(compoundingDiePattern.matcher(exp).matches()) {
- return true;
- } else if(explodingDiePattern.matcher(exp).matches()) {
- return true;
- } else if(penetratingDiePattern.matcher(exp).matches()) {
- return true;
- } else if (diceListPattern.matcher(exp).matches()) {
- return true;
- } else {
- return false;
- }
- }
-
- private static Predicate<Long> deriveCond(String patt) {
- long num = Long.parseLong(patt.substring(1));
-
- switch(patt.charAt(0)) {
- case '<':
- return (roll) -> roll < num;
- case '=':
- return (roll) -> roll == num;
- case '>':
- return (roll) -> roll > num;
- default:
- return (roll) -> false;
- }
- }
-}
diff --git a/dice-lang/src/bjc/dicelang/v2/DiceLangEngine.java b/dice-lang/src/bjc/dicelang/v2/DiceLangEngine.java
index 8ff20ef..200c0b6 100644
--- a/dice-lang/src/bjc/dicelang/v2/DiceLangEngine.java
+++ b/dice-lang/src/bjc/dicelang/v2/DiceLangEngine.java
@@ -1,5 +1,6 @@
package bjc.dicelang.v2;
+import bjc.dicelang.v2.dice.DiceBox;
import bjc.utils.data.IPair;
import bjc.utils.data.ITree;
import bjc.utils.data.Pair;
diff --git a/dice-lang/src/bjc/dicelang/v2/Evaluator.java b/dice-lang/src/bjc/dicelang/v2/Evaluator.java
index 047e12f..ed9db17 100644
--- a/dice-lang/src/bjc/dicelang/v2/Evaluator.java
+++ b/dice-lang/src/bjc/dicelang/v2/Evaluator.java
@@ -1,5 +1,9 @@
package bjc.dicelang.v2;
+import bjc.dicelang.v2.dice.CompoundDie;
+import bjc.dicelang.v2.dice.MathDie;
+import bjc.dicelang.v2.dice.SimpleDie;
+import bjc.dicelang.v2.dice.SimpleDieList;
import bjc.utils.data.ITree;
import bjc.utils.data.SingleIterator;
import bjc.utils.data.Tree;
@@ -210,18 +214,18 @@ public class Evaluator {
if(left.type == DICE && !left.diceVal.isList) {
if(right.type == DICE && !right.diceVal.isList) {
res = new EvaluatorResult(DICE,
- new DiceBox.SimpleDie(left.diceVal.scalar, right.diceVal.scalar));
+ new SimpleDie(left.diceVal.scalar, right.diceVal.scalar));
} else if (right.type == INT) {
- res = new EvaluatorResult(DICE, new DiceBox.SimpleDie(left.diceVal.scalar, right.intVal));
+ res = new EvaluatorResult(DICE, new SimpleDie(left.diceVal.scalar, right.intVal));
} else {
Errors.inst.printError(EK_EVAL_INVDGROUP, right.type.toString());
return new Tree<>(FAIL(right));
}
} else if(left.type == INT) {
if(right.type == DICE && !right.diceVal.isList) {
- res = new EvaluatorResult(DICE, new DiceBox.SimpleDie(left.intVal, right.diceVal.scalar));
+ res = new EvaluatorResult(DICE, new SimpleDie(left.intVal, right.diceVal.scalar));
} else if (right.type == INT) {
- res = new EvaluatorResult(DICE, new DiceBox.SimpleDie(left.intVal, right.intVal));
+ res = new EvaluatorResult(DICE, new SimpleDie(left.intVal, right.intVal));
} else {
Errors.inst.printError(EK_EVAL_INVDGROUP, right.type.toString());
return new Tree<>(FAIL(right));
@@ -239,7 +243,7 @@ public class Evaluator {
return new Tree<>(FAIL(right));
} else {
res = new EvaluatorResult(DICE,
- new DiceBox.CompoundDie(left.diceVal.scalar, right.diceVal.scalar));
+ new CompoundDie(left.diceVal.scalar, right.diceVal.scalar));
}
break;
case DICELIST:
@@ -251,7 +255,7 @@ public class Evaluator {
return new Tree<>(FAIL(right));
} else {
res = new EvaluatorResult(DICE,
- new DiceBox.SimpleDieList(left.diceVal.scalar, right.diceVal.scalar));
+ new SimpleDieList(left.diceVal.scalar, right.diceVal.scalar));
}
break;
default:
@@ -304,7 +308,7 @@ public class Evaluator {
return new Tree<>(FAIL(right));
}
- res = new EvaluatorResult(DICE, new DiceBox.MathDie(DiceBox.MathDie.MathOp.ADD,
+ res = new EvaluatorResult(DICE, new MathDie(MathDie.MathOp.ADD,
left.diceVal.scalar, right.diceVal.scalar));
} else {
res = new EvaluatorResult(FLOAT, left.floatVal + right.floatVal);
@@ -322,7 +326,7 @@ public class Evaluator {
return new Tree<>(FAIL(right));
}
- res = new EvaluatorResult(DICE, new DiceBox.MathDie(DiceBox.MathDie.MathOp.SUBTRACT,
+ res = new EvaluatorResult(DICE, new MathDie(MathDie.MathOp.SUBTRACT,
left.diceVal.scalar, right.diceVal.scalar));
} else {
res = new EvaluatorResult(FLOAT, left.floatVal - right.floatVal);
@@ -340,7 +344,7 @@ public class Evaluator {
return new Tree<>(FAIL(right));
}
- res = new EvaluatorResult(DICE, new DiceBox.MathDie(DiceBox.MathDie.MathOp.MULTIPLY,
+ res = new EvaluatorResult(DICE, new MathDie(MathDie.MathOp.MULTIPLY,
left.diceVal.scalar, right.diceVal.scalar));
} else {
res = new EvaluatorResult(FLOAT, left.floatVal * right.floatVal);
diff --git a/dice-lang/src/bjc/dicelang/v2/EvaluatorResult.java b/dice-lang/src/bjc/dicelang/v2/EvaluatorResult.java
index 510d5e9..bac4d2d 100644
--- a/dice-lang/src/bjc/dicelang/v2/EvaluatorResult.java
+++ b/dice-lang/src/bjc/dicelang/v2/EvaluatorResult.java
@@ -1,5 +1,8 @@
package bjc.dicelang.v2;
+import bjc.dicelang.v2.dice.Die;
+import bjc.dicelang.v2.dice.DieExpression;
+import bjc.dicelang.v2.dice.DieList;
import bjc.utils.data.ITree;
import bjc.utils.data.Tree;
@@ -15,7 +18,7 @@ public class EvaluatorResult {
// off of the result type
public long intVal;
public double floatVal;
- public DiceBox.DieExpression diceVal;
+ public DieExpression diceVal;
public String stringVal;
// Original node data
@@ -51,22 +54,22 @@ public class EvaluatorResult {
floatVal = dVal;
}
- public EvaluatorResult(EvaluatorResult.Type typ, DiceBox.DieExpression dVal) {
+ public EvaluatorResult(EvaluatorResult.Type typ, DieExpression dVal) {
this(typ);
diceVal = dVal;
}
- public EvaluatorResult(EvaluatorResult.Type typ, DiceBox.Die dVal) {
+ public EvaluatorResult(EvaluatorResult.Type typ, Die dVal) {
this(typ);
- diceVal = new DiceBox.DieExpression(dVal);
+ diceVal = new DieExpression(dVal);
}
- public EvaluatorResult(EvaluatorResult.Type typ, DiceBox.DieList dVal) {
+ public EvaluatorResult(EvaluatorResult.Type typ, DieList dVal) {
this(typ);
- diceVal = new DiceBox.DieExpression(dVal);
+ diceVal = new DieExpression(dVal);
}
public EvaluatorResult(EvaluatorResult.Type typ, String strang) {
diff --git a/dice-lang/src/bjc/dicelang/v2/Token.java b/dice-lang/src/bjc/dicelang/v2/Token.java
index e5d3d9f..3d8359f 100644
--- a/dice-lang/src/bjc/dicelang/v2/Token.java
+++ b/dice-lang/src/bjc/dicelang/v2/Token.java
@@ -1,5 +1,6 @@
package bjc.dicelang.v2;
+import bjc.dicelang.v2.dice.DieExpression;
import bjc.utils.funcdata.IList;
/**
@@ -46,7 +47,7 @@ public class Token {
// This is used for the following token types
// DICE_LIT (dice value)
- public DiceBox.DieExpression diceValue;
+ public DieExpression diceValue;
// This is used for the following token types
// TOKGROUP (the tokens in the group)
@@ -69,7 +70,7 @@ public class Token {
floatValue = val;
}
- public Token(Type typ, DiceBox.DieExpression val) {
+ public Token(Type typ, DieExpression val) {
this(typ);
diceValue = val;
diff --git a/dice-lang/src/bjc/dicelang/v2/dice/CompoundDie.java b/dice-lang/src/bjc/dicelang/v2/dice/CompoundDie.java
new file mode 100644
index 0000000..a8186eb
--- /dev/null
+++ b/dice-lang/src/bjc/dicelang/v2/dice/CompoundDie.java
@@ -0,0 +1,31 @@
+package bjc.dicelang.v2.dice;
+
+public class CompoundDie implements Die {
+ private Die left;
+ private Die right;
+
+ public CompoundDie(Die lft, Die rght) {
+ left = lft;
+ right = rght;
+ }
+
+ public boolean canOptimize() {
+ return left.canOptimize() && right.canOptimize();
+ }
+
+ public long optimize() {
+ return Long.parseLong(left.optimize() + "" + right.optimize());
+ }
+
+ public long roll() {
+ return Long.parseLong(left.roll() + "" + right.roll());
+ }
+
+ public long rollSingle() {
+ return roll();
+ }
+
+ public String toString() {
+ return left.toString() + "c" + right.toString();
+ }
+} \ No newline at end of file
diff --git a/dice-lang/src/bjc/dicelang/v2/dice/CompoundingDie.java b/dice-lang/src/bjc/dicelang/v2/dice/CompoundingDie.java
new file mode 100644
index 0000000..d5991ae
--- /dev/null
+++ b/dice-lang/src/bjc/dicelang/v2/dice/CompoundingDie.java
@@ -0,0 +1,63 @@
+package bjc.dicelang.v2.dice;
+
+import java.util.function.Predicate;
+
+public class CompoundingDie implements Die {
+ private Die source;
+
+ private Predicate<Long> compoundOn;
+ private String compoundPattern;
+
+ public CompoundingDie(Die src, Predicate<Long> compound) {
+ this(src, compound, null);
+ }
+
+ public CompoundingDie(Die src, Predicate<Long> compound, String patt) {
+ source = src;
+
+ compoundOn = compound;
+ compoundPattern = patt;
+ }
+
+ public boolean canOptimize() {
+ return source.canOptimize() && source.optimize() == 0;
+ }
+
+ public long optimize() {
+ return 0;
+ }
+
+ public long roll() {
+ long res = source.roll();
+ long oldRes = res;
+
+ while(compoundOn.test(oldRes)) {
+ oldRes = source.rollSingle();
+
+ res += oldRes;
+ }
+
+ return res;
+ }
+
+ public long rollSingle() {
+ long res = source.rollSingle();
+ long oldRes = res;
+
+ while(compoundOn.test(oldRes)) {
+ oldRes = source.rollSingle();
+
+ res += oldRes;
+ }
+
+ return res;
+ }
+
+ public String toString() {
+ if(compoundPattern == null) {
+ return source + "!!";
+ } else {
+ return source + "!!" + compoundPattern;
+ }
+ }
+} \ No newline at end of file
diff --git a/dice-lang/src/bjc/dicelang/v2/dice/DiceBox.java b/dice-lang/src/bjc/dicelang/v2/dice/DiceBox.java
new file mode 100644
index 0000000..995c3bf
--- /dev/null
+++ b/dice-lang/src/bjc/dicelang/v2/dice/DiceBox.java
@@ -0,0 +1,142 @@
+package bjc.dicelang.v2.dice;
+
+import java.util.Random;
+import java.util.function.Predicate;
+import java.util.regex.Pattern;
+
+public class DiceBox {
+ static final Random rng = new Random();
+
+ public static DieExpression parseExpression(String exp) {
+ if(!isValidExpression(exp)) return null;
+
+ if(scalarDiePattern.matcher(exp).matches()) {
+ Die scal = new ScalarDie(Long.parseLong(exp.substring(0, exp.indexOf('s'))));
+
+ return new DieExpression(scal);
+ } else if(simpleDiePattern.matcher(exp).matches()) {
+ String[] dieParts = exp.split("d");
+
+ long right = Long.parseLong(dieParts[1]);
+ if(dieParts[0].equals("")) {
+ Die scal = new SimpleDie(1, right);
+ return new DieExpression(scal);
+ } else {
+ Die scal = new SimpleDie(Long.parseLong(dieParts[0]), right);
+ return new DieExpression(scal);
+ }
+ } else if(fudgeDiePattern.matcher(exp).matches()) {
+ String nDice = exp.substring(0, exp.indexOf('d'));
+
+ return new DieExpression(new FudgeDie(Long.parseLong(nDice)));
+ } else if(compoundDiePattern.matcher(exp).matches()) {
+ String[] dieParts = exp.split("c");
+
+ DieExpression left = parseExpression(dieParts[0]);
+ DieExpression right = parseExpression(dieParts[1]);
+
+ return new DieExpression(new CompoundDie(left.scalar, right.scalar));
+ } else if(compoundingDiePattern.matcher(exp).matches()) {
+ String[] dieParts = exp.split("!!");
+
+ DieExpression left = parseExpression(dieParts[0]);
+ Predicate<Long> right = deriveCond(dieParts[1]);
+
+ Die scal = new CompoundingDie(left.scalar, right, dieParts[1]);
+ return new DieExpression(scal);
+ } else if(explodingDiePattern.matcher(exp).matches()) {
+ String[] dieParts = exp.split("!");
+
+ DieExpression left = parseExpression(dieParts[0]);
+ Predicate<Long> right = deriveCond(dieParts[1]);
+
+ DieList lst = new ExplodingDice(left.scalar, right, dieParts[1], false);
+ return new DieExpression(lst);
+ } else if(penetratingDiePattern.matcher(exp).matches()) {
+ String[] dieParts = exp.split("p!");
+
+ DieExpression left = parseExpression(dieParts[0]);
+ Predicate<Long> right = deriveCond(dieParts[1]);
+
+ DieList lst = new ExplodingDice(left.scalar, right, dieParts[1], true);
+ return new DieExpression(lst);
+ } else if(diceListPattern.matcher(exp).matches()) {
+ String[] dieParts = exp.split("dl");
+
+ DieExpression left = parseExpression(dieParts[0]);
+ DieExpression right = parseExpression(dieParts[1]);
+
+ DieList lst = new SimpleDieList(left.scalar, right.scalar);
+ return new DieExpression(lst);
+ }
+
+ // @TODO give a specific error message
+ return null;
+ }
+
+ private static final String comparePoint = "[<>=]\\d+";
+
+ private static final String scalarDie = "[\\+\\-]?\\d+sd";
+ private static final Pattern scalarDiePattern = Pattern.compile("\\A" + scalarDie + "\\Z");
+
+ private static final String simpleDie = "(?:\\d+)?d\\d+";
+ private static final Pattern simpleDiePattern = Pattern.compile("\\A" + simpleDie + "\\Z");
+
+ private static final String fudgeDie = "(?:\\d+)?dF";
+ private static final Pattern fudgeDiePattern = Pattern.compile("\\A" + fudgeDie + "\\Z");
+
+ private static final String compoundDie = simpleDie + "c(?:(?:" + simpleDie + ")|(?:\\d+))";
+ private static final Pattern compoundDiePattern = Pattern.compile("\\A" + compoundDie + "\\Z");
+
+ private static final String compoundGroup = "(?:(?:" + scalarDie + ")|(?:" + simpleDie + ")|(?:"
+ + compoundDie + ")|(?:" + fudgeDie +"))";
+
+ private static final String compoundingDie = compoundGroup + "!!" + comparePoint;
+ private static final Pattern compoundingDiePattern = Pattern.compile("\\A" + compoundingDie + "\\Z");
+
+ private static final String explodingDie = compoundGroup + "!" + comparePoint;
+ private static final Pattern explodingDiePattern = Pattern.compile("\\A" + explodingDie + "\\Z");
+
+ private static final String penetratingDie = compoundGroup + "!" + comparePoint;
+ private static final Pattern penetratingDiePattern = Pattern.compile("\\A" + penetratingDie + "\\Z");
+
+ private static final String diceList = compoundGroup + "dl" + compoundGroup;
+ private static final Pattern diceListPattern = Pattern.compile("\\A" + diceList + "\\Z");
+
+ public static boolean isValidExpression(String exp) {
+ if(scalarDiePattern.matcher(exp).matches()) {
+ return true;
+ } else if(simpleDiePattern.matcher(exp).matches()) {
+ return true;
+ } else if(fudgeDiePattern.matcher(exp).matches()) {
+ return true;
+ } else if(compoundDiePattern.matcher(exp).matches()) {
+ return true;
+ } else if(compoundingDiePattern.matcher(exp).matches()) {
+ return true;
+ } else if(explodingDiePattern.matcher(exp).matches()) {
+ return true;
+ } else if(penetratingDiePattern.matcher(exp).matches()) {
+ return true;
+ } else if (diceListPattern.matcher(exp).matches()) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ private static Predicate<Long> deriveCond(String patt) {
+ long num = Long.parseLong(patt.substring(1));
+
+ switch(patt.charAt(0)) {
+ case '<':
+ return (roll) -> roll < num;
+ case '=':
+ return (roll) -> roll == num;
+ case '>':
+ return (roll) -> roll > num;
+ default:
+ return (roll) -> false;
+ }
+ }
+}
diff --git a/dice-lang/src/bjc/dicelang/v2/dice/Die.java b/dice-lang/src/bjc/dicelang/v2/dice/Die.java
new file mode 100644
index 0000000..808d7fd
--- /dev/null
+++ b/dice-lang/src/bjc/dicelang/v2/dice/Die.java
@@ -0,0 +1,9 @@
+package bjc.dicelang.v2.dice;
+
+public interface Die {
+ boolean canOptimize();
+ long optimize();
+
+ long roll();
+ long rollSingle();
+} \ No newline at end of file
diff --git a/dice-lang/src/bjc/dicelang/v2/dice/DieExpression.java b/dice-lang/src/bjc/dicelang/v2/dice/DieExpression.java
new file mode 100644
index 0000000..93fcbb9
--- /dev/null
+++ b/dice-lang/src/bjc/dicelang/v2/dice/DieExpression.java
@@ -0,0 +1,30 @@
+package bjc.dicelang.v2.dice;
+
+import java.util.Arrays;
+
+public class DieExpression {
+ public final boolean isList;
+
+ public Die scalar;
+ public DieList list;
+
+ public DieExpression(Die scal) {
+ isList = false;
+ scalar = scal;
+ }
+
+ public DieExpression(DieList lst) {
+ isList = true;
+ list = lst;
+ }
+
+ public String toString() {
+ if(isList) return list.toString();
+ else return scalar.toString();
+ }
+
+ public String value() {
+ if(isList) return Arrays.toString(list.roll());
+ else return Long.toString(scalar.roll());
+ }
+} \ No newline at end of file
diff --git a/dice-lang/src/bjc/dicelang/v2/dice/DieList.java b/dice-lang/src/bjc/dicelang/v2/dice/DieList.java
new file mode 100644
index 0000000..ab3c7b7
--- /dev/null
+++ b/dice-lang/src/bjc/dicelang/v2/dice/DieList.java
@@ -0,0 +1,8 @@
+package bjc.dicelang.v2.dice;
+
+public interface DieList {
+ boolean canOptimize();
+ long[] optimize();
+
+ long[] roll();
+} \ No newline at end of file
diff --git a/dice-lang/src/bjc/dicelang/v2/dice/ExplodingDice.java b/dice-lang/src/bjc/dicelang/v2/dice/ExplodingDice.java
new file mode 100644
index 0000000..40ff1e0
--- /dev/null
+++ b/dice-lang/src/bjc/dicelang/v2/dice/ExplodingDice.java
@@ -0,0 +1,70 @@
+package bjc.dicelang.v2.dice;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.function.Predicate;
+
+public class ExplodingDice implements DieList {
+ private Die source;
+
+ private Predicate<Long> explodeOn;
+ private String explodePattern;
+ private boolean explodePenetrates;
+
+ public ExplodingDice(Die src, Predicate<Long> explode) {
+ this(src, explode, null, false);
+ }
+
+ public ExplodingDice(Die src, Predicate<Long> explode, boolean penetrate) {
+ this(src, explode, null, penetrate);
+ }
+
+ public ExplodingDice(Die src, Predicate<Long> explode, String patt,
+ boolean penetrate) {
+ source = src;
+ explodeOn = explode;
+ explodePattern = patt;
+ explodePenetrates = penetrate;
+ }
+
+ public boolean canOptimize() {
+ return false;
+ }
+
+ public long[] optimize() {
+ return new long[0];
+ }
+
+ public long[] roll() {
+ long res = source.roll();
+ long oldRes = res;
+
+ List<Long> resList = new LinkedList<>();
+
+ while(explodeOn.test(oldRes)) {
+ oldRes = source.rollSingle();
+
+ if(explodePenetrates) oldRes -= 1;
+ resList.add(oldRes);
+ }
+
+ long[] newRes = new long[resList.size() + 1];
+ newRes[0] = res;
+
+ int i = 1;
+ for(long rll : resList) {
+ newRes[i] = rll;
+ i += 1;
+ }
+
+ return newRes;
+ }
+
+ public String toString() {
+ if(explodePattern == null) {
+ return source + (explodePenetrates ? "p" : "") + "!";
+ } else {
+ return source + (explodePenetrates ? "p" : "") + "!" + explodePattern;
+ }
+ }
+} \ No newline at end of file
diff --git a/dice-lang/src/bjc/dicelang/v2/dice/FudgeDie.java b/dice-lang/src/bjc/dicelang/v2/dice/FudgeDie.java
new file mode 100644
index 0000000..4c8c52a
--- /dev/null
+++ b/dice-lang/src/bjc/dicelang/v2/dice/FudgeDie.java
@@ -0,0 +1,37 @@
+package bjc.dicelang.v2.dice;
+
+public class FudgeDie implements Die {
+ private Die numDice;
+
+ public FudgeDie(long nDice) {
+ numDice = new ScalarDie(nDice);
+ }
+
+ public boolean canOptimize() {
+ return numDice.canOptimize() && numDice.optimize() == 0;
+ }
+
+ public long optimize() {
+ return 0;
+ }
+
+ public long roll() {
+ long res = 0;
+
+ long nDice = numDice.roll();
+
+ for(int i = 0; i < nDice; i++) {
+ res += rollSingle();
+ }
+
+ return res;
+ }
+
+ public long rollSingle() {
+ return DiceBox.rng.nextInt(3) - 1;
+ }
+
+ public String toString() {
+ return numDice + "dF";
+ }
+} \ No newline at end of file
diff --git a/dice-lang/src/bjc/dicelang/v2/dice/MathDie.java b/dice-lang/src/bjc/dicelang/v2/dice/MathDie.java
new file mode 100644
index 0000000..55e01f8
--- /dev/null
+++ b/dice-lang/src/bjc/dicelang/v2/dice/MathDie.java
@@ -0,0 +1,74 @@
+package bjc.dicelang.v2.dice;
+
+public class MathDie implements Die {
+ public static enum MathOp {
+ ADD, SUBTRACT, MULTIPLY;
+
+ public String toString() {
+ switch(this) {
+ case ADD:
+ return "+";
+ case SUBTRACT:
+ return "-";
+ case MULTIPLY:
+ return "*";
+ default:
+ return this.name();
+ }
+ }
+ }
+
+ private MathDie.MathOp type;
+
+ private Die left;
+ private Die right;
+
+ public MathDie(MathDie.MathOp op, Die lft, Die rght) {
+ type = op;
+
+ left = lft;
+ right = rght;
+ }
+
+ public boolean canOptimize() {
+ return left.canOptimize() && right.canOptimize();
+ }
+
+ private long performOp(long lft, long rght) {
+ switch(type) {
+ case ADD:
+ return lft + rght;
+ case SUBTRACT:
+ return lft - rght;
+ case MULTIPLY:
+ return lft * rght;
+ default:
+ return 0;
+ }
+ }
+
+ public long optimize() {
+ long lft = left.optimize();
+ long rght = right.optimize();
+
+ return performOp(lft, rght);
+ }
+
+ public long roll() {
+ long lft = left.roll();
+ long rght = right.roll();
+
+ return performOp(lft, rght);
+ }
+
+ public long rollSingle() {
+ long lft = left.rollSingle();
+ long rght = right.rollSingle();
+
+ return performOp(lft, rght);
+ }
+
+ public String toString() {
+ return left.toString() + " " + type.toString() + " " + right.toString();
+ }
+} \ No newline at end of file
diff --git a/dice-lang/src/bjc/dicelang/v2/dice/ScalarDie.java b/dice-lang/src/bjc/dicelang/v2/dice/ScalarDie.java
new file mode 100644
index 0000000..17714ee
--- /dev/null
+++ b/dice-lang/src/bjc/dicelang/v2/dice/ScalarDie.java
@@ -0,0 +1,29 @@
+package bjc.dicelang.v2.dice;
+
+public class ScalarDie implements Die {
+ private long val;
+
+ public ScalarDie(long vl) {
+ val = vl;
+ }
+
+ public boolean canOptimize() {
+ return true;
+ }
+
+ public long optimize() {
+ return val;
+ }
+
+ public long roll() {
+ return val;
+ }
+
+ public long rollSingle() {
+ return val;
+ }
+
+ public String toString() {
+ return Long.toString(val);
+ }
+} \ No newline at end of file
diff --git a/dice-lang/src/bjc/dicelang/v2/dice/SimpleDie.java b/dice-lang/src/bjc/dicelang/v2/dice/SimpleDie.java
new file mode 100644
index 0000000..f084822
--- /dev/null
+++ b/dice-lang/src/bjc/dicelang/v2/dice/SimpleDie.java
@@ -0,0 +1,60 @@
+package bjc.dicelang.v2.dice;
+
+public class SimpleDie implements Die {
+ private Die numDice;
+ private Die diceSize;
+
+ public SimpleDie(long nDice, long size) {
+ numDice = new ScalarDie(nDice);
+ diceSize = new ScalarDie(size);
+ }
+
+ public SimpleDie(Die nDice, long size) {
+ numDice = nDice;
+ diceSize = new ScalarDie(size);
+ }
+
+ public SimpleDie(long nDice, Die size) {
+ numDice = new ScalarDie(nDice);
+ diceSize = size;
+ }
+
+ public SimpleDie(Die nDice, Die size) {
+ numDice = nDice;
+ diceSize = size;
+ }
+
+ public boolean canOptimize() {
+ if(diceSize.canOptimize() && (diceSize.optimize() <= 1)) {
+ return numDice.canOptimize();
+ } else return false;
+ }
+
+ public long optimize() {
+ long optSize = diceSize.optimize();
+
+ if(optSize == 0) return 0;
+ else return numDice.optimize();
+ }
+
+ public long roll() {
+ long total = 0;
+
+ long nDice = numDice.roll();
+ long dSize = diceSize.roll();
+
+ for(int i = 0; i < nDice; i++) {
+ total += (Math.abs(DiceBox.rng.nextLong()) % dSize) + 1;
+ }
+
+ return total;
+ }
+
+ public long rollSingle() {
+ return (Math.abs(DiceBox.rng.nextLong()) % diceSize.roll()) + 1;
+ }
+
+ public String toString() {
+ return numDice + "d" + diceSize;
+ }
+} \ No newline at end of file
diff --git a/dice-lang/src/bjc/dicelang/v2/dice/SimpleDieList.java b/dice-lang/src/bjc/dicelang/v2/dice/SimpleDieList.java
new file mode 100644
index 0000000..e5aef18
--- /dev/null
+++ b/dice-lang/src/bjc/dicelang/v2/dice/SimpleDieList.java
@@ -0,0 +1,48 @@
+package bjc.dicelang.v2.dice;
+
+public class SimpleDieList implements DieList {
+ private Die numDice;
+ private Die size;
+
+ public SimpleDieList(Die nDice, Die sze) {
+ numDice = nDice;
+ size = sze;
+ }
+
+ public boolean canOptimize() {
+ if(size.canOptimize() && size.optimize() <= 1) {
+ return numDice.canOptimize();
+ } else {
+ return false;
+ }
+ }
+
+ public long[] optimize() {
+ int sze = (int)numDice.optimize();
+ long res = size.optimize();
+
+ long[] ret = new long[sze];
+
+ for(int i = 0; i < sze; i++) {
+ ret[i] = res;
+ }
+
+ return ret;
+ }
+
+ public long[] roll() {
+ int num = (int)numDice.roll();
+
+ long[] ret = new long[num];
+
+ for(int i = 0; i < num; i++) {
+ ret[i] = size.roll();
+ }
+
+ return ret;
+ }
+
+ public String toString() {
+ return numDice.toString() + "dl" + size.toString();
+ }
+} \ No newline at end of file