diff options
-rw-r--r-- | __tests__/dice.test.js | 24 | ||||
-rw-r--r-- | __tests__/lexer.test.js | 10 | ||||
-rw-r--r-- | __tests__/parser.test.js | 10 | ||||
-rw-r--r-- | index.js | 2 | ||||
-rw-r--r-- | src/dice.js | 37 | ||||
-rw-r--r-- | src/lexer.js | 1 | ||||
-rw-r--r-- | src/parser.js | 1 |
7 files changed, 85 insertions, 0 deletions
diff --git a/__tests__/dice.test.js b/__tests__/dice.test.js index d4e2802..272f436 100644 --- a/__tests__/dice.test.js +++ b/__tests__/dice.test.js @@ -12,6 +12,7 @@ const { keepHigh, keepLow, again, + againUnder, threshold } = require('../src/dice.js') @@ -579,6 +580,29 @@ describe('again', () => { } }) }) + + describe('1a1d6', () => { + const die = againUnder(constant(1), d(constant(1), constant(6))) + + testDie(die, { + variableDiceCount: { + min: 1, + max: Infinity + }, + average: { + average: 4.2 + }, + variance: { + variance: 2.24 + }, + bounds: { + low: 2, + high: Infinity, + expectLow: true, + expectHigh: false + } + }) + }) }) describe('threshold', () => { diff --git a/__tests__/lexer.test.js b/__tests__/lexer.test.js index 0336f44..25ef816 100644 --- a/__tests__/lexer.test.js +++ b/__tests__/lexer.test.js @@ -203,6 +203,16 @@ describe('lex', () => { { type: 'constant', value: 6 } ]) }) + + test('6a3d6', () => { + expect(lex('6a3d6')).toEqual([ + { type: 'constant', value: 6 }, + { type: 'a' }, + { type: 'constant', value: 3 }, + { type: 'd' }, + { type: 'constant', value: 6 } + ]) + }) }) describe('threshold', () => { diff --git a/__tests__/parser.test.js b/__tests__/parser.test.js index 765388d..ad67fc4 100644 --- a/__tests__/parser.test.js +++ b/__tests__/parser.test.js @@ -219,6 +219,16 @@ describe('parse', () => { right: { type: 'constant', value: 10 } } }) + + expect(parse('10a3d10')).toEqual({ + type: 'a', + left: { type: 'constant', value: 10 }, + right: { + type: 'd', + left: { type: 'constant', value: 3 }, + right: { type: 'constant', value: 10 } + } + }) }) it('parases dice with threshold', () => { @@ -17,6 +17,8 @@ const interpret = tree => { return D.keepLow(interpret(tree.left), interpret(tree.right)) case 'A': return D.again(interpret(tree.left), interpret(tree.right)) + case 'a': + return D.againUnder(interpret(tree.left), interpret(tree.right)) case 'T': return D.threshold(interpret(tree.left), interpret(tree.right)) case 'add': diff --git a/src/dice.js b/src/dice.js index e96aca9..e580c9d 100644 --- a/src/dice.js +++ b/src/dice.js @@ -162,6 +162,42 @@ const again = (die1, die2) => { } } +const againUnder = (die1, die2) => { + return () => { + const againOn = roll(die1) + let rolls = [] + let rollAgain = [] + + const rollDie = (die) => { + const roll = die() + + if (roll <= againOn) { + rollAgain.push(die) + } + + let returnedOriginal = false + rolls.push(() => { + if (!returnedOriginal) { + returnedOriginal = true + return roll + } else { + return die() + } + }) + } + + die2().forEach(rollDie) + + while (rollAgain.length > 0) { + const oldRollAgain = rollAgain + rollAgain = [] + oldRollAgain.forEach(rollDie) + } + + return rolls + } +} + const threshold = (die1, die2) => { return () => { const cutoff = roll(die1) @@ -193,4 +229,5 @@ exports.explodeUnder = explodeUnder exports.keepHigh = keepHigh exports.keepLow = keepLow exports.again = again +exports.againUnder = againUnder exports.threshold = threshold diff --git a/src/lexer.js b/src/lexer.js index 7eb95b0..f33dc87 100644 --- a/src/lexer.js +++ b/src/lexer.js @@ -27,6 +27,7 @@ newLexemeType('e', 'e') newLexemeType('K', 'K') newLexemeType('k', 'k') newLexemeType('A', 'A') +newLexemeType('a', 'a') newLexemeType('T', 'T') const lex = (expressionString) => { diff --git a/src/parser.js b/src/parser.js index 124d686..f8e2a5b 100644 --- a/src/parser.js +++ b/src/parser.js @@ -65,6 +65,7 @@ newDieOperation('e') newDieOperation('K') newDieOperation('k') newDieOperation('A') +newDieOperation('a') newDieOperation('T') newInfix('bigPlus', 20, { type: 'add' }) |