feat: add green board efficiency analysis

This commit is contained in:
2026-08-18 18:44:05 +09:00
parent ab23508645
commit 2aefc14547
3 changed files with 581 additions and 18 deletions
+17 -4
View File
@@ -40,6 +40,7 @@ export type BoardEffectsResult = {
};
const stats: readonly UnitStat[] = ['performance', 'technique', 'sense'];
const generationBonusCap = 900;
const emptyStats = (): Record<UnitStat, number> => ({ performance: 0, technique: 0, sense: 0 });
const groupingLabels: Record<string, string> = {
'grp-gen_0': '0기생', 'grp-gen_1': '1기생', 'grp-gen_2': '2기생', 'grp-gen_3': '3기생',
@@ -140,6 +141,7 @@ export function calculateBoardEffects(
let scoreSupportPercent = 0;
let directSongScoreBonusPercent = 0;
const multipliers = connectionMultipliers(summary, memberBoards, connections);
const generationBonusByCardAndGrouping: Record<string, Record<string, number>> = {};
for (const [ownerId, activeGroupIds] of Object.entries(memberBoards)) {
for (const groupId of activeGroupIds) {
@@ -172,9 +174,19 @@ export function calculateBoardEffects(
const destination = effect.type.endsWith('_permil_up') ? rateByCardId : flatByCardId;
const normalizedValue = effect.type.endsWith('_permil_up') ? value / 10 : value;
const effectTargets = targets(effect, ownerId, cards).filter((card) =>
effect.type !== 'all_parameter_up_for_character_grouping' || overrides?.generationBonusByCardId?.[card.id] === undefined
);
const effectTargets = targets(effect, ownerId, cards);
if (effect.type === 'all_parameter_up_for_character_grouping') {
const groupingId = effect.targetId ?? 'unknown-grouping';
for (const card of effectTargets) {
if (overrides?.generationBonusByCardId?.[card.id] !== undefined) continue;
const cardBonuses = generationBonusByCardAndGrouping[card.id] ??= {};
const currentBonus = cardBonuses[groupingId] ?? 0;
const appliedValue = Math.max(0, Math.min(normalizedValue, generationBonusCap - currentBonus));
cardBonuses[groupingId] = currentBonus + appliedValue;
for (const stat of stats) destination[card.id][stat] += appliedValue;
}
continue;
}
for (const card of effectTargets) {
for (const stat of affectedStats(effect.type)) destination[card.id][stat] += normalizedValue;
}
@@ -183,7 +195,8 @@ export function calculateBoardEffects(
for (const [cardId, value] of Object.entries(overrides?.generationBonusByCardId ?? {})) {
if (!flatByCardId[cardId]) continue;
for (const stat of stats) flatByCardId[cardId][stat] += value;
const cappedValue = Math.max(0, Math.min(generationBonusCap, value));
for (const stat of stats) flatByCardId[cardId][stat] += cappedValue;
}
// 쿨타임 감소는 현재 보드 상태가 아니라 최적화 변수다. 모든 멤버가 네 경우를 항상 탐색한다.