feat: streamline search results and open captured analyses
Publish GitHub Pages output / publish (push) Successful in 54s
Publish GitHub Pages output / publish (push) Successful in 54s
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
import type { AnalysisCapture, AnalysisSettings, GrowthSnapshot } from './analysis-history.ts';
|
||||
import type { ExactOptimizationResult, ExactSongChart, OptimizerCard, ScoreAchievementProbabilities } from '../engine/types.ts';
|
||||
import { resolveCandidateAwakening } from '../engine/combination-search.ts';
|
||||
|
||||
export const ANALYSIS_TRANSFER_KEY = 'holodori.analysis-transfer.v1';
|
||||
export type AnalysisTransfer = {
|
||||
schemaVersion: 1;
|
||||
source?: 'combination' | 'rating';
|
||||
capture: AnalysisCapture;
|
||||
result: ExactOptimizationResult;
|
||||
cards: OptimizerCard[];
|
||||
chart: ExactSongChart;
|
||||
directSongScoreBonusPercent: number;
|
||||
achievementProbabilities?: ScoreAchievementProbabilities;
|
||||
};
|
||||
|
||||
export type CombinationConditions = Pick<AnalysisSettings, 'songId' | 'difficulty' | 'leaderCharacterId' | 'leaderOutfitCardId' | 'songScoreBonusOverride'> & {
|
||||
fixedCardIds: string[]; fixedAwakenings?: number[];
|
||||
fixedCooldownReductions?: AnalysisSettings['fixedCooldownReductions'];
|
||||
fixedAllBlueNodes?: boolean[]; fixedGenerationBonusOverrides?: (number | null)[];
|
||||
awakening: number; candidateGenerationBonus?: number | null;
|
||||
};
|
||||
|
||||
export function combinationAnalysisSettings(state: CombinationConditions, cardIds: readonly string[], growth: GrowthSnapshot): AnalysisSettings {
|
||||
const slots = cardIds.map(id => state.fixedCardIds.indexOf(id));
|
||||
return {
|
||||
songId: state.songId, difficulty: state.difficulty, cardIds: [...cardIds],
|
||||
awakenings: cardIds.map((id, i) => slots[i] >= 0 ? state.fixedAwakenings?.[slots[i]] ?? 0
|
||||
: resolveCandidateAwakening(state.awakening, Boolean(growth.collection[id]?.owned), growth.collection[id]?.awakening ?? 5)),
|
||||
fixedCooldownReductions: slots.map(slot => slot < 0 ? null : state.fixedCooldownReductions?.[slot] ?? null),
|
||||
allBlueNodes: slots.map(slot => slot < 0 || state.fixedAllBlueNodes?.[slot] === true),
|
||||
generationBonusOverrides: slots.map(slot => slot < 0 ? state.candidateGenerationBonus ?? null : state.fixedGenerationBonusOverrides?.[slot] ?? null),
|
||||
songScoreBonusOverride: state.songScoreBonusOverride ?? null,
|
||||
leaderCharacterId: state.leaderCharacterId, leaderOutfitCardId: state.leaderOutfitCardId
|
||||
};
|
||||
}
|
||||
|
||||
// Match the analysis page's key so a transferred result can flag newer growth data.
|
||||
export function transferredAnalysisKey({ settings: s, growth: g }: AnalysisCapture): string {
|
||||
return JSON.stringify({ songId: s.songId, difficulty: s.difficulty, input: JSON.stringify({
|
||||
selectedCardIds: s.cardIds, selectedAwakenings: s.awakenings,
|
||||
fixedCooldownReductions: s.fixedCooldownReductions, allBlueNodes: s.allBlueNodes,
|
||||
generationBonusOverrides: s.generationBonusOverrides, songScoreBonusOverride: s.songScoreBonusOverride,
|
||||
leaderCharacterId: s.leaderCharacterId, leaderOutfitCardId: s.leaderOutfitCardId,
|
||||
collection: g.collection, memberBoards: g.memberBoards, boardCards: g.boardCards,
|
||||
memoryCount: g.memoryCount, memberPowerUpPercent: g.memberPowerUpPercent
|
||||
}) });
|
||||
}
|
||||
|
||||
export function parseAnalysisTransfer(raw: string): AnalysisTransfer {
|
||||
const value = JSON.parse(raw) as AnalysisTransfer;
|
||||
const ids = value?.capture?.settings?.cardIds;
|
||||
if (value?.schemaVersion !== 1 || !Array.isArray(ids) || ids.length !== 5 || new Set(ids).size !== 5 ||
|
||||
!value.capture.growth || !Array.isArray(value.cards) || value.cards.length !== 5 ||
|
||||
!ids.every(id => value.cards.some(card => card.id === id)) ||
|
||||
!Array.isArray(value.result?.order) || value.result.order.length !== 5 || new Set(value.result.order).size !== 5 ||
|
||||
!value.result.order.every(id => ids.includes(id)) || !Array.isArray(value.result.notes) ||
|
||||
!Array.isArray(value.chart?.notes) || value.chart.songId !== value.capture.settings.songId ||
|
||||
value.chart.difficulty !== value.capture.settings.difficulty || !Number.isFinite(value.directSongScoreBonusPercent)) {
|
||||
throw new Error('전달된 분석 결과를 읽지 못했습니다. 원래 결과 목록에서 다시 열어 주세요.');
|
||||
}
|
||||
return value;
|
||||
}
|
||||
Reference in New Issue
Block a user