diff --git a/server/src/industry/__tests__/inventionTimeline.test.ts b/server/src/industry/__tests__/inventionTimeline.test.ts new file mode 100644 index 0000000..7d66892 --- /dev/null +++ b/server/src/industry/__tests__/inventionTimeline.test.ts @@ -0,0 +1,44 @@ +import { describe, it, expect } from 'vitest'; +import { createInventionTimeline, type InventionTimeline } from '../inventionTimeline.js'; + +describe('InventionTimeline', () => { + it('starts empty', () => { + const timeline = createInventionTimeline(); + expect(timeline.getAll()).toEqual([]); + }); + + it('records an invention entry', () => { + const timeline = createInventionTimeline(); + timeline.record({ + itemId: 'rope', + inventorEntityId: 1, + inventorName: 'Gwen', + tick: 500, + day: 2, + }); + const all = timeline.getAll(); + expect(all).toHaveLength(1); + expect(all[0].itemId).toBe('rope'); + expect(all[0].inventorName).toBe('Gwen'); + }); + + it('counts inventions per entity', () => { + const timeline = createInventionTimeline(); + timeline.record({ itemId: 'rope', inventorEntityId: 1, inventorName: 'Gwen', tick: 500, day: 2 }); + timeline.record({ itemId: 'clay', inventorEntityId: 1, inventorName: 'Gwen', tick: 600, day: 2 }); + timeline.record({ itemId: 'kiln', inventorEntityId: 2, inventorName: 'Bram', tick: 700, day: 3 }); + + expect(timeline.countByEntity(1)).toBe(2); + expect(timeline.countByEntity(2)).toBe(1); + expect(timeline.countByEntity(3)).toBe(0); + }); + + it('returns entries in insertion order', () => { + const timeline = createInventionTimeline(); + timeline.record({ itemId: 'a', inventorEntityId: 1, inventorName: 'X', tick: 300, day: 1 }); + timeline.record({ itemId: 'b', inventorEntityId: 2, inventorName: 'Y', tick: 100, day: 1 }); + const all = timeline.getAll(); + expect(all[0].tick).toBe(300); + expect(all[1].tick).toBe(100); + }); +}); diff --git a/server/src/industry/inventionTimeline.ts b/server/src/industry/inventionTimeline.ts new file mode 100644 index 0000000..ef4d57e --- /dev/null +++ b/server/src/industry/inventionTimeline.ts @@ -0,0 +1,33 @@ +import type { EntityId } from '@dflike/shared'; + +export interface InventionEntry { + itemId: string; + inventorEntityId: EntityId; + inventorName: string; + tick: number; + day: number; +} + +export interface InventionTimeline { + record(entry: InventionEntry): void; + getAll(): InventionEntry[]; + countByEntity(entityId: EntityId): number; +} + +export function createInventionTimeline(): InventionTimeline { + const entries: InventionEntry[] = []; + + return { + record(entry: InventionEntry): void { + entries.push(entry); + }, + + getAll(): InventionEntry[] { + return [...entries]; + }, + + countByEntity(entityId: EntityId): number { + return entries.filter(e => e.inventorEntityId === entityId).length; + }, + }; +}