Back to Rail Game
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.

src/progress.ts
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) };
}