From 17f371d5ee8abeabcdb4853fc6445a365562059c Mon Sep 17 00:00:00 2001 From: Giancarmine Salucci Date: Sat, 11 Apr 2026 21:20:08 +0200 Subject: [PATCH] fix(SCOPONE-0012): complete iteration 4 - rebalance scopa priority --- src/game/ai.ts | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/game/ai.ts b/src/game/ai.ts index 1fde9de..ab40f8e 100644 --- a/src/game/ai.ts +++ b/src/game/ai.ts @@ -710,7 +710,7 @@ interface TacticalPriorityLadder { const TACTICAL_PRIORITY_WEIGHTS = { scopa: 120000000, settebello: 20000000, - antiScopa: 950000, + antiScopa: 5000000, partnerSetup: 45000, sevenDenial: 2101, denariDenial: 101, @@ -1829,6 +1829,9 @@ function scoreMoveObjectiveBias( const capturedCards = getMoveCollectedCards(move); const threats = getPriorityThreatSummary(summary.projectedTable, projectedHand, tracker, state, playerIdx); const scopaPriority = evaluateSafeScopaPriority(summary.clearsTable, summary.projectedTable, lastPlay, nextIsOpp, threats); + const antiScopaPriority = evaluateAntiScopaPriority(summary.projectedTable, nextIsOpp, threats); + const partnerSetupPriority = evaluatePartnerSetupPriority(summary.projectedTable, nextIsOpp, partnerHandSize, threats); + const immediateTacticalConcession = isImmediateTacticalConcession(summary.projectedTable, nextIsOpp, threats); const openingReleasePriority = move.capture.length === 0 ? evaluateFirstHandOpeningReleasePriority( move.card, @@ -1913,8 +1916,8 @@ function scoreMoveObjectiveBias( bias -= 460; } - bias += evaluateAntiScopaPriority(summary.projectedTable, nextIsOpp, threats) * 34; - bias += evaluatePartnerSetupPriority(summary.projectedTable, nextIsOpp, partnerHandSize, threats) * 34; + bias += antiScopaPriority * 48; + bias += partnerSetupPriority * 8; bias += evaluateSevenDenialPriority(summary.projectedTable, capturedCards, move.capture.length === 0 ? move.card : null, nextIsOpp, race.need7s) * (race.need7s ? 42 : race.sevenRaceLive ? 40 : 36); bias += evaluateDenariDenialPriority(summary.projectedTable, capturedCards, move.capture.length === 0 ? move.card : null, nextIsOpp, race.behindInDenari) * (race.behindInDenari ? 38 : race.denariRaceLive ? 36 : 32); bias += openingReleasePriority * 52; @@ -1936,6 +1939,10 @@ function scoreMoveObjectiveBias( bias -= Math.round(summary.projectedTable.reduce((sum, card) => sum + primieraVal(card), 0) * 1.25); } + if (nextIsOpp && !summary.clearsTable && immediateTacticalConcession) { + bias -= 720; + } + if (move.capture.length === 0) { if (summary.highQuietRelease) bias += 72; bias += summary.sameValueAnchorsRemaining * 44; @@ -2516,7 +2523,11 @@ function scoreControlOverrideCandidate( const summary = summarizeMoveTactics(move, hand, state.table); const projectedHand = hand.filter(card => card.id !== move.card.id); const threats = getPriorityThreatSummary(summary.projectedTable, projectedHand, tracker, state, playerIdx); + const partnerHandSize = state.players[partnerOf(playerIdx)].hand.length; const scopaPriority = evaluateSafeScopaPriority(summary.clearsTable, summary.projectedTable, lastPlay, nextIsOpp, threats); + const antiScopaPriority = evaluateAntiScopaPriority(summary.projectedTable, nextIsOpp, threats); + const partnerSetupPriority = evaluatePartnerSetupPriority(summary.projectedTable, nextIsOpp, partnerHandSize, threats); + const immediateTacticalConcession = isImmediateTacticalConcession(summary.projectedTable, nextIsOpp, threats); const openingReleasePriority = move.capture.length === 0 ? evaluateFirstHandOpeningReleasePriority( move.card, @@ -2535,6 +2546,12 @@ function scoreControlOverrideCandidate( score += summary.projectedTable.length * 48; score += summary.tableSum >= 11 ? 90 + summary.tableSum * 8 : -260; score += scopaPriority * 600; + score += antiScopaPriority * 54; + score += partnerSetupPriority * 8; + + if (nextIsOpp && !summary.clearsTable && immediateTacticalConcession) { + score -= 720; + } if (move.capture.length === 0) { if (summary.highQuietRelease) score += 220;