feat: add selectable core resonance pairs

This commit is contained in:
2026-07-11 22:05:33 +09:00
parent 7d3c49ac0b
commit 51529e51c2
9 changed files with 1693 additions and 100 deletions

View File

@@ -9,6 +9,8 @@ const server = await createServer({
try {
const {
compareSortieSynergy,
coreSortieResonanceChainRateForLevel,
coreSortieResonanceMinLevel,
evaluateSortiePursuitPairs,
evaluateSortieSynergy,
firstPursuitRolePreviewSummaries,
@@ -56,6 +58,20 @@ try {
`Unexpected Lv${level} bond bonus: ${JSON.stringify(actual)}`
);
});
assert(coreSortieResonanceMinLevel === 30, `Expected core resonance eligibility to begin at Lv30: ${coreSortieResonanceMinLevel}`);
const coreResonanceBoundaryCases = [
[29, 0],
[30, 8],
[49, 8],
[50, 18],
[69, 18],
[70, 28],
[100, 28]
];
coreResonanceBoundaryCases.forEach(([level, chainRate]) => {
const actual = coreSortieResonanceChainRateForLevel(level);
assert(actual === chainRate, `Unexpected Lv${level} core resonance chain rate: ${actual}`);
});
const members = [
{ id: 'liu-bei', name: '유비', role: 'support', terrainScore: 101 },
@@ -133,6 +149,7 @@ try {
{ id: 'active-70-zeta', title: 'Active Tie', unitIds: ['selected-a', 'selected-b'], level: 70 },
{ id: 'active-70-alpha', title: 'Active Tie', unitIds: ['selected-b', 'selected-a'], level: 70 },
{ id: 'active-50', title: 'Active 50', unitIds: ['selected-a', 'selected-b'], level: 50 },
{ id: 'active-30-core', title: 'Core 30', unitIds: ['selected-a', 'selected-b'], level: 30 },
{ id: 'opportunity-70-zeta', title: 'Zeta Opportunity', unitIds: ['selected-a', 'candidate-70'], level: 70 },
{ id: 'opportunity-70-alpha', title: 'Alpha Opportunity', unitIds: ['candidate-70', 'selected-a'], level: 70 },
{ id: 'opportunity-50-duplicate', title: 'Opportunity 50 Duplicate', unitIds: ['selected-a', 'candidate-70'], level: 50 },
@@ -149,6 +166,11 @@ try {
pursuitPairs.activePairs.map((bond) => `${bond.id}:${bond.chainRate}`).join(',') === 'active-70-alpha:18',
`Expected a selected pair to keep its highest-level bond and resolve level ties by title/id while normalizing duplicate selections: ${JSON.stringify(pursuitPairs.activePairs)}`
);
assert(
pursuitPairs.activePairs.every((bond) => bond.core === false && bond.baseChainRate === bond.chainRate) &&
pursuitPairs.selectableOpportunities.every((bond) => bond.core === false && bond.baseChainRate === bond.chainRate),
`Expected non-designated pursuit pairs to preserve their legacy rates: ${JSON.stringify(pursuitPairs)}`
);
assert(
pursuitPairs.selectableOpportunities.map((bond) => `${bond.id}:${bond.chainRate}`).join(',') === 'opportunity-70-alpha:18,opportunity-50:8',
`Expected opportunities to keep one strongest unordered pair, resolve ties deterministically, expose Lv70/Lv50 rates, and hide Lv49: ${JSON.stringify(pursuitPairs.selectableOpportunities)}`
@@ -181,6 +203,31 @@ try {
promotedPursuitPairs.selectableOpportunities.every((bond) => bond.candidateUnitId !== 'candidate-70'),
`Expected a selected candidate to move from opportunity to active pair: ${JSON.stringify(promotedPursuitPairs)}`
);
const corePursuitPairs = evaluateSortiePursuitPairs({
members: pursuitMembers,
bonds: pursuitBonds,
selectedUnitIds: ['selected-a', 'selected-b', 'candidate-70'],
coreBondId: 'active-30-core'
});
assert(
corePursuitPairs.activePairs[0]?.id === 'active-30-core' &&
corePursuitPairs.activePairs[0].core === true &&
corePursuitPairs.activePairs[0].baseChainRate === 0 &&
corePursuitPairs.activePairs[0].chainRate === 8 &&
corePursuitPairs.activePairs.some((bond) => bond.id === 'opportunity-70-alpha' && !bond.core && bond.chainRate === 18),
`Expected an eligible Lv30 core pair to gain 8% pursuit and sort ahead of stronger ordinary pairs: ${JSON.stringify(corePursuitPairs.activePairs)}`
);
const inactiveCorePursuitPairs = evaluateSortiePursuitPairs({
members: pursuitMembers,
bonds: pursuitBonds,
selectedUnitIds: ['selected-a', 'selected-b'],
coreBondId: 'opportunity-49'
});
assert(
inactiveCorePursuitPairs.activePairs[0]?.id === 'active-70-alpha' &&
inactiveCorePursuitPairs.selectableOpportunities.every((bond) => bond.id !== 'opportunity-49' && !bond.core),
`Expected an ineligible or undeployed core id not to promote a pursuit pair: ${JSON.stringify(inactiveCorePursuitPairs)}`
);
assert(
JSON.stringify({ pursuitMembers, pursuitBonds }) === frozenPursuitInputs,
'Expected pursuit-pair evaluation not to mutate its inputs.'