/** * Life Journey — the real board: 211 tiles across 12 segments, built from * shared/tileInventory.js (parsed from the design doc). * * TEMPORARY: the 12 segments have no defined connections yet — that's what * shared/BRANCHING-TEMPLATE.md is an open request for (the STOP forks, and * which segment's exit feeds which segment's entry). Until board-graph.json * exists, TEMP_SEGMENT_ORDER below just concatenates all 12 segments in the * design doc's own listed order into one line, so movement/tests/rendering * have something real to walk. This is NOT the real board topology — delete * this placeholder and replace `next` wiring once board-graph.json exists. * * Similarly, no tile in the source data has type 'finish' (win condition is * itself an open question in GAME-REVIEW.md) — a synthetic `finish` space is * appended after the last tile so the reducer has something to end on. * * Movement is one tile per turn (no tile in the data implies a movement die — * every `die` value belongs to that tile's own effect resolution), so unlike * the old board there is no walkForward()/multi-step-with-early-stop concept * here: a turn is just "go to `next`, then resolve whatever that tile needs." * * Space shape: { id, type, label, die, externalTables, statsTouched, next } * type: one of the 9 tile-inventory types — payday, action_space, * dice_space, roll_table_ref, inline_table, cash_bonus, event, choice, stop * die: 'D100'|'D20'|'D10'|'D8'|'D6'|'D2'|null — what to roll to resolve this tile * externalTables: source_doc_id[] into shared/rollTables.js (0-3 entries) * statsTouched: string[] hint from the source data, informational only * next: id of the following space (absent only on the synthetic 'finish') * choices: NOT set on any tile yet (no real branch destinations are known) — * shared/game.js only pauses a 'choice'/'stop' space for a decision when * `choices` is non-empty, so today every one of these is a harmless * pass-through, not a dead end. */ import tileInventory from './tileInventory.js'; const TEMP_SEGMENT_ORDER = [ 'starting_strip', 'career', 'investment', 'investment_bottom', 'high_risk', 'gap_year', 'education', 'relationship_top', 'relationship_bottom', 'retirement_top', 'retirement_middle', 'retirement_bottom', ]; const segmentsById = Object.fromEntries(tileInventory.segments.map((s) => [s.id, s])); function buildSegmentSpaces(segmentId, nextAfterSegment) { const segment = segmentsById[segmentId]; if (!segment) throw new Error(`Unknown segment id in TEMP_SEGMENT_ORDER: ${segmentId}`); return segment.tiles.map((tile, i) => ({ id: `${segmentId}_${i}`, type: tile.type, label: tile.name, die: tile.die ?? null, externalTables: tile.external_tables ?? [], statsTouched: tile.stats_touched ?? [], next: i < segment.tiles.length - 1 ? `${segmentId}_${i + 1}` : nextAfterSegment, })); } const spaceList = TEMP_SEGMENT_ORDER.flatMap((segmentId, i) => { const isLastSegment = i === TEMP_SEGMENT_ORDER.length - 1; const nextAfterSegment = isLastSegment ? 'finish' : `${TEMP_SEGMENT_ORDER[i + 1]}_0`; return buildSegmentSpaces(segmentId, nextAfterSegment); }); spaceList.push({ id: 'finish', type: 'finish', label: 'Finish', die: null, externalTables: [], statsTouched: [], // no `next` — this is the temporary end of TEMP_SEGMENT_ORDER, not a real // win-condition tile from the source data. }); export const board = { id: 'life-journey-full-v1', startSpaceId: `${TEMP_SEGMENT_ORDER[0]}_0`, spaces: Object.fromEntries(spaceList.map((space) => [space.id, space])), };