Files
HolodoriCalc/src/lib/models/analysis-history.ts
T
dal4segno 0af64052c6
Publish GitHub Pages output / publish (push) Successful in 41s
feat: support every song difficulty including Easy and Normal
2026-09-07 14:18:10 +09:00

39 lines
2.2 KiB
TypeScript

import type { DifficultyKey } from '../data/difficulty.ts';
import type { CooldownReduction, ExactOptimizationResult } from '../engine/types.ts';
export type AnalysisSettings = {
songId: string; difficulty: DifficultyKey; cardIds: string[]; awakenings: number[];
fixedCooldownReductions?: (CooldownReduction | null)[];
allBlueNodes?: boolean[]; generationBonusOverrides?: (number | null)[];
songScoreBonusOverride?: number | null; leaderCharacterId: string; leaderOutfitCardId: string;
};
export type GrowthSnapshot = {
collection: Record<string, { owned?: boolean; awakening?: number }>;
memberBoards: Record<string, string[]>;
boardCards: Record<string, Record<string, string>>;
memoryCount: number; memberPowerUpPercent: number;
};
export type StoredResult = Omit<ExactOptimizationResult, 'notes' | 'scoreBySecond'>;
export type AnalysisCapture = {
settings: AnalysisSettings; growth: GrowthSnapshot; title: string; durationSeconds: number;
overallPower: number; analyzedAt: string;
};
export type AnalysisRecord = Omit<AnalysisCapture, 'growth'> & {
id: string; name: string; snapshotId: string; result: StoredResult;
};
export function compactResult(result: ExactOptimizationResult): StoredResult {
const { notes, scoreBySecond, ...stored } = result;
return structuredClone(stored);
}
// Object insertion order and board selection order must not create duplicate snapshots.
export function snapshotKey(value: unknown): string {
if (Array.isArray(value)) return JSON.stringify(value.map((item) => snapshotKey(item)).sort());
if (value && typeof value === 'object') return JSON.stringify(Object.entries(value).sort(([a], [b]) => a.localeCompare(b)).map(([key, item]) => [key, snapshotKey(item)]));
return JSON.stringify(value) ?? 'null';
}
export function currentGrowthSettings(settings: AnalysisSettings, growth: GrowthSnapshot): AnalysisSettings {
const missing = settings.cardIds.filter((id) => !growth.collection[id]?.owned);
if (missing.length) throw new Error('현재 보유 데이터에 없는 편성 카드가 있습니다. 보유 카드와 개화를 등록한 후 비교해 주세요.');
return { ...structuredClone(settings), awakenings: settings.cardIds.map((id) => growth.collection[id]?.awakening ?? 0) };
}