diff --git a/.github/workflows/pr-build.yml b/.github/workflows/pr-build.yml index 27001c0..d90fd91 100644 --- a/.github/workflows/pr-build.yml +++ b/.github/workflows/pr-build.yml @@ -9,7 +9,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ macos-latest, ubuntu-latest, windows-latest ] + os: [ macos-latest, ubuntu-latest ] steps: - uses: actions/checkout@v6 - name: Use Node.js 24 diff --git a/app/games/otter-stop/game.js b/app/games/otter-stop/game.js index c3e5331..fa5dcad 100644 --- a/app/games/otter-stop/game.js +++ b/app/games/otter-stop/game.js @@ -253,7 +253,7 @@ export function recordResponse(isNoGo, spacePressed) { staircaseState = { value: level, consecutiveCorrect, - consecutiveWrong: 0, + consecutiveWrong, }; } } else { diff --git a/app/games/otter-stop/tests/game.test.js b/app/games/otter-stop/tests/game.test.js index 465d4aa..7e7554f 100644 --- a/app/games/otter-stop/tests/game.test.js +++ b/app/games/otter-stop/tests/game.test.js @@ -317,10 +317,10 @@ describe('recordResponse()', () => { expect(getConsecutiveCorrect()).toBe(0); }); - it('resets consecutiveWrong to 0', () => { - recordResponse(false, false); // wrong first - recordResponse(false, true); // now correct - expect(getConsecutiveWrong()).toBe(0); + it('does not reset consecutiveWrong (only a correct no-go inhibition resets it)', () => { + recordResponse(false, false); // wrong first (consecutiveWrong = 1) + recordResponse(false, true); // correct go — does NOT reset wrong streak + expect(getConsecutiveWrong()).toBe(1); }); }); @@ -491,14 +491,33 @@ describe('recordResponse()', () => { expect(getConsecutiveWrong()).toBe(2); }); - it('a correct response resets the wrong streak', () => { + it('a correct no-go inhibition resets the wrong streak', () => { for (let i = 0; i < 6; i += 1) recordResponse(true, false); // level → 2 - recordResponse(false, false); - recordResponse(false, false); - recordResponse(false, true); // correct go — resets wrong streak - recordResponse(false, false); - recordResponse(false, false); - expect(getLevel()).toBe(2); // no drop + recordResponse(false, false); // miss, consecutiveWrong = 1 + recordResponse(false, false); // miss, consecutiveWrong = 2 + recordResponse(true, false); // correct no-go inhibition — resets wrong streak + recordResponse(false, false); // miss, consecutiveWrong = 1 + recordResponse(false, false); // miss, consecutiveWrong = 2 + expect(getLevel()).toBe(2); // no drop (only 2 wrong since last correct no-go) + }); + + it('a correct go response does not reset the wrong streak', () => { + for (let i = 0; i < 6; i += 1) recordResponse(true, false); // level → 2 + recordResponse(false, false); // miss, consecutiveWrong = 1 + recordResponse(false, false); // miss, consecutiveWrong = 2 + recordResponse(false, true); // correct go — does NOT reset wrong streak + recordResponse(false, false); // miss, consecutiveWrong = 3 → level drops to 0 + expect(getLevel()).toBe(0); + }); + + it('3 false alarms with correct forced-go responses between them cause a level drop', () => { + for (let i = 0; i < 6; i += 1) recordResponse(true, false); // level → 2 + recordResponse(true, true); // false alarm, consecutiveWrong = 1 + recordResponse(false, true); // correct forced go — does NOT reset wrong streak + recordResponse(true, true); // false alarm, consecutiveWrong = 2 + recordResponse(false, true); // correct forced go — does NOT reset wrong streak + recordResponse(true, true); // false alarm, consecutiveWrong = 3 → level drops + expect(getLevel()).toBe(0); }); }); });