diff options
| -rw-r--r-- | README.md | 3 | ||||
| -rw-r--r-- | __tests__/dice.test.js | 23 | ||||
| -rw-r--r-- | __tests__/lexer.test.js | 24 | ||||
| -rw-r--r-- | __tests__/parser.test.js | 42 | ||||
| -rw-r--r-- | index.js | 2 | ||||
| -rw-r--r-- | src/dice.js | 7 | ||||
| -rw-r--r-- | src/lexer.js | 1 | ||||
| -rw-r--r-- | src/parser.js | 1 | 
8 files changed, 103 insertions, 0 deletions
| @@ -80,6 +80,7 @@ The parser recognizes the following grammar:            | 'd' Die            | Die ' + ' Die            | Die ' - ' Die +          | Die ' * ' Die            | Die '+' Die            | Die '-' Die            | '-' Die @@ -106,6 +107,8 @@ Semantics are defined in terms of the `pool` function.    `D`.  * `-D` returns the opposites of values generated by `D`.  * `D - E` is equivalent to `D + (-E)`. +* `D * E` generates a dicepool with a single value - the produc of `roll(D)` and +  `roll(E)`.  * `D+E` is the additive bonus operation. For each die in `D`'s pool, the die is    rolled and `roll(E)` is added to its result.  * `D-E` is equivalent to `D+(-E)`. diff --git a/__tests__/dice.test.js b/__tests__/dice.test.js index caba0a9..4e89031 100644 --- a/__tests__/dice.test.js +++ b/__tests__/dice.test.js @@ -4,6 +4,7 @@ const {    d,    add,    subtract, +  multiply,    bonusAdd,    bonusSubtract,    negative, @@ -316,6 +317,28 @@ describe('subtract', () => {    })  }) +describe('multiply', () => { +  describe('1d6 * 3', () => { +    const die = multiply(d(constant(1), constant(6)), constant(3)) +    testDie(die, { +      diceCount: 1, +      average: { +        average: 10.5 +      }, +      variance: { +        variance: 26.25 +      }, +      bounds: { +        low: 3, +        high: 18, +        expectLow: true, +        expectHigh: true +      } +    }) +  }) +}) + +  describe('bonusAdd', () => {    describe('1d20+3', () => {      const die = bonusAdd(d(constant(1), constant(20)), constant(3)) diff --git a/__tests__/lexer.test.js b/__tests__/lexer.test.js index b51c0f9..db7ab50 100644 --- a/__tests__/lexer.test.js +++ b/__tests__/lexer.test.js @@ -97,6 +97,30 @@ describe('lex', () => {      })    }) +  describe('lexes multiplication', () => { +    it('1d6 * 1d4', () => { +      expect(lex('1d6 * 1d4')).toEqual([ +        { type: 'constant', value: 1 }, +        { type: 'd' }, +        { type: 'constant', value: 6 }, +        { type: 'bigTimes' }, +        { type: 'constant', value: 1 }, +        { type: 'd' }, +        { type: 'constant', value: 4 } +      ]) +    }) + +    it('2d17 * 4', () => { +      expect(lex('2d17 * 4')).toEqual([ +        { type: 'constant', value: 2 }, +        { type: 'd' }, +        { type: 'constant', value: 17 }, +        { type: 'bigTimes' }, +        { type: 'constant', value: 4 } +      ]) +    }) +  }) +    describe('lexes parentheses', () => {      it('(1d6)d6', () => {        expect(lex('(1d6)d6')).toEqual([ diff --git a/__tests__/parser.test.js b/__tests__/parser.test.js index 6e575b6..5d4288d 100644 --- a/__tests__/parser.test.js +++ b/__tests__/parser.test.js @@ -97,6 +97,22 @@ describe('parse', () => {      })    }) +  it('parses dice multiplication', () => { +    expect(parse('1d6 * 2d8')).toEqual({ +      type: 'multiply', +      left: { +        type: 'd', +        left: { type: 'constant', value: 1 }, +        right: { type: 'constant', value: 6 } +      }, +      right: { +        type: 'd', +        left: { type: 'constant', value: 2 }, +        right: { type: 'constant', value: 8 } +      } +    }) +  }) +    it('parses additive bonuses', () => {      expect(parse('3d4+1')).toEqual({        type: 'bonusAdd', @@ -282,4 +298,30 @@ describe('parse', () => {        })      })    }) + +  describe('order of operations', () => { +    test('2 * 3 + 4', () => { +      expect(parse('2 * 3 + 4')).toEqual({ +        type: 'add', +        left: { +          type: 'multiply', +          left: { type: 'constant', value: 2 }, +          right: { type: 'constant', value: 3 }, +        }, +        right: { type: 'constant', value: 4 }, +      }) +    }) + +    test('2 + 3 * 4', () => { +      expect(parse('2 + 3 * 4')).toEqual({ +        type: 'add', +        left: { type: 'constant', value: 2 }, +        right: { +          type: 'multiply', +          left: { type: 'constant', value: 3 }, +          right: { type: 'constant', value: 4 }, +        } +      }) +    }) +  })  }) @@ -27,6 +27,8 @@ const interpret = tree => {      return D.add(interpret(tree.left), interpret(tree.right))    case 'subtract':      return D.subtract(interpret(tree.left), interpret(tree.right)) +  case 'multiply': +    return D.multiply(interpret(tree.left), interpret(tree.right))    case 'negative':      return D.negative(interpret(tree.value))    case 'bonusAdd': diff --git a/src/dice.js b/src/dice.js index 828a772..abe3c4b 100644 --- a/src/dice.js +++ b/src/dice.js @@ -44,6 +44,12 @@ const subtract = (die1, die2) => {    }  } +const multiply = (die1, die2) => { +  return () => { +    return [() => roll(die1) * roll(die2)] +  } +} +  const bonusAdd = (die1, die2) => {    return () => {      return die1().map(die => { @@ -187,6 +193,7 @@ exports.constant = constant  exports.d = d  exports.add = add  exports.subtract = subtract +exports.multiply = multiply  exports.bonusAdd = bonusAdd  exports.bonusSubtract = bonusSubtract  exports.negative = negative diff --git a/src/lexer.js b/src/lexer.js index ba3d3a5..c3eec8a 100644 --- a/src/lexer.js +++ b/src/lexer.js @@ -18,6 +18,7 @@ newValueLexeme('constant', '\\d+', Number)  newLexemeType('d', 'd')  newLexemeType('bigPlus', ' \\+ ' )  newLexemeType('bigMinus', ' - ') +newLexemeType('bigTimes', ' \\* ')  newLexemeType('plus', '\\+')  newLexemeType('minus', '-')  newLexemeType('(', '\\(') diff --git a/src/parser.js b/src/parser.js index adb4b9b..1a1e5d4 100644 --- a/src/parser.js +++ b/src/parser.js @@ -71,6 +71,7 @@ newDieOperation('t')  newInfix('bigPlus', 20, { type: 'add' })  newInfix('bigMinus', 20, { type: 'subtract' }) +newInfix('bigTimes', 23, { type: 'multiply' })  newInfix('plus', 25, { type: 'bonusAdd' })  newInfix('minus', 25, { type: 'bonusSubtract' })  newSymbol('minus', (parser) => { |