import { random } from './core.js'; export const PRODUCTION_PLAN_VERSION = '2026-09-12-r1'; export const PRODUCTION_CAMPAIGN = { id: 'v0.5', revision: 1, chapterSize: 50, chapters: ['初见弯路', '朝内的出口', '绕行花园', '轻轻让路', '环里的风景', '花瓣初开', '交织之间', '两岸来信', '回旋的发现', '层层放行', '走进花心', '曲径相逢', '另一侧的出口', '编织新路', '旋开的花园', '从容穿行', '旧路新发现', '花与回声', '千回百转', '一路盛放'], }; export const EXPERIENCE_KINDS = { tour: { name: '长路巡游', lesson: '点一枚棋子,跟着它沿弯路找到出口。', intent: '直接享受完整行进;多个出口提供连续点击的空间。' }, gate: { name: '清挡放行', lesson: '先让挡路的棋子离开,再放出里面的长路。', intent: '移走清楚可见的挡子,为后面的长路打开出口。' }, contrast: { name: '轻巧反差', lesson: '朝内也有出路,试着转动底盘再出发。', intent: '朝内的目标通过一次旋转接上长路;位置和箭头保持不变。' }, turn: { name: '旋转换路', lesson: '先放出能走的棋子,再转出另一条路。', intent: '棋盘初步释放后,转动轨道建立新的离场机会。' }, stages: { name: '分段释放', lesson: '一片一片清开,让不同区域的路线接连畅通。', intent: '清挡和换路分段展开,经过至少两次换路后放出主路线。' }, }; const families = ['petals', 'orbits', 'spiral', 'switchback', 'weave', 'crossing']; // Teaching introduces a small set of actions. Later blocks vary their beat // length/order; chapter boundaries are production units, not difficulty cliffs. const introduction = [ ['switchback', 'tour', 2, 3], ['orbits', 'tour', 2, 4], ['petals', 'gate', 2, 5], ['spiral', 'contrast', 2, 5], ['weave', 'tour', 2, 4], ['crossing', 'gate', 2, 6], ['orbits', 'turn', 2, 6], ['petals', 'tour', 3, 5], ['switchback', 'gate', 3, 7], ['spiral', 'turn', 3, 7], ]; const beats = [ ['tour', 'gate', 'contrast', 'tour', 'turn', 'gate', 'stages', 'tour', 'gate'], ['gate', 'tour', 'turn', 'contrast', 'gate', 'tour', 'stages', 'turn'], ['contrast', 'gate', 'tour', 'turn', 'stages', 'tour', 'gate'], ]; export function productionSlot(index) { if (!Number.isInteger(index) || index < 0 || index >= 1000) throw new RangeError('Production slot must be 0–999'); const chapter = Math.floor(index / 50), local = index % 50; const rng = random(55012026 + index * 7919); const phrase = beats[(chapter + Math.floor(local / 9)) % beats.length]; let kind = phrase[(local + chapter * 3) % phrase.length]; let family = families[(local + Math.floor(local / 6) * 2 + chapter * 5) % families.length]; let radius = chapter < 2 ? 3 : chapter < 5 ? 3 + (rng() > .65 ? 1 : 0) : 3 + Math.floor(rng() * 3); let target = (kind === 'tour' ? 5 : 8) + Math.min(6, Math.floor(chapter / 3)) + Math.floor(rng() * 4); if (local === 49) { family = 'petals'; kind = chapter < 2 ? 'tour' : 'stages'; radius = chapter < 2 ? 3 : 5; target = chapter < 2 ? 7 : 14; } if (index < introduction.length) [family, kind, radius, target] = introduction[index]; if (index < 30 && kind === 'stages') kind = 'turn'; // A long open route reserves real space. Familiarity permits new relations, // but does not create room for arbitrary extra pieces on a small board. const capacity = ['contrast', 'turn'].includes(kind) ? { 2: 6, 3: 9, 4: 12, 5: 14 } : { 2: 6, 3: 11, 4: 14, 5: 17 }; target = Math.min(target, capacity[radius]); // Chapter-sheet review found 849 and 850 too similar in both silhouette and // release rhythm. A woven breather makes the final layered flower distinct. if (index === 848) { family = 'weave'; kind = 'tour'; radius = 4; target = 8; } return { index, number: index + 1, chapter: chapter + 1, chapterName: PRODUCTION_CAMPAIGN.chapters[chapter], family, kind, radius, target, variant: Math.floor(index / 6), minHeroBends: index === 0 ? 3 : radius === 2 ? 5 : 7, maxHeroBends: radius === 2 ? 22 : radius === 3 ? 36 : 70, seed: 55000000 + index * 1009, phase: chapter < 2 ? 'learn' : chapter < 6 ? 'practice' : chapter < 12 ? 'combine' : 'fluent', }; }