Skip to content

Commit

Permalink
add increments
Browse files Browse the repository at this point in the history
  • Loading branch information
radulle committed May 22, 2021
1 parent 0101fdf commit c4505b7
Show file tree
Hide file tree
Showing 5 changed files with 319 additions and 105 deletions.
1 change: 1 addition & 0 deletions .github/workflows/npm-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ jobs:
node-version: 12
registry-url: https://registry.npmjs.org/
- run: yarn
- run: yarn build
- run: yarn publish
env:
NODE_AUTH_TOKEN: ${{secrets.npm_token}}
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
node_modules
/lib
lib
coverage
14 changes: 12 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,26 @@
"description": "Chess clock API",
"author": "Nikola Radulaški",
"license": "MIT",
"version": "0.0.1",
"version": "0.1.2",
"keywords": [
"chess",
"chessclock",
"chess-clock",
"gameclock",
"game-clock",
"chesstimer",
"chess-timer",
"gametimer",
"game-timer",
"board-game",
"boardgame",
"clock",
"timing",
"timer"
"timer",
"delay",
"fischer",
"bronstein",
"hourglass"
],
"main": "./lib/cjs/index.js",
"module": "./lib/esm/index.js",
Expand Down
177 changes: 158 additions & 19 deletions src/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Status, Timer, TimerInterface } from '.'
import { Mode, Status, Timer, TimerInterface } from '.'

const TIME = 5 * 6000
const TIME = 5 * 60_000
const UPDATE_INTERVAL = 100

jest.useFakeTimers()
Expand All @@ -10,15 +10,44 @@ dateNow.mockImplementation(() => (time += UPDATE_INTERVAL))

const callback = jest.fn()

const noIncrementOptions = {
stageList: [
const noIncrement = {
stages: [
{
time: [TIME, TIME],
increment: 0,
},
],
} as TimerInterface

const bronstein = {
stages: [
{
time: [TIME, TIME],
increment: 5000,
mode: Mode.Bronstein,
},
],
} as TimerInterface

const simpleDelay = {
stages: [
{
time: [TIME, TIME],
increment: 5000,
mode: Mode.Delay,
},
],
} as TimerInterface

const hourglass = {
stages: [
{
time: [TIME, TIME],
mode: Mode.Hourglass,
},
],
} as TimerInterface

describe('Timer', () => {
beforeEach(() => {
jest.clearAllMocks()
Expand All @@ -43,7 +72,7 @@ describe('Timer', () => {
})

it('can have different initial times', () => {
const timer = new Timer({ stageList: [{ time: [4, 2] }] })
const timer = new Timer({ stages: [{ time: [4, 2] }] })
expect(timer.state.remainingTime).toStrictEqual([4, 2])
})

Expand All @@ -55,7 +84,7 @@ describe('Timer', () => {

it('stage defined by move', () => {
const timer = new Timer({
stageList: [{ time: [1, 1] }, { time: [1, 1], move: 1 }],
stages: [{ time: [1, 1] }, { time: [1, 1], move: 1 }],
})
timer.push(0)
expect(timer.state.stage.map((e) => e.i)).toStrictEqual([1, 0])
Expand All @@ -69,14 +98,14 @@ describe('Timer', () => {

it('will add time on new stage', () => {
const timer = new Timer({
stageList: [{ time: [42, 21] }, { time: [42, 21], move: 1 }],
stages: [{ time: [42, 21] }, { time: [42, 21], move: 1 }],
})
timer.push(0)
expect(timer.state.remainingTime).toStrictEqual([84, 21])
})

it('can reset to initial values', () => {
const timer = new Timer()
it('can reset to initial game parameters', () => {
const timer = new Timer(noIncrement)
timer.push(0)
timer.addTime(0, 42)
expect(timer.state.move).toStrictEqual([1, 0])
Expand All @@ -88,6 +117,13 @@ describe('Timer', () => {
expect(timer.state.log).toStrictEqual([[], []])
})

it('can reset to new game parameters', () => {
const timer = new Timer(noIncrement)
expect(timer.state.stages[0].mode).toBeUndefined()
timer.reset(hourglass.stages)
expect(timer.state.stages[0].mode).toBe(Mode.Hourglass)
})

it('provides state', () => {
const timer = new Timer()
expect(timer.state).not.toBe(undefined)
Expand All @@ -109,8 +145,16 @@ describe('Timer', () => {
expect(timer.state.status).toBe(Status.done)
})

it('status is done when remainingTime has expired on push', () => {
const timer = new Timer()
timer.push(0)
dateNow.mockReturnValueOnce(TIME + 100)
timer.push(1)
expect(timer.state.status).toBe(Status.done)
})

it('remainingTime can not be lower than 0', () => {
const timer = new Timer({ callback })
const timer = new Timer({ ...noIncrement, callback })
timer.push(0)
jest.runTimersToTime(2 * TIME)
expect(timer.state.remainingTime).toStrictEqual([TIME, 0])
Expand Down Expand Up @@ -140,12 +184,23 @@ describe('Timer', () => {
it('has no effect if twice in a row by the same player', () => {
const timer = new Timer()
timer.push(0)
const state = timer.state
timer.push(0)
expect(timer.state.move).toStrictEqual([1, 0])
expect(timer.state).toStrictEqual(state)
})

it('has no effect if status is done', () => {
const timer = new Timer()
timer.push(0)
jest.runTimersToTime(TIME)
timer.push(1)
const state = timer.state
timer.push(0)
expect(timer.state).toStrictEqual(state)
})

it('can update elapsed time (without increment)', () => {
const timer = new Timer(noIncrementOptions)
const timer = new Timer(noIncrement)

timer.push(0)
expect(timer.state.timestamp).toBe(100)
Expand All @@ -157,7 +212,7 @@ describe('Timer', () => {
})

it('can log time on non opening moves (without increment)', () => {
const timer = new Timer(noIncrementOptions)
const timer = new Timer(noIncrement)

expect(timer.state.status).toBe(Status.ready)

Expand All @@ -184,7 +239,7 @@ describe('Timer', () => {

describe('Pause', () => {
it('has effect if status is live', () => {
const timer = new Timer(noIncrementOptions)
const timer = new Timer(noIncrement)

timer.push(0)

Expand All @@ -200,7 +255,7 @@ describe('Timer', () => {
})

it('has no effect if status is not live', () => {
const timer = new Timer(noIncrementOptions)
const timer = new Timer(noIncrement)

// ready
timer.pause()
Expand All @@ -216,13 +271,13 @@ describe('Timer', () => {
jest.runTimersToTime(4200)
expect(timer.state.status).toBe(Status.done)

expect(dateNow).toBeCalledTimes(301)
expect(dateNow).toBeCalledTimes(TIME / UPDATE_INTERVAL + 1)
})
})

describe('Resume', () => {
it('has effect if status is paused', () => {
const timer = new Timer(noIncrementOptions)
const timer = new Timer(noIncrement)

timer.push(0)

Expand All @@ -241,7 +296,7 @@ describe('Timer', () => {
})

it('has no effect if status is not live', () => {
const timer = new Timer(noIncrementOptions)
const timer = new Timer(noIncrement)

// ready
timer.resume()
Expand All @@ -266,7 +321,7 @@ describe('Timer', () => {
})

it('Resume has no effect if status is ready or done', () => {
const timer = new Timer(noIncrementOptions)
const timer = new Timer(noIncrement)

// ready
timer.resume()
Expand Down Expand Up @@ -323,4 +378,88 @@ describe('Timer', () => {
expect(callback).toBeCalledTimes(11)
})
})

describe('Increments', () => {
describe('Fischer', () => {
it('will add increment at end of each turn', () => {
const timer = new Timer()
timer.push(0)
expect(timer.state.remainingTime).toStrictEqual([
TIME + (timer.state.stage[0].increment || 0),
TIME,
])
})
})

describe('Bronstein', () => {
it('will add spent increment at end of each turn', () => {
const timer = new Timer(bronstein)
timer.push(0)
expect(timer.state.remainingTime).toStrictEqual([TIME, TIME])
jest.advanceTimersByTime((timer.state.stage[1]?.increment || 0) / 2)
expect(timer.state.remainingTime).toStrictEqual([
TIME,
TIME - (timer.state.stage[1]?.increment || 0) / 2,
])
timer.push(1)
expect(timer.state.remainingTime).toStrictEqual([TIME, TIME])
})

it('will add whole increment if it is spent at end of each turn', () => {
const timer = new Timer(bronstein)
timer.push(0)
expect(timer.state.remainingTime).toStrictEqual([TIME, TIME])
jest.advanceTimersByTime(timer.state.stage[1]?.increment || 0)
timer.push(1)
expect(timer.state.remainingTime).toStrictEqual([TIME, TIME - 100])
})
})

describe('Hourglass', () => {
it('will add spent time to opponent', () => {
const timer = new Timer(hourglass)
timer.push(0)
expect(timer.state.remainingTime).toStrictEqual([TIME, TIME])
jest.advanceTimersByTime(1000)
timer.push(1)
expect(timer.state.remainingTime).toStrictEqual([
TIME + 1100,
TIME - 1100,
])
})
})

describe('Delay', () => {
it('will not start decreasing remainingTime before delay', () => {
const timer = new Timer(simpleDelay)
const delay = timer.state.stage[1]?.increment || 0
timer.push(0)
expect(timer.state.remainingTime).toStrictEqual([TIME, TIME])
jest.advanceTimersByTime(delay / 2)
expect(timer.state.remainingTime).toStrictEqual([TIME, TIME])
timer.push(1)
jest.advanceTimersByTime(delay - 100)
timer.push(0)
expect(timer.state.remainingTime).toStrictEqual([TIME, TIME])
})

it('will decrease remainingTime after delay', () => {
const timer = new Timer(simpleDelay)
const delay = timer.state.stage[1]?.increment || 0
timer.push(0)
jest.advanceTimersByTime(delay + 100)
timer.push(1)
expect(timer.state.remainingTime).toStrictEqual([TIME, TIME - 200])
})

it('will immediately decrease remainingTime after delay', () => {
const timer = new Timer(simpleDelay)
const delay = timer.state.stage[1]?.increment || 0
timer.push(0)
jest.advanceTimersByTime(delay)
timer.push(1)
expect(timer.state.remainingTime).toStrictEqual([TIME, TIME - 100])
})
})
})
})
Loading

0 comments on commit c4505b7

Please sign in to comment.