m-chrzan.xyz
aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcin Chrzanowski <marcin.j.chrzanowski@gmail.com>2017-07-09 16:32:02 -0400
committerMarcin Chrzanowski <marcin.j.chrzanowski@gmail.com>2017-07-09 16:33:50 -0400
commit606a177f0d0fd03fb8ac8899e67c0d4083b93ba6 (patch)
treedf15a1bb24e1eaaac6f4798ebc64e3085f57b2e8
parentc97eb5f531678c358c65d5e2738d5e6ca6c09b66 (diff)
Implement basic dice
-rw-r--r--__tests__/dice.test.js119
-rw-r--r--src/dice.js18
2 files changed, 137 insertions, 0 deletions
diff --git a/__tests__/dice.test.js b/__tests__/dice.test.js
new file mode 100644
index 0000000..9df156f
--- /dev/null
+++ b/__tests__/dice.test.js
@@ -0,0 +1,119 @@
+const { d } = require('../src/dice.js')
+
+const defaultNumberRolls = 100
+
+expect.extend({
+ toBeOnAverage(received, expected, margin = 0.3) {
+ const average = received.reduce(plus) / received.length
+ const pass = average > expected - margin && average < expected + margin
+
+ return {
+ pass,
+ message: () => (
+ `expected average to${pass ? ' not ' : ' '}be around ${expected} (margin: ${margin}), got ${average}`
+ )
+ }
+ },
+ toBeBetween(received, low, high) {
+ const pass = received.reduce((allOk, value) => {
+ return allOk && value >= low && value <= high
+ }, true)
+
+ return {
+ pass,
+ message: () => (
+ `expected all to${pass ? ' not ' : ' '}be between ${low} and ${high}`
+ )
+ }
+ },
+ toAllBe(received, expected) {
+ const pass = received.reduce((allOk, value) => {
+ return allOk && value === expected
+ })
+
+ return {
+ pass,
+ message: () => (
+ `expected all to${pass ? ' not ' : ' '}be equal to ${expected}`
+ )
+ }
+ }
+})
+
+const plus = (a, b) => (a + b)
+
+const rollForTest = (die, numberRolls) => {
+ let pools = []
+ let rolls = []
+
+ for (let i = 0; i < numberRolls; i++) {
+ let rolled = die()
+ pools.push(rolled)
+ rolls.push(rolled.reduce(plus))
+ }
+
+ return { pools, rolls }
+}
+
+const testDie = (die, numberRolls, testSpecs) => {
+ let { pools, rolls } = rollForTest(die, numberRolls)
+
+ if ('diceCount' in testSpecs) {
+ it(`rolls ${testSpecs.diceCount} dice`, () => {
+ expect(pools.map((pool) => (pool.length))).toAllBe(testSpecs.diceCount)
+ })
+ }
+
+ if ('average' in testSpecs) {
+ let { average, margin } = testSpecs.average
+
+ it(`has an expected value of ${average}`, () => {
+ expect(rolls).toBeOnAverage(average, margin)
+ })
+ }
+
+ if ('bounds' in testSpecs) {
+ let { low, high } = testSpecs.bounds
+
+ it(`rolls between ${low} and ${high}`, () => {
+ expect(rolls).toBeBetween(low, high)
+ })
+
+ it('attains its minimum', () => {
+ expect(rolls).toContain(low)
+ })
+
+ it('attains its maximum', () => {
+ expect(rolls).toContain(high)
+ })
+ }
+}
+
+const describeBasicDie = (number, sides, numberRolls = defaultNumberRolls) => {
+ describe(`${number}d${sides}`, () => {
+ const die = d(number, sides)
+ const min = number
+ const max = number * sides
+
+ const testSpecs = {
+ diceCount: number,
+ average: {
+ average: (min + max) / 2,
+ },
+ bounds: {
+ low: min,
+ high: max,
+ expectLow: true,
+ expectHigh: true
+ }
+ }
+
+ testDie(die, numberRolls, testSpecs)
+ })
+}
+
+describe('basic dice', () => {
+ describeBasicDie(1, 6)
+ describeBasicDie(2, 8)
+ describeBasicDie(20, 1)
+})
diff --git a/src/dice.js b/src/dice.js
new file mode 100644
index 0000000..2914317
--- /dev/null
+++ b/src/dice.js
@@ -0,0 +1,18 @@
+const d = (number, sides) => {
+ return () => {
+ let pool = []
+
+ for (let i = 0; i < number; i++) {
+ pool.push(1 + Math.floor(Math.random() * sides))
+ }
+
+ return pool
+ }
+}
+
+const roll = (die) => {
+ return die().reduce((a, b) => (a + b))
+}
+
+exports.d = d
+exports.roll = roll