import assert from 'node:assert/strict' import test from 'node:test' import { createStepQueue } from '../static/tetris/step-queue.js' const step = (side, number, raceElapsedMs = number) => ({ side, step: number, race_elapsed_ms: raceElapsedMs, game: { pieces: number }, }) test('a short race keeps every step on two independent boards', () => { const queue = createStepQueue() for (let number = 1; number <= 40; number += 1) { assert.equal(queue.enqueueStep('left', step('left', number)), true) assert.equal(queue.enqueueStep('right', step('right', number)), true) } assert.equal(queue.enqueueStep('left', step('left', 40)), false) const left = [] const right = [] let processed = 0 let now = 0 while (queue.hasPending()) { const frame = queue.nextFrame(now) if (frame.steps.left) left.push(frame.steps.left.step) if (frame.steps.right) right.push(frame.steps.right.step) processed += frame.processed now += 16 } assert.equal(processed, 80) assert.equal(left.at(-1), 40) assert.equal(right.at(-1), 40) assert.ok(left.every((value, index) => index === 0 || value > left[index - 1])) assert.ok(right.every((value, index) => index === 0 || value > right[index - 1])) }) test('a line clear survives when a later step replaces its board in the same frame', () => { const queue = createStepQueue() queue.enqueueStep('left', { ...step('left', 1, 10), cleared_rows: [19], }, 0) queue.enqueueStep('left', { ...step('left', 2, 10), cleared_rows: [], }, 0) queue.enqueueStep('right', { ...step('right', 1, 10), cleared_rows: [], }, 0) const frame = queue.nextFrame(0) assert.equal(frame.steps.left.step, 2) assert.equal(frame.steps.right.step, 1) assert.equal(frame.lineClears.left, 1) assert.equal(frame.lineClears.right, 0) }) test('a 2,000-step-per-side burst finishes visual replay within a bounded interval', () => { const queue = createStepQueue() for (let number = 1; number <= 2_000; number += 1) { queue.enqueueStep('left', step('left', number, number / 3), 0) queue.enqueueStep('right', step('right', number, number / 3), 0) } queue.finishSide('left', { score: 10 }, 670, 0) queue.finishSide('right', { score: 20 }, 675, 0) const left = [] const right = [] let processed = 0 let now = 0 const finishedAt = {} while (queue.hasPending()) { const frame = queue.nextFrame(now) if (frame.steps.left) left.push(frame.steps.left.step) if (frame.steps.right) right.push(frame.steps.right.step) if (frame.finished) finishedAt[frame.finished.side] = now processed += frame.processed now += 16 } assert.equal(processed, 4_002) assert.equal(left.at(-1), 2_000) assert.equal(right.at(-1), 2_000) assert.ok(finishedAt.left < finishedAt.right) assert.ok(now <= 1_200, `4,000 decisions replayed in ${now} ms`) }) test('a completed 120-step-per-side race does not incur a frame per decision', () => { const queue = createStepQueue() for (let number = 1; number <= 120; number += 1) { queue.enqueueStep('left', step('left', number, number * 5), 0) queue.enqueueStep('right', step('right', number, number * 5), 0) } queue.finishSide('left', { score: 10 }, 605, 0) queue.finishSide('right', { score: 20 }, 610, 0) let now = 0 let processed = 0 const last = { left: 0, right: 0 } while (queue.hasPending()) { const frame = queue.nextFrame(now) processed += frame.processed for (const side of ['left', 'right']) { if (frame.steps[side]) last[side] = frame.steps[side].step } now += 16 } assert.equal(processed, 242) assert.deepEqual(last, { left: 120, right: 120 }) assert.ok(now <= 900, `240 decisions replayed in ${now} ms`) }) test('terminal cards follow actual finish order and wait for each last board frame', () => { const queue = createStepQueue() for (let number = 1; number <= 3; number += 1) { queue.enqueueStep('left', step('left', number, number * 10), 0) } queue.enqueueStep('right', step('right', 1, 15), 0) queue.finishSide('left', { score: 10 }, 40, 0) queue.finishSide('right', { score: 20 }, 50, 0) const frames = [] for (let now = 0; queue.hasPending(); now += 16) frames.push(queue.nextFrame(now)) assert.equal(frames[0].steps.left.step, 1) assert.equal(frames[1].steps.right.step, 1) assert.equal(frames[0].finished, null) assert.equal(frames[2].steps.left.step, 3) assert.deepEqual(frames[2].finished, { side: 'left', result: { score: 10 } }) assert.deepEqual(frames[3].finished, { side: 'right', result: { score: 20 } }) }) test('snapshot recovery applies the server finish order before rendering cards', () => { const queue = createStepQueue() queue.setFinishOrder(['right', 'left']) queue.finishSide('left', { score: 10 }) queue.finishSide('right', { score: 20 }) assert.equal(queue.nextFrame(0).finished.side, 'right') assert.equal(queue.nextFrame(16).finished.side, 'left') assert.equal(queue.hasPending(), false) }) test('a completed replay keeps a large finish gap without dropping decisions', () => { const queue = createStepQueue() for (let number = 1; number <= 4; number += 1) { queue.enqueueStep('left', step('left', number, number * 25), 0) queue.enqueueStep('right', step('right', number, number * 10_000), 0) } queue.finishSide('left', { score: 10 }, 125, 0) queue.finishSide('right', { score: 20 }, 41_000, 0) const latest = { left: 0, right: 0 } const finishedAt = {} let processed = 0 for (let now = 0; queue.hasPending() && now <= 2400; now += 16) { const frame = queue.nextFrame(now) for (const side of ['left', 'right']) { if (frame.steps[side]) latest[side] = frame.steps[side].step } processed += frame.processed if (frame.finished) finishedAt[frame.finished.side] = now } assert.deepEqual(latest, { left: 4, right: 4 }) assert.equal(processed, 10) assert.ok(finishedAt.left < finishedAt.right - 1000) assert.ok(finishedAt.right <= 2000) assert.equal(queue.hasPending(), false) })