fix: scope blue board coverage to selected unit members
Publish GitHub Pages output / publish (push) Successful in 48s
Publish GitHub Pages output / publish (push) Successful in 48s
This commit is contained in:
@@ -94,6 +94,51 @@ test('큰 노드를 덮는 카드가 부족하면 파란 소켓을 비우거나
|
||||
}
|
||||
});
|
||||
|
||||
test('편성 밖 파란 소켓은 필수 배치에서 제외하고 여분 카드로도 빈 슬롯을 채우지 않는다', () => {
|
||||
for (const side of [-1, 1]) {
|
||||
const scopedSource = blueSource(side);
|
||||
scopedSource.members = ['okayu', 'korone', 'member'].map((id) => ({ id, positionGroupId: 'model' }));
|
||||
const boards = Object.fromEntries(scopedSource.members.map(({ id }) => [id, ['S-blue', 'B-large']]));
|
||||
const coveringCard = { ...rightCard, connect: [{ level: 1, effectPermilUp: 1000, extent: [{ x: -side * 2, y: 0 }] }] };
|
||||
for (const cards of [[coveringCard], [coveringCard, { ...coveringCard, id: 'spare' }]]) {
|
||||
const result = optimizeBoardConnectionCards(scopedSource, boards, cards, {
|
||||
requireBlueActivationCoverage: ['member'],
|
||||
preservePlacementOnTie: () => true,
|
||||
placementWeight: () => 0,
|
||||
placementTieWeight: (_card, memberId, socketId) => memberId === 'member' && socketId === 'S-blue' ? 6 : 0
|
||||
});
|
||||
assert.equal(result.assignments.length, 1);
|
||||
assert.equal(result.assignments[0].memberId, 'member');
|
||||
assert.equal(result.assignments[0].socketId, 'S-blue');
|
||||
}
|
||||
assert.throws(() => optimizeBoardConnectionCards(scopedSource, boards, [], {
|
||||
requireBlueActivationCoverage: ['member'], placementWeight: () => 0
|
||||
}), /큰 발동률 노드를 포함할 수 없어/);
|
||||
}
|
||||
});
|
||||
|
||||
test('편성 밖 보드의 점수 기여와 동률인 기존 배치는 유지한다', () => {
|
||||
const scopedSource = blueSource(1);
|
||||
scopedSource.members = ['member', 'outsider'].map((id) => ({ id, positionGroupId: 'model' }));
|
||||
const cards = ['required', 'global', 'existing'].map((id) => ({
|
||||
id, awakening: 0, connect: [{ level: 1, effectPermilUp: 1000, extent: [{ x: -2, y: 0 }] }]
|
||||
}));
|
||||
const result = optimizeBoardConnectionCards(scopedSource, {
|
||||
member: ['S-blue', 'B-large'], outsider: ['S-blue', 'B-large']
|
||||
}, cards, {
|
||||
requireBlueActivationCoverage: ['member'],
|
||||
currentPlacements: { outsider: { 'S-blue': 'existing' } },
|
||||
preservePlacementOnTie: () => true,
|
||||
placementWeight: (card, memberId, socketId) =>
|
||||
card.id === 'global' && memberId === 'outsider' && socketId === 'S-center' ? 100 : 0,
|
||||
placementTieWeight: (_card, memberId, socketId) => memberId === 'member' && socketId === 'S-blue' ? 6 : 0
|
||||
});
|
||||
assert.deepEqual(result.placements, {
|
||||
member: { 'S-blue': 'required' }, outsider: { 'S-center': 'global', 'S-blue': 'existing' }
|
||||
});
|
||||
assert.equal(new Set(result.assignments.map(({ cardId }) => cardId)).size, 3);
|
||||
});
|
||||
|
||||
test('모양과 수치가 같은 카드는 기존 배치를 유지하고 중복 배치하지 않는다', () => {
|
||||
const cards = ['a', 'b', 'c'].map((id) => ({ ...rightCard, id }));
|
||||
const currentPlacements = { member: { 'S-center': 'c', 'S-right': 'a' } };
|
||||
|
||||
@@ -52,7 +52,8 @@ export type BoardConnectionOptimizationOptions = {
|
||||
targetMemberId?: string;
|
||||
requireSoloSongBonus?: boolean;
|
||||
requireGroupSongBonus?: boolean;
|
||||
requireBlueActivationCoverage?: boolean;
|
||||
/** true covers every member; a member ID list scopes coverage to the current unit. */
|
||||
requireBlueActivationCoverage?: boolean | readonly string[];
|
||||
placementWeight?: (card: OptimizableConnectionCard, memberId: string, socketId: string) => number;
|
||||
placementPriorityWeight?: (card: OptimizableConnectionCard, memberId: string, socketId: string) => number;
|
||||
placementTieWeight?: (card: OptimizableConnectionCard, memberId: string, socketId: string) => number;
|
||||
@@ -137,7 +138,9 @@ export function optimizeBoardConnectionCards(
|
||||
// Large blue activation nodes must be in the card's actual extent, even
|
||||
// when inactive. Identify the blue side from coordinates, not left/right.
|
||||
const requiredNodes = slots.map(({ member, socket, positions }) =>
|
||||
options.requireBlueActivationCoverage && socket.x !== 0
|
||||
(options.requireBlueActivationCoverage === true
|
||||
|| (Array.isArray(options.requireBlueActivationCoverage) && options.requireBlueActivationCoverage.includes(member.id)))
|
||||
&& socket.x !== 0
|
||||
? positions.filter((position) => {
|
||||
const node = nodeForMember(source, position.groupId, member.id);
|
||||
return position.groupId.startsWith('B-') && position.x * socket.x > 0
|
||||
|
||||
Reference in New Issue
Block a user