summaryrefslogtreecommitdiff
path: root/dice-lang/src
diff options
context:
space:
mode:
authorbculkin2442 <bjculkin@mix.wvu.edu>2017-03-06 14:15:03 -0500
committerbculkin2442 <bjculkin@mix.wvu.edu>2017-03-06 14:15:03 -0500
commit9139064c95f6c9c4f7ba1d0aea21e2f5233ad188 (patch)
treedd93017bff73e61fec20c58b7baa43d1662c0c5b /dice-lang/src
parentb11f8d2c92aaaf1160e69190559ffadc4774f138 (diff)
Formatting/Documentation
Diffstat (limited to 'dice-lang/src')
-rw-r--r--dice-lang/src/bjc/dicelang/Define.java13
-rw-r--r--dice-lang/src/bjc/dicelang/DiceLangEngine.java293
-rw-r--r--dice-lang/src/bjc/dicelang/Errors.java254
-rw-r--r--dice-lang/src/bjc/dicelang/StreamEngine.java134
-rw-r--r--dice-lang/src/bjc/dicelang/dice/CompoundDie.java24
-rw-r--r--dice-lang/src/bjc/dicelang/dice/CompoundingDie.java31
-rw-r--r--dice-lang/src/bjc/dicelang/dice/DiceBox.java107
-rw-r--r--dice-lang/src/bjc/dicelang/dice/Die.java30
-rw-r--r--dice-lang/src/bjc/dicelang/dice/DieExpression.java30
-rw-r--r--dice-lang/src/bjc/dicelang/dice/DieList.java24
-rw-r--r--dice-lang/src/bjc/dicelang/dice/ExplodingDice.java43
11 files changed, 733 insertions, 250 deletions
diff --git a/dice-lang/src/bjc/dicelang/Define.java b/dice-lang/src/bjc/dicelang/Define.java
index 2967af6..a70ca61 100644
--- a/dice-lang/src/bjc/dicelang/Define.java
+++ b/dice-lang/src/bjc/dicelang/Define.java
@@ -34,6 +34,11 @@ public class Define implements UnaryOperator<String> {
doRecur = recur;
subType = isSub;
+ inError = false;
+
+ /*
+ * Only try to compile non-null predicates
+ */
if(predicte != null) {
try {
predicate = Pattern.compile(predicte);
@@ -44,6 +49,9 @@ public class Define implements UnaryOperator<String> {
}
}
+ /*
+ * Compile the search pattern
+ */
try {
searcher = Pattern.compile(searchr);
} catch (PatternSyntaxException psex) {
@@ -52,8 +60,9 @@ public class Define implements UnaryOperator<String> {
return;
}
- inError = false;
-
+ /*
+ * Check whether or not we do sub-replacements
+ */
if(subType) {
if(replacrs.iterator().hasNext()) {
replacers = new CircularIterator<>(replacrs, isCircular);
diff --git a/dice-lang/src/bjc/dicelang/DiceLangEngine.java b/dice-lang/src/bjc/dicelang/DiceLangEngine.java
index 195c98a..dfe956e 100644
--- a/dice-lang/src/bjc/dicelang/DiceLangEngine.java
+++ b/dice-lang/src/bjc/dicelang/DiceLangEngine.java
@@ -21,57 +21,97 @@ import java.util.LinkedList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+/**
+ * Implements the orchestration necessary for processing DiceLang commands
+ *
+ * @author Ben Culkin
+ */
public class DiceLangEngine {
- // Input rules for processing tokens
+ /*
+ * Input rules for processing tokens.
+ */
private List<IPair<String, String>> opExpansionList;
- private List<IPair<String, String>> deaffixationList;
- // ID for generation
+ /*
+ * ID for generation.
+ */
private int nextLiteral;
- // Debug indicator
+ /*
+ * Debug indicator.
+ */
private boolean debugMode;
- // Should we do shunting?
+ /*
+ * Should we do shunting?
+ */
private boolean postfixMode;
- // Should we reverse the token stream
+ /*
+ * Should we reverse the token stream?
+ */
private boolean prefixMode;
- // Should we do step-by-step evaluation
+ /*
+ * Should we do step-by-step evaluation?
+ */
private boolean stepEval;
- // Shunter for token postfixing
+ /*
+ * Shunter for token postfixing.
+ */
private Shunter shunt;
- // Tokenizer for tokenizing
+ /*
+ * Tokenizer for tokenizing.
+ */
private Tokenizer tokenzer;
- // Parser for tree construction
+ /*
+ * Parser for tree construction.
+ */
private Parser parsr;
- // Evaluator for evaluating
+ /*
+ * Evaluator for evaluating.
+ */
private Evaluator eval;
- // Tables for symbols
+ /*
+ * Tables for symbols.
+ */
public final IMap<Integer, String> symTable;
public final IMap<Integer, String> stringLits;
- // Lists for preprocessing
+ /*
+ * Lists for preprocessing.
+ */
private IList<Define> lineDefns;
private IList<Define> tokenDefns;
- // Are defns sorted by priority
+ /*
+ * Are defns sorted by priority?
+ */
private boolean defnsSorted;
- // Stream engine for processing streams
+ /*
+ * Stream engine for processing streams.
+ */
private StreamEngine streamEng;
public DiceLangEngine() {
+ /*
+ * Initialize defns.
+ */
lineDefns = new FunctionalList<>();
tokenDefns = new FunctionalList<>();
defnsSorted = true;
+ /*
+ * Init tables.
+ */
symTable = new FunctionalMap<>();
stringLits = new FunctionalMap<>();
+ /*
+ * Initialize operator expansion list.
+ */
opExpansionList = new LinkedList<>();
-
opExpansionList.add(new Pair<>("+", "\\+"));
opExpansionList.add(new Pair<>("-", "-"));
opExpansionList.add(new Pair<>("*", "\\*"));
@@ -80,30 +120,36 @@ public class DiceLangEngine {
opExpansionList.add(new Pair<>(":=", ":="));
opExpansionList.add(new Pair<>("=>", "=>"));
opExpansionList.add(new Pair<>(",", ","));
-
- deaffixationList = new LinkedList<>();
-
- deaffixationList.add(new Pair<>("(", "\\("));
- deaffixationList.add(new Pair<>(")", "\\)"));
- deaffixationList.add(new Pair<>("[", "\\["));
- deaffixationList.add(new Pair<>("]", "\\]"));
- deaffixationList.add(new Pair<>("{", "\\{"));
- deaffixationList.add(new Pair<>("}", "}"));
+ opExpansionList.add(new Pair<>("(", "\\("));
+ opExpansionList.add(new Pair<>(")", "\\)"));
+ opExpansionList.add(new Pair<>("[", "\\["));
+ opExpansionList.add(new Pair<>("]", "\\]"));
+ opExpansionList.add(new Pair<>("{", "\\{"));
+ opExpansionList.add(new Pair<>("}", "}"));
nextLiteral = 1;
+ /*
+ * Initial mode settings.
+ */
debugMode = true;
postfixMode = false;
prefixMode = false;
stepEval = false;
+ /*
+ * Create components.
+ */
streamEng = new StreamEngine(this);
- shunt = new Shunter();
- tokenzer = new Tokenizer(this);
- parsr = new Parser();
- eval = new Evaluator(this);
+ shunt = new Shunter();
+ tokenzer = new Tokenizer(this);
+ parsr = new Parser();
+ eval = new Evaluator(this);
}
+ /**
+ * Sort defns by priority.
+ */
public void sortDefns() {
Comparator<Define> defnCmp = (dfn1, dfn2) -> dfn1.priority - dfn2.priority;
@@ -113,36 +159,66 @@ public class DiceLangEngine {
defnsSorted = true;
}
+ /**
+ * Add a defn that's applied to lines.
+ *
+ * @param dfn The defn to add.
+ */
public void addLineDefine(Define dfn) {
lineDefns.add(dfn);
defnsSorted = false;
}
+ /**
+ * Add a defn that's applied to tokens.
+ *
+ * @param dfn The defn to add.
+ */
public void addTokenDefine(Define dfn) {
tokenDefns.add(dfn);
defnsSorted = false;
}
+ /**
+ * Toggle debug mode.
+ *
+ * @return The current state of debug mode.
+ */
public boolean toggleDebug() {
debugMode = !debugMode;
return debugMode;
}
+ /**
+ * Toggle postfix mode.
+ *
+ * @return The current state of postfix mode.
+ */
public boolean togglePostfix() {
postfixMode = !postfixMode;
return postfixMode;
}
+ /**
+ * Toggle prefix mode.
+ *
+ * @return The current state of prefix mode
+ */
public boolean togglePrefix() {
prefixMode = !prefixMode;
return prefixMode;
}
+ /**
+ * Toggle step-eval mode
+ *
+ * @return The current state of step-eval mode
+ */
public boolean toggleStepEval() {
stepEval = !stepEval;
@@ -163,34 +239,49 @@ public class DiceLangEngine {
*/
private Pattern quotePattern = Pattern.compile("\"([^\\\"]*(?:\\\"(?:[^\\\"])*)*)\"");
- // Similiar to the above, but using angle brackets instead of quotes
+ /*
+ * Similiar to the above, but using angle brackets instead of quotes
+ */
private Pattern nonExpandPattern = Pattern.compile("<<([^\\>]*(?:\\>(?:[^\\>])*)*)>>");
+ /**
+ * Run a command to completion.
+ *
+ * @param command The command to run
+ *
+ * @return Whether or not the command ran succesfully
+ */
public boolean runCommand(String command) {
- // Sort the defines if they aren't sorted
+ /*
+ * Sort the defines if they aren't sorted
+ */
if(!defnsSorted) sortDefns();
+ /*
+ * Run the tokens through the stream engine
+ */
IList<String> streamToks = new FunctionalList<>();
boolean success = streamEng.doStreams(command.split(" "), streamToks);
if(!success) return false;
+ /*
+ * Apply line defns
+ */
String newComm = ListUtils.collapseTokens(streamToks, " ");
-
if(debugMode)
System.out.println("\tCommand after stream commands: " + newComm);
-
for(Define dfn : lineDefns.toIterable()) {
newComm = dfn.apply(newComm);
}
-
if(debugMode)
System.out.println("\tCommand after line defines: " + newComm);
+ /*
+ * Destring command
+ */
IMap<String, String> stringLiterals = new FunctionalMap<>();
-
Matcher quoteMatcher = quotePattern.matcher(newComm);
StringBuffer destringedCommand = new StringBuffer();
-
while(quoteMatcher.find()) {
String stringLit = quoteMatcher.group(1);
@@ -199,13 +290,7 @@ public class DiceLangEngine {
quoteMatcher.appendReplacement(destringedCommand, " " + litName + " ");
}
-
quoteMatcher.appendTail(destringedCommand);
-
- // Split the command into tokens
- IList<String> tokens = FunctionalStringTokenizer
- .fromString(destringedCommand.toString()).toList();
-
if(debugMode) {
System.out.println("\tCommand after destringing: " + destringedCommand);
@@ -218,11 +303,19 @@ public class DiceLangEngine {
}
}
+ /*
+ * Split the command into tokens
+ */
+ IList<String> tokens = FunctionalStringTokenizer
+ .fromString(destringedCommand.toString()).toList();
+
+
+ /*
+ * Temporarily remove non-expanding tokens
+ */
IMap<String, String> nonExpandedTokens = new FunctionalMap<>();
-
tokens = tokens.map(tk -> {
Matcher nonExpandMatcher = nonExpandPattern.matcher(tk);
-
if(nonExpandMatcher.matches()) {
String tkName = "nonExpandToken" + nextLiteral++;
nonExpandedTokens.put(tkName, nonExpandMatcher.group(1));
@@ -232,14 +325,18 @@ public class DiceLangEngine {
return tk;
}
});
+ if(debugMode)
+ System.out.printf("\tCommand after removal of non-expanders: %s\n", tokens.toString());
- System.out.println("\tCommand after removal of non-expanders: " + tokens.toString());
-
- IList<String> semiExpandedTokens = deaffixTokens(tokens, deaffixationList);
- IList<String> fullyExpandedTokens = deaffixTokens(semiExpandedTokens, opExpansionList);
-
+ /*
+ * Expand tokens
+ */
+ IList<String> fullyExpandedTokens = deaffixTokens(tokens, opExpansionList);
System.out.println("\tCommand after token expansion: " + fullyExpandedTokens.toString());
+ /*
+ * Reinsert non-expanded tokens
+ */
fullyExpandedTokens = fullyExpandedTokens.map(tk -> {
if(tk.startsWith("nonExpandToken")) {
return nonExpandedTokens.get(tk);
@@ -247,46 +344,61 @@ public class DiceLangEngine {
return tk;
}
});
-
if(debugMode)
- System.out.printf("\tCommand after non-expander reinsertion: "
- + fullyExpandedTokens.toString() + "\n");
+ System.out.printf("\tCommand after non-expander reinsertion: %s\n",
+ fullyExpandedTokens.toString());
IList<Token> lexedTokens = new FunctionalList<>();
-
for(String token : fullyExpandedTokens) {
String newTok = token;
+ /*
+ * Apply token defns
+ */
for(Define dfn : tokenDefns.toIterable()) {
newTok = dfn.apply(newTok);
}
+ /*
+ * Lex the token
+ */
Token tk = tokenzer.lexToken(token, stringLiterals);
+ /*
+ * Ignore blank tokens
+ */
if(tk == null) continue;
+ /*
+ * Fail on bad tokens
+ */
else if(tk == Token.NIL_TOKEN) return false;
else lexedTokens.add(tk);
}
-
if(debugMode)
System.out.printf("\tCommand after tokenization: %s\n", lexedTokens.toString());
+ /*
+ * Handle preshunted tokens
+ */
IList<Token> shuntedTokens = lexedTokens;
-
IList<Token> preparedTokens = new FunctionalList<>();
- boolean sc = removePreshuntTokens(lexedTokens, preparedTokens);
-
+ succ = removePreshuntTokens(lexedTokens, preparedTokens);
if(!sc) return false;
-
if(debugMode && !postfixMode)
System.out.printf("\tCommand after pre-shunter removal: %s\n", preparedTokens.toString());
if(!postfixMode && !prefixMode) {
+ /*
+ * Shunt the tokens
+ */
shuntedTokens = new FunctionalList<>();
success = shunt.shuntTokens(preparedTokens, shuntedTokens);
if(!success) return false;
} else if(prefixMode) {
+ /*
+ * Reverse directional tokens
+ */
preparedTokens.reverse();
shuntedTokens = preparedTokens.map(tk -> {
switch(tk.type) {
@@ -307,10 +419,12 @@ public class DiceLangEngine {
}
});
}
-
if(debugMode && !postfixMode)
System.out.printf("\tCommand after shunting: %s\n", shuntedTokens.toString());
+ /*
+ * Expand token groups
+ */
IList<Token> readyTokens = shuntedTokens.flatMap(tk -> {
if(tk.type == Token.Type.TOKGROUP) {
return tk.tokenValues;
@@ -320,37 +434,47 @@ public class DiceLangEngine {
return new FunctionalList<>(tk);
}
});
-
if(debugMode && !postfixMode)
System.out.printf("\tCommand after re-preshunting: %s\n", readyTokens.toString());
+ /*
+ * Parse the tokens
+ */
IList<ITree<Node>> astForest = new FunctionalList<>();
success = parsr.parseTokens(readyTokens, astForest);
-
if(!success) return false;
- if(debugMode) {
- evaluateForest(astForest);
- }
+ /*
+ * Evaluate the tokens
+ */
+ evaluateForest(astForest);
return true;
}
private void evaluateForest(IList<ITree<Node>> astForest) {
- System.out.println("\tParsed forest of asts");
+ if(debugMode)
+ System.out.println("\tParsed forest of asts");
int treeNo = 1;
for(ITree<Node> ast : astForest) {
- System.out.println("\t\tTree " + treeNo + " in forest:\n" + ast);
+ if(debugMode)
+ System.out.println("\t\tTree " + treeNo + " in forest:\n" + ast);
- if(stepEval) {
+ if(debugMode && stepEval) {
int step = 1;
+ /*
+ * Evaluate it step by step
+ */
for(Iterator<ITree<Node>> itr = eval.stepDebug(ast); itr.hasNext();){
ITree<Node> nodeStep = itr.next();
System.out.printf("\t\tStep %d: Node is %s", step, nodeStep);
+ /*
+ * Don't evaluate null steps
+ */
if(nodeStep == null) {
System.out.println();
@@ -358,6 +482,9 @@ public class DiceLangEngine {
continue;
}
+ /*
+ * Print out details for results
+ */
if(nodeStep.getHead().type == Node.Type.RESULT) {
EvaluatorResult res = nodeStep.getHead().resultVal;
@@ -374,16 +501,24 @@ public class DiceLangEngine {
System.out.printf(")");
}
-
+ /*
+ * Advance a step
+ */
System.out.println();
step += 1;
}
} else {
+ /*
+ * Evaluate it normally
+ */
EvaluatorResult res = eval.evaluate(ast);
- System.out.printf("\t\tEvaluates to %s", res);
- if(res.type == EvaluatorResult.Type.DICE) {
- System.out.println("\t\t (sample roll " + res.diceVal.value() + ")");
+ if(debugMode) {
+ System.out.printf("\t\tEvaluates to %s", res);
+
+ if(res.type == EvaluatorResult.Type.DICE) {
+ System.out.println("\t\t (sample roll " + res.diceVal.value() + ")");
+ }
}
}
@@ -470,12 +605,16 @@ public class DiceLangEngine {
for(String tk : working) {
if(opRegexOnly.matcher(tk).matches()) {
- // The string contains only the operator
+ /*
+ * The string contains only the operator
+ */
newWorking.add(tk);
} else {
Matcher medianMatcher = opRegexPattern.matcher(tk);
- // Read the first match
+ /*
+ * Read the first match
+ */
boolean found = medianMatcher.find();
if(!found) {
@@ -496,7 +635,9 @@ public class DiceLangEngine {
String[] pieces = opRegexPattern.split(tk);
if(startsWith) {
- // Skip the starting operator
+ /*
+ * Skip the starting operator
+ */
medianMatcher.find();
newWorking.add(tk.substring(0, startMatcher.end()));
}
@@ -504,7 +645,9 @@ public class DiceLangEngine {
for(int i = 0; i < pieces.length; i++) {
String piece = pieces[i];
- // Find the next operator
+ /*
+ * Find the next operator
+ */
boolean didFind = medianMatcher.find();
if(piece.equals("")) {
diff --git a/dice-lang/src/bjc/dicelang/Errors.java b/dice-lang/src/bjc/dicelang/Errors.java
index e6a825c..729ecc2 100644
--- a/dice-lang/src/bjc/dicelang/Errors.java
+++ b/dice-lang/src/bjc/dicelang/Errors.java
@@ -21,7 +21,7 @@ public class Errors {
EK_ENG_NOOPENING,
// Reached end of command w/out balanced doublebraces
EK_ENG_NOCLOSING,
-
+
// Tokenizer Errors
// Found an unexpected grouping token
EK_TOK_UNGROUP,
@@ -29,7 +29,7 @@ public class Errors {
EK_TOK_INVBASE,
// Invalid flexadecimal number in a given base
EK_TOK_INVFLEX,
-
+
// Evaluator Errors
// Unknown node type
EK_EVAL_INVNODE,
@@ -102,136 +102,136 @@ public class Errors {
public void printError(ErrorKey key, String... args) {
switch(mode) {
- case WIZARD:
- System.out.println("\t? " + key.ordinal());
- break;
- case DEV:
- devError(key, args);
- break;
- default:
- System.out.println("\tERROR ERROR: Unknown error mode " + mode);
+ case WIZARD:
+ System.out.println("\t? " + key.ordinal());
+ break;
+ case DEV:
+ devError(key, args);
+ break;
+ default:
+ System.out.println("\tERROR ERROR: Unknown error mode " + mode);
}
}
private void devError(ErrorKey key, String[] args) {
switch(key) {
- case EK_DFN_PREDSYN:
- System.out.printf("\tERROR: Incorrect define guard syntax %s\n", args[0]);
- break;
- case EK_DFN_SRCSYN:
- System.out.printf("\tERROR: Incorrect define match syntax %s\n", args[0]);
- break;
- case EK_DFN_RECUR:
- System.out.printf("\tERROR: Recursive define didn't converge after %s iterations."
- + " Original string was %s, last iteration was %s\n",
- args[0], args[1], args[2]);
- break;
- case EK_CONS_INVPRAG:
- System.out.printf("\tERROR: Unknown pragma %s\n", args[0]);
- break;
- case EK_CONS_INVDEFINE:
- System.out.printf("\tERROR: Improperly formatted define %s\n", args[0]);
- break;
- case EK_ENG_NOOPENING:
- System.out.printf("\tERROR: Encountered closing doublebrace without"
- + " matching opening doublebrace\n");
- break;
- case EK_ENG_NOCLOSING:
- System.out.printf("\tERROR: Reached end of string before closing doublebrace was found\n");
- break;
- case EK_TOK_UNGROUP:
- System.out.printf("\tERROR: Unrecognized grouping token %s\n", args[0]);
- break;
- case EK_TOK_INVBASE:
- System.out.printf("\tERROR: Invalid flexadecimal base %s\n", args[0]);
- break;
- case EK_TOK_INVFLEX:
- System.out.printf("\tERROR: Invalid flexadecimal number %s in base %s\n", args[0], args[1]);
- break;
- case EK_EVAL_INVNODE:
- System.out.printf("\tERROR: Unknown node in evaluator: %s\n", args[0]);
- break;
- case EK_EVAL_INVBIN:
- System.out.printf("\tERROR: Binary operators take 2 operand, not %s\n"
- + "\tProblem node is %s\n", args[0], args[1]);
- break;
- case EK_EVAL_UNBIN:
- System.out.printf("\tERROR: Unknown binary operator %s\n", args[0]);
- break;
- case EK_EVAL_STRINGMATH:
- System.out.printf("\tERROR: Math operators don't work on strings\n");
- break;
- case EK_EVAL_DIVZERO:
- System.out.printf("\tERROR: Attempted divide by zero\n");
- break;
- case EK_EVAL_DIVDICE:
- System.out.printf("\tERROR: Dice cannot be divided\n");
- break;
- case EK_EVAL_UNMATH:
- System.out.printf("\tERROR: Unknown math binary operator: %s\n", args[0]);
- break;
- case EK_EVAL_UNTOK:
- System.out.printf("\tERROR: Unknown token ref %s\n", args[0]);
- break;
- case EK_EVAL_UNDICE:
- System.out.printf("\tERROR: Unknown dice operator %s\n", args[0]);
- break;
- case EK_EVAL_INVDGROUP:
- System.out.printf("\tERROR: Dice group operator expects scalar dice or integers,"
- + " not %s\n", args[0]);
- break;
- case EK_EVAL_INVDICE:
- System.out.printf("\tERROR: Dice operators expect scalar dice, not %s\n", args[0]);
- break;
- case EK_EVAL_MISMATH:
- System.out.printf("\tERROR: Math operators expect two operands of the same type\n");
- break;
- case EK_PARSE_NOCLOSE:
- System.out.printf("\tERROR: Group closing with no possible group opener\n");
- break;
- case EK_PARSE_UNCLOSE:
- System.out.printf("\tERROR: Found group closer without opener: (closing was %s"
- + ", expected %s)\n", args[0], args[1]);
- break;
- case EK_PARSE_BINARY:
- System.out.printf("\tERROR: Expected at least two operands\n");
- break;
- case EK_PARSE_UNOPERAND:
- System.out.printf("\tERROR: Operator %s expected more operands than provided\n", args[0]);
- break;
- case EK_PARSE_INVTOKEN:
- System.out.printf("\tERROR: Unrecognized token type in parsing: %s\n", args[0]);
- break;
- case EK_SHUNT_NOTADV:
- System.out.printf("\tERROR: Unary operator %s is an adjective, not an adverb. It can't be"
- + " applied to the operator %s\n", args[0], args[1]);
- break;
- case EK_SHUNT_NOTADJ:
- System.out.printf("\tERROR: Unary operator %s is an adjective, not an adverb. It can't be"
- + " applied to the operator %s\n", args[0], args[1]);
- break;
- case EK_SHUNT_NOOP:
- System.out.printf("\tERROR: Unary operator %s is an adverb, but there is no operator"
- + " to apply it to\n", args[0]);
- break;
- case EK_SHUNT_NOGROUP:
- System.out.printf("\tERROR: Couldn't find matching grouping %s (expected %s)\n",
- args[0], args[1]);
- break;
- case EK_SHUNT_INVSEP:
- System.out.printf("\tERROR: Couldn't find grouper for group seperator to attach to\n");
- break;
- case EK_STRM_NONEX:
- System.out.printf("\tERROR: Attempted to switch to non-existent stream\n");
- break;
- case EK_STRM_LAST:
- System.out.printf("\tERROR: Cannot delete last stream\n");
- break;
- case EK_STRM_INVCOM:
- System.out.printf("\tERROR: Unknown stream control command %s\n", args[0]);
- break;
- default:
- System.out.printf("\tERROR ERROR: Unknown error key %s\n", key);
+ case EK_DFN_PREDSYN:
+ System.out.printf("\tERROR: Incorrect define guard syntax %s\n", args[0]);
+ break;
+ case EK_DFN_SRCSYN:
+ System.out.printf("\tERROR: Incorrect define match syntax %s\n", args[0]);
+ break;
+ case EK_DFN_RECUR:
+ System.out.printf("\tERROR: Recursive define didn't converge after %s iterations."
+ + " Original string was %s, last iteration was %s\n",
+ args[0], args[1], args[2]);
+ break;
+ case EK_CONS_INVPRAG:
+ System.out.printf("\tERROR: Unknown pragma %s\n", args[0]);
+ break;
+ case EK_CONS_INVDEFINE:
+ System.out.printf("\tERROR: Improperly formatted define %s\n", args[0]);
+ break;
+ case EK_ENG_NOOPENING:
+ System.out.printf("\tERROR: Encountered closing doublebrace without"
+ + " matching opening doublebrace\n");
+ break;
+ case EK_ENG_NOCLOSING:
+ System.out.printf("\tERROR: Reached end of string before closing doublebrace was found\n");
+ break;
+ case EK_TOK_UNGROUP:
+ System.out.printf("\tERROR: Unrecognized grouping token %s\n", args[0]);
+ break;
+ case EK_TOK_INVBASE:
+ System.out.printf("\tERROR: Invalid flexadecimal base %s\n", args[0]);
+ break;
+ case EK_TOK_INVFLEX:
+ System.out.printf("\tERROR: Invalid flexadecimal number %s in base %s\n", args[0], args[1]);
+ break;
+ case EK_EVAL_INVNODE:
+ System.out.printf("\tERROR: Unknown node in evaluator: %s\n", args[0]);
+ break;
+ case EK_EVAL_INVBIN:
+ System.out.printf("\tERROR: Binary operators take 2 operand, not %s\n"
+ + "\tProblem node is %s\n", args[0], args[1]);
+ break;
+ case EK_EVAL_UNBIN:
+ System.out.printf("\tERROR: Unknown binary operator %s\n", args[0]);
+ break;
+ case EK_EVAL_STRINGMATH:
+ System.out.printf("\tERROR: Math operators don't work on strings\n");
+ break;
+ case EK_EVAL_DIVZERO:
+ System.out.printf("\tERROR: Attempted divide by zero\n");
+ break;
+ case EK_EVAL_DIVDICE:
+ System.out.printf("\tERROR: Dice cannot be divided\n");
+ break;
+ case EK_EVAL_UNMATH:
+ System.out.printf("\tERROR: Unknown math binary operator: %s\n", args[0]);
+ break;
+ case EK_EVAL_UNTOK:
+ System.out.printf("\tERROR: Unknown token ref %s\n", args[0]);
+ break;
+ case EK_EVAL_UNDICE:
+ System.out.printf("\tERROR: Unknown dice operator %s\n", args[0]);
+ break;
+ case EK_EVAL_INVDGROUP:
+ System.out.printf("\tERROR: Dice group operator expects scalar dice or integers,"
+ + " not %s\n", args[0]);
+ break;
+ case EK_EVAL_INVDICE:
+ System.out.printf("\tERROR: Dice operators expect scalar dice, not %s\n", args[0]);
+ break;
+ case EK_EVAL_MISMATH:
+ System.out.printf("\tERROR: Math operators expect two operands of the same type\n");
+ break;
+ case EK_PARSE_NOCLOSE:
+ System.out.printf("\tERROR: Group closing with no possible group opener\n");
+ break;
+ case EK_PARSE_UNCLOSE:
+ System.out.printf("\tERROR: Found group closer without opener: (closing was %s"
+ + ", expected %s)\n", args[0], args[1]);
+ break;
+ case EK_PARSE_BINARY:
+ System.out.printf("\tERROR: Expected at least two operands\n");
+ break;
+ case EK_PARSE_UNOPERAND:
+ System.out.printf("\tERROR: Operator %s expected more operands than provided\n", args[0]);
+ break;
+ case EK_PARSE_INVTOKEN:
+ System.out.printf("\tERROR: Unrecognized token type in parsing: %s\n", args[0]);
+ break;
+ case EK_SHUNT_NOTADV:
+ System.out.printf("\tERROR: Unary operator %s is an adjective, not an adverb. It can't be"
+ + " applied to the operator %s\n", args[0], args[1]);
+ break;
+ case EK_SHUNT_NOTADJ:
+ System.out.printf("\tERROR: Unary operator %s is an adjective, not an adverb. It can't be"
+ + " applied to the operator %s\n", args[0], args[1]);
+ break;
+ case EK_SHUNT_NOOP:
+ System.out.printf("\tERROR: Unary operator %s is an adverb, but there is no operator"
+ + " to apply it to\n", args[0]);
+ break;
+ case EK_SHUNT_NOGROUP:
+ System.out.printf("\tERROR: Couldn't find matching grouping %s (expected %s)\n",
+ args[0], args[1]);
+ break;
+ case EK_SHUNT_INVSEP:
+ System.out.printf("\tERROR: Couldn't find grouper for group seperator to attach to\n");
+ break;
+ case EK_STRM_NONEX:
+ System.out.printf("\tERROR: Attempted to switch to non-existent stream\n");
+ break;
+ case EK_STRM_LAST:
+ System.out.printf("\tERROR: Cannot delete last stream\n");
+ break;
+ case EK_STRM_INVCOM:
+ System.out.printf("\tERROR: Unknown stream control command %s\n", args[0]);
+ break;
+ default:
+ System.out.printf("\tERROR ERROR: Unknown error key %s\n", key);
}
}
diff --git a/dice-lang/src/bjc/dicelang/StreamEngine.java b/dice-lang/src/bjc/dicelang/StreamEngine.java
index 2971392..5debe00 100644
--- a/dice-lang/src/bjc/dicelang/StreamEngine.java
+++ b/dice-lang/src/bjc/dicelang/StreamEngine.java
@@ -8,37 +8,93 @@ import static bjc.dicelang.Errors.ErrorKey.*;
import bjc.utils.esodata.SingleTape;
import bjc.utils.esodata.Tape;
-
+import bjc.utils.esodata.TapeLibrary;
+
+/**
+ * Implements multiple interleaved parse streams, as well as a command language
+ * for the streams.
+ *
+ * The idea for the interleaved streams came from the language Oozylbub &amp;
+ * Murphy, but the command language was my own idea.
+ *
+ * @author Ben Culkin
+ */
public class StreamEngine {
+ /*
+ * The engine we're attached to.
+ */
private DiceLangEngine eng;
+ /*
+ * Our streams.
+ */
private Tape<IList<String>> streams;
private IList<String> currStream;
+ /*
+ * Saved streams
+ */
+ private TapeLibrary<IList<String>> savedStreams;
+
+ /**
+ * Create a new stream engine.
+ *
+ * @param engine The dice engine we're attached to.
+ */
public StreamEngine(DiceLangEngine engine) {
eng = engine;
+
+ savedStreams = new TapeLibrary<>();
}
private void init() {
+ /*
+ * Reinitialize our list of streams.
+ */
streams = new SingleTape<>();
+ /*
+ * Create an initial stream.
+ */
currStream = new FunctionalList<>();
streams.insertBefore(currStream);
}
+ /**
+ * Process a possibly interleaved set of streams from toks into dest.
+ *
+ * @param toks The raw token to read streams from.
+ * @param dest The list to write the final stream to.
+ *
+ * @return Whether or not the streams were successfully processed.
+ */
public boolean doStreams(String[] toks, IList<String> dest) {
+ /*
+ * Initialize per-run state.
+ */
init();
+ /*
+ * Are we currently quoting things?
+ */
boolean quoteMode = false;
+ /*
+ * Process each token.
+ */
for(String tk : toks) {
+ /*
+ * Process stream commands.
+ */
if(tk.startsWith("{@S") && !quoteMode) {
if(tk.equals("{@SQ}")) {
quoteMode = true;
} else if(!processCommand(tk)) {
return false;
}
- // Command ran correctly, continue
+ /*
+ * Command ran correctly, continue
+ */
} else {
if(tk.equals("{@SU}")) {
quoteMode = false;
@@ -69,47 +125,47 @@ public class StreamEngine {
for(char comm : comms) {
switch(comm) {
- case '+':
- streams.insertAfter(new FunctionalList<>());
- break;
- case '>':
- if(!streams.right()) {
- Errors.inst.printError(EK_STRM_NONEX);
- return false;
- }
+ case '+':
+ streams.insertAfter(new FunctionalList<>());
+ break;
+ case '>':
+ if(!streams.right()) {
+ Errors.inst.printError(EK_STRM_NONEX);
+ return false;
+ }
- currStream = streams.item();
- break;
- case '<':
- if(!streams.left()) {
- Errors.inst.printError(EK_STRM_NONEX);
- return false;
- }
+ currStream = streams.item();
+ break;
+ case '<':
+ if(!streams.left()) {
+ Errors.inst.printError(EK_STRM_NONEX);
+ return false;
+ }
+ currStream = streams.item();
+ break;
+ case '-':
+ if(streams.size() == 1) {
+ Errors.inst.printError(EK_STRM_LAST);
+ return false;
+ } else {
+ streams.remove();
currStream = streams.item();
- break;
- case '-':
- if(streams.size() == 1) {
- Errors.inst.printError(EK_STRM_LAST);
- return false;
- } else {
- streams.remove();
- currStream = streams.item();
- }
- break;
- case 'S':
- if(streams.size() == 1) {
- Errors.inst.printError(EK_STRM_LAST);
- return false;
- } else {
- IList<String> stringLit = streams.remove();
- currStream = streams.item();
- currStream.add(ListUtils.collapseTokens(stringLit, " "));
- }
- break;
- default:
- Errors.inst.printError(EK_STRM_INVCOM, tk);
+ }
+ break;
+ case 'S':
+ if(streams.size() == 1) {
+ Errors.inst.printError(EK_STRM_LAST);
return false;
+ } else {
+ IList<String> stringLit = streams.remove();
+ currStream = streams.item();
+ currStream.add(ListUtils.collapseTokens(stringLit, " "));
+ }
+ break;
+ default:
+ Errors.inst.printError(EK_STRM_INVCOM, tk);
+ return false;
}
}
diff --git a/dice-lang/src/bjc/dicelang/dice/CompoundDie.java b/dice-lang/src/bjc/dicelang/dice/CompoundDie.java
index 16aec76..a20095a 100644
--- a/dice-lang/src/bjc/dicelang/dice/CompoundDie.java
+++ b/dice-lang/src/bjc/dicelang/dice/CompoundDie.java
@@ -1,31 +1,53 @@
package bjc.dicelang.dice;
+/**
+ * A die whose rolls result from concatenating two other rolls together.
+ *
+ * @author Ben Culkin
+ */
public class CompoundDie implements Die {
+ /*
+ * The dice that form this die
+ */
private Die left;
private Die right;
+ /**
+ * Create a new compound die.
+ *
+ * @param lft The left die
+ * @param rght The right die
+ */
public CompoundDie(Die lft, Die rght) {
left = lft;
right = rght;
}
+ @Override
public boolean canOptimize() {
return left.canOptimize() && right.canOptimize();
}
+ @Override
public long optimize() {
return Long.parseLong(left.optimize() + "" + right.optimize());
}
+ @Override
public long roll() {
return Long.parseLong(left.roll() + "" + right.roll());
}
+ @Override
public long rollSingle() {
+ /*
+ * We're only one die, we can't be split
+ */
return roll();
}
+ @Override
public String toString() {
return left.toString() + "c" + right.toString();
}
-} \ No newline at end of file
+}
diff --git a/dice-lang/src/bjc/dicelang/dice/CompoundingDie.java b/dice-lang/src/bjc/dicelang/dice/CompoundingDie.java
index 9744650..3291b52 100644
--- a/dice-lang/src/bjc/dicelang/dice/CompoundingDie.java
+++ b/dice-lang/src/bjc/dicelang/dice/CompoundingDie.java
@@ -2,16 +2,37 @@ package bjc.dicelang.dice;
import java.util.function.Predicate;
+/**
+ * Implements a compounding die.
+ *
+ * This means that the source will be rolled, and then more single rolls will be
+ * added while it meets a qualification.
+ *
+ * @author Ben Culkin
+ */
public class CompoundingDie implements Die {
private Die source;
private Predicate<Long> compoundOn;
private String compoundPattern;
+ /**
+ * Create a new compounding die with no pattern.
+ *
+ * @param src The die to compound from
+ * @param compound The conditions to compound on
+ */
public CompoundingDie(Die src, Predicate<Long> compound) {
this(src, compound, null);
}
+ /**
+ * Create a new compounding die with a specified pattern.
+ *
+ * @param src The die to compound from
+ * @param compound The conditions to compound on
+ * @param patt The string pattern the condition came from, for printing
+ */
public CompoundingDie(Die src, Predicate<Long> compound, String patt) {
source = src;
@@ -19,14 +40,17 @@ public class CompoundingDie implements Die {
compoundPattern = patt;
}
+ @Override
public boolean canOptimize() {
return source.canOptimize() && source.optimize() == 0;
}
+ @Override
public long optimize() {
return 0;
}
+ @Override
public long roll() {
long res = source.roll();
long oldRes = res;
@@ -40,7 +64,11 @@ public class CompoundingDie implements Die {
return res;
}
+ @Override
public long rollSingle() {
+ /*
+ * Just compound on a single roll
+ */
long res = source.rollSingle();
long oldRes = res;
@@ -53,6 +81,7 @@ public class CompoundingDie implements Die {
return res;
}
+ @Override
public String toString() {
if(compoundPattern == null) {
return source + "!!";
@@ -60,4 +89,4 @@ public class CompoundingDie implements Die {
return source + "!!" + compoundPattern;
}
}
-} \ No newline at end of file
+}
diff --git a/dice-lang/src/bjc/dicelang/dice/DiceBox.java b/dice-lang/src/bjc/dicelang/dice/DiceBox.java
index 4c0641a..92e58af 100644
--- a/dice-lang/src/bjc/dicelang/dice/DiceBox.java
+++ b/dice-lang/src/bjc/dicelang/dice/DiceBox.java
@@ -4,21 +4,43 @@ import java.util.Random;
import java.util.function.Predicate;
import java.util.regex.Pattern;
+/**
+ * Contains static methods for producing dice from strings.
+ *
+ * @author Ben Culkin
+ */
public class DiceBox {
static final Random rng = new Random();
+ /**
+ * Parse a die expression from a string.
+ *
+ * @return The die expression from the string, or null if it wasn't one
+ */
public static DieExpression parseExpression(String exp) {
+ /*
+ * Only bother will valid expressions
+ */
if(!isValidExpression(exp)) return null;
if(scalarDiePattern.matcher(exp).matches()) {
+ /*
+ * Parse scalar die
+ */
Die scal = new ScalarDie(Long.parseLong(exp.substring(0, exp.indexOf('s'))));
return new DieExpression(scal);
} else if(simpleDiePattern.matcher(exp).matches()) {
+ /*
+ * Parse simple die groups
+ */
String[] dieParts = exp.split("d");
long right = Long.parseLong(dieParts[1]);
if(dieParts[0].equals("")) {
+ /*
+ * Handle short-form expressions.
+ */
Die scal = new SimpleDie(1, right);
return new DieExpression(scal);
} else {
@@ -26,10 +48,16 @@ public class DiceBox {
return new DieExpression(scal);
}
} else if(fudgeDiePattern.matcher(exp).matches()) {
+ /*
+ * Parse fudge dice
+ */
String nDice = exp.substring(0, exp.indexOf('d'));
return new DieExpression(new FudgeDie(Long.parseLong(nDice)));
} else if(compoundDiePattern.matcher(exp).matches()) {
+ /*
+ * Parse compound die expressions
+ */
String[] dieParts = exp.split("c");
DieExpression left = parseExpression(dieParts[0]);
@@ -37,6 +65,9 @@ public class DiceBox {
return new DieExpression(new CompoundDie(left.scalar, right.scalar));
} else if(compoundingDiePattern.matcher(exp).matches()) {
+ /*
+ * Parse compounding die expressions
+ */
String[] dieParts = exp.split("!!");
DieExpression left = parseExpression(dieParts[0]);
@@ -45,6 +76,9 @@ public class DiceBox {
Die scal = new CompoundingDie(left.scalar, right, dieParts[1]);
return new DieExpression(scal);
} else if(explodingDiePattern.matcher(exp).matches()) {
+ /*
+ * Parse exploding die expressions
+ */
String[] dieParts = exp.split("!");
DieExpression left = parseExpression(dieParts[0]);
@@ -53,6 +87,9 @@ public class DiceBox {
DieList lst = new ExplodingDice(left.scalar, right, dieParts[1], false);
return new DieExpression(lst);
} else if(penetratingDiePattern.matcher(exp).matches()) {
+ /*
+ * Parse penetrating die expressions
+ */
String[] dieParts = exp.split("p!");
DieExpression left = parseExpression(dieParts[0]);
@@ -61,6 +98,9 @@ public class DiceBox {
DieList lst = new ExplodingDice(left.scalar, right, dieParts[1], true);
return new DieExpression(lst);
} else if(diceListPattern.matcher(exp).matches()) {
+ /*
+ * Parse simple die lists
+ */
String[] dieParts = exp.split("dl");
DieExpression left = parseExpression(dieParts[0]);
@@ -70,39 +110,101 @@ public class DiceBox {
return new DieExpression(lst);
}
- // @TODO give a specific error message
return null;
}
+ /*
+ * The strings and patterns used for matching
+ */
+
+ /*
+ * Defines a comparison predicate
+ */
private static final String comparePoint = "[<>=]\\d+";
+ /*
+ * Defines a scalar die.
+ *
+ * This is just a number.
+ */
private static final String scalarDie = "[\\+\\-]?\\d+sd";
private static final Pattern scalarDiePattern = Pattern.compile("\\A" + scalarDie + "\\Z");
+ /*
+ * Defines a simple die.
+ *
+ * This is a group of one or more dice of the same size.
+ */
private static final String simpleDie = "(?:\\d+)?d\\d+";
private static final Pattern simpleDiePattern = Pattern.compile("\\A" + simpleDie + "\\Z");
+ /*
+ * Defines a fudge die.
+ *
+ * This is like a simple die, but all the die give -1, 0, or 1 as
+ * results.
+ */
private static final String fudgeDie = "(?:\\d+)?dF";
private static final Pattern fudgeDiePattern = Pattern.compile("\\A" + fudgeDie + "\\Z");
+ /*
+ * Defines a compound die.
+ *
+ * This is like using two d10's to simulate a d100
+ */
private static final String compoundDie = simpleDie + "c(?:(?:" + simpleDie + ")|(?:\\d+))";
private static final Pattern compoundDiePattern = Pattern.compile("\\A" + compoundDie + "\\Z");
+ /*
+ * Defines a compound group.
+ *
+ * This is used for forming die list type expressions.
+ */
private static final String compoundGroup = "(?:(?:" + scalarDie + ")|(?:" + simpleDie + ")|(?:"
+ compoundDie + ")|(?:" + fudgeDie +"))";
+ /*
+ * Defines a compounding die.
+ *
+ * This is like an exploding die, but is a single die, not a group of
+ * them.
+ */
private static final String compoundingDie = compoundGroup + "!!" + comparePoint;
private static final Pattern compoundingDiePattern = Pattern.compile("\\A" + compoundingDie + "\\Z");
+ /*
+ * Defines an exploding die.
+ *
+ * This is a die that you reroll the component of if it meets a certain
+ * condition.
+ */
private static final String explodingDie = compoundGroup + "!" + comparePoint;
private static final Pattern explodingDiePattern = Pattern.compile("\\A" + explodingDie + "\\Z");
+ /*
+ * Defines a penetrating die.
+ *
+ * This is like an exploding die, but the exploded result gets a -1
+ * penalty.
+ */
private static final String penetratingDie = compoundGroup + "!" + comparePoint;
private static final Pattern penetratingDiePattern = Pattern.compile("\\A" + penetratingDie + "\\Z");
+ /*
+ * Defines a die list.
+ *
+ * This is an array of dice of the specified size
+ */
private static final String diceList = compoundGroup + "dl" + compoundGroup;
private static final Pattern diceListPattern = Pattern.compile("\\A" + diceList + "\\Z");
+ /**
+ * Check if a given string is a valid die expression.
+ *
+ * @param exp The string to check validity of.
+ *
+ * @return Whether or not the string is a valid command
+ */
public static boolean isValidExpression(String exp) {
if(scalarDiePattern.matcher(exp).matches()) {
return true;
@@ -125,6 +227,9 @@ public class DiceBox {
}
}
+ /*
+ * Derive a predicate from a compare point
+ */
private static Predicate<Long> deriveCond(String patt) {
long num = Long.parseLong(patt.substring(1));
diff --git a/dice-lang/src/bjc/dicelang/dice/Die.java b/dice-lang/src/bjc/dicelang/dice/Die.java
index 9f839ed..22ba522 100644
--- a/dice-lang/src/bjc/dicelang/dice/Die.java
+++ b/dice-lang/src/bjc/dicelang/dice/Die.java
@@ -1,9 +1,37 @@
package bjc.dicelang.dice;
+/**
+ * Represents one or more dice that produce a scalar result.
+ *
+ * @author Ben Culkin
+ */
public interface Die {
+ /**
+ * Can this die be optimized to a single number?
+ *
+ * @return Whether this die can be optimized or not.
+ */
boolean canOptimize();
+ /**
+ * Optimize this die to a single number.
+ *
+ * Calling optimize on dice that return false for canOptimize produces
+ * undefined behavior
+ *
+ * @return The optimized form of this die
+ */
long optimize();
+ /**
+ * Roll this die.
+ *
+ * @return A possible roll of this die
+ */
long roll();
+ /**
+ * Roll only a single portion of this die.
+ *
+ * @return A possible roll of a single portion of this die.
+ */
long rollSingle();
-} \ No newline at end of file
+}
diff --git a/dice-lang/src/bjc/dicelang/dice/DieExpression.java b/dice-lang/src/bjc/dicelang/dice/DieExpression.java
index 3bf121b..81d0b7d 100644
--- a/dice-lang/src/bjc/dicelang/dice/DieExpression.java
+++ b/dice-lang/src/bjc/dicelang/dice/DieExpression.java
@@ -2,29 +2,57 @@ package bjc.dicelang.dice;
import java.util.Arrays;
+/**
+ * Represents either a die or a die list
+ *
+ * @author Ben Culkin
+ */
public class DieExpression {
+ /**
+ * Is this expression a list?
+ */
public final boolean isList;
+ /**
+ * The scalar value in this expression, if there is one.
+ */
public Die scalar;
+ /**
+ * The list value in this expression, if there is one.
+ */
public DieList list;
+ /**
+ * Create a scalar die expression.
+ *
+ * @param scal The scalar value of this expression.
+ */
public DieExpression(Die scal) {
isList = false;
scalar = scal;
}
+ /**
+ * Create a list die expression.
+ *
+ * @param lst The list value of this expression.
+ */
public DieExpression(DieList lst) {
isList = true;
list = lst;
}
+ @Override
public String toString() {
if(isList) return list.toString();
else return scalar.toString();
}
+ /**
+ * Get the value of this expression as a string.
+ */
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/dice/DieList.java b/dice-lang/src/bjc/dicelang/dice/DieList.java
index a55f2b9..5454759 100644
--- a/dice-lang/src/bjc/dicelang/dice/DieList.java
+++ b/dice-lang/src/bjc/dicelang/dice/DieList.java
@@ -1,8 +1,30 @@
package bjc.dicelang.dice;
+/**
+ * Represents a group of dice.
+ *
+ * @author Ben Culkin.
+ */
public interface DieList {
+ /**
+ * Can this list be optimized?
+ *
+ * @return Whether or not this list cna be optimized.
+ */
boolean canOptimize();
+ /**
+ * Optimize this list, if it can be done.
+ *
+ * Invoking this on unoptimizable expression is undefined.
+ *
+ * @return The optimized form of this list.
+ */
long[] optimize();
+ /**
+ * Roll this group of dice.
+ *
+ * @param A possible roll of this group.
+ */
long[] roll();
-} \ No newline at end of file
+}
diff --git a/dice-lang/src/bjc/dicelang/dice/ExplodingDice.java b/dice-lang/src/bjc/dicelang/dice/ExplodingDice.java
index 6ab9902..59e739e 100644
--- a/dice-lang/src/bjc/dicelang/dice/ExplodingDice.java
+++ b/dice-lang/src/bjc/dicelang/dice/ExplodingDice.java
@@ -4,21 +4,58 @@ import java.util.LinkedList;
import java.util.List;
import java.util.function.Predicate;
+/**
+ * An exploding die.
+ *
+ * Represents a die list that keeps getting another added die as long as a
+ * condition is met.
+ *
+ * @author Ben Culkin
+ */
public class ExplodingDice implements DieList {
+ /*
+ * The source die to use.
+ */
private Die source;
+ /*
+ * The conditions for exploding.
+ */
private Predicate<Long> explodeOn;
private String explodePattern;
private boolean explodePenetrates;
+ /**
+ * Create a new exploding die.
+ *
+ * @param src The source die for exploding.
+ * @param explode The condition to explode on.
+ */
public ExplodingDice(Die src, Predicate<Long> explode) {
this(src, explode, null, false);
}
+ /**
+ * Create a new exploding die that may penetrate.
+ *
+ * @param src The source die for exploding.
+ * @param explode The condition to explode on.
+ * @param penetrate Whether or not for explosions to penetrate (-1 to
+ * exploded die).
+ */
public ExplodingDice(Die src, Predicate<Long> explode, boolean penetrate) {
this(src, explode, null, penetrate);
}
+ /**
+ * Create a new exploding die that may penetrate.
+ *
+ * @param src The source die for exploding.
+ * @param explode The condition to explode on.
+ * @param penetrate Whether or not for explosions to penetrate (-1 to
+ * exploded die).
+ * @param patt The string the condition came from, for printing.
+ */
public ExplodingDice(Die src, Predicate<Long> explode, String patt,
boolean penetrate) {
source = src;
@@ -27,14 +64,17 @@ public class ExplodingDice implements DieList {
explodePenetrates = penetrate;
}
+ @Override
public boolean canOptimize() {
return false;
}
+ @Override
public long[] optimize() {
return new long[0];
}
+ @Override
public long[] roll() {
long res = source.roll();
long oldRes = res;
@@ -60,6 +100,7 @@ public class ExplodingDice implements DieList {
return newRes;
}
+ @Override
public String toString() {
if(explodePattern == null) {
return source + (explodePenetrates ? "p" : "") + "!";
@@ -67,4 +108,4 @@ public class ExplodingDice implements DieList {
return source + (explodePenetrates ? "p" : "") + "!" + explodePattern;
}
}
-} \ No newline at end of file
+}