39 lines
2.2 KiB
TypeScript
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) };
|
|
}
|