SOURCE / PINNED RELEASE
Made of little things.
Rail Game
- Release
- ccdd5b913413…
- Author-recorded commit
- ddf0122b6acc…
- License
- LICENSE
- Author’s source reference
- nostr://npub1n8ga89w8h6tvwamxusfyzexw8gjy84yxu9rxgnmk955cxtml4ujswzxydd/wss%3A%2F%2Fgit.napplet.soy%2F/n-91ec90c6fdf
Archive hash verified: dad7b678e25f96a3…. The source-to-build association is the author’s claim; it has not been independently rebuilt.
import { STAGES } from './game.js';
export interface Progress { unlocked: number; best: number[] }
export function parseProgress(raw: string | null): Progress {
const fallback = { unlocked: 0, best: STAGES.map(() => 0) };
if (!raw) return fallback;
try {
const value: unknown = JSON.parse(raw);
if (!value || typeof value !== 'object') return fallback;
const data = value as Record<string, unknown>;
return {
unlocked: typeof data.unlocked === 'number' && Number.isInteger(data.unlocked) ? Math.max(0, Math.min(STAGES.length - 1, data.unlocked)) : 0,
best: STAGES.map((_, i) => Array.isArray(data.best) && Number.isSafeInteger(data.best[i]) && data.best[i] >= 0 ? Math.min(9999999, data.best[i]) : 0),
};
} catch { return fallback; }
}
export function mergeProgress(a: Progress, b: Progress): Progress {
return { unlocked: Math.max(a.unlocked, b.unlocked), best: STAGES.map((_, i) => Math.max(a.best[i], b.best[i])) };
}
export function recordRun(progress: Progress, stage: number, score: number, won: boolean): Progress {
return { unlocked: won ? Math.max(progress.unlocked, Math.min(STAGES.length - 1, stage + 1)) : progress.unlocked,
best: progress.best.map((best, i) => i === stage ? Math.max(best, score) : best) };
}
