FAILURE MAP
← Case archive

FA-83761 / Card game rule engines / Open access

The royal marriage inside a run is scored twice · case 01

A trump run scores 190 instead of 150.

Verified by executionVariant 1 · 8 checks per implementationDownload source bundle ↓JSON ↗

ROOT CAUSE

Marriages in trump are counted without removing those used by runs.

VERIFIED REPAIR

Subtract one royal marriage per run.

Unsuccessful approach: Removing only one marriage for a double run double-counts the second.

Case contract

Input [hand, trump]. Arounds (one of the rank in each suit): A 100, K 80, Q 60, J 40; double around x10. Run in trump (A T K Q J) 150 each; marriages (K+Q same suit) 20, royal marriage in trump 40, but a K+Q used in a run is not also a royal marriage. Pinochle (JD+QS) 40, double pinochle 300. Return the meld total.

Why this case matters

Card-game engines, scoring apps and online tables apply this rule automatically on every hand.

1 / The failure

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
from collections import Counter
N = 1
observations = []
def solve(x):
    hand, trump = x
    cnt = Counter(hand)
    pts = 0
    for r, v in (('A', 100), ('K', 80), ('Q', 60), ('J', 40)):
        k = min(cnt[r + s] for s in 'SHDC')
        if k >= 2:
            pts += v * 10
        elif k == 1:
            pts += v
    runs = min(cnt[r + trump] for r in 'ATKQJ')
    pts += 150 * runs
    for s in 'SHDC':
        m = min(cnt['K' + s], cnt['Q' + s])
        if s == trump:
            pts += 40 * m
        else:
            pts += 20 * m
    p = min(cnt['JD'], cnt['QS'])
    pts += 300 if p == 2 else 40 * p
    return pts
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[['AC', 'AC', 'AD', 'AD', 'AH', 'AH', 'AS', 'AS', 'JD', 'JD', 'QS', 'QS'], 'D'], 1300], [[['9C', '9D', '9S', 'AC', 'AH', 'JH', 'JS', 'KH', 'KH', 'KS', 'QH', 'TD'], 'C'], 20], [[['9D', 'JC', 'JD', 'JD', 'JH', 'KD', 'KS', 'QH', 'QS', 'QS', 'TC', 'TD'], 'H'], 320], [[['AC', 'AC', 'AD', 'AD', 'AH', 'AH', 'AS', 'AS', 'JD', 'JD', 'QS', 'QS'], 'D'], 1300], [[['9S', 'AH', 'AS', 'JC', 'JS', 'KD', 'KS', 'KS', 'QD', 'QS', 'TC', 'TS'], 'S'], 170], [[['AH', 'AH', 'AS', 'AS', 'JH', 'KC', 'KH', 'QH', 'QS', 'TH', 'TH', 'TS'], 'C'], 20], [[['9S', '9S', 'AC', 'JD', 'JD', 'KD', 'KS', 'QD', 'QS', 'QS', 'QS', 'TD'], 'D'], 360], [[['AD', 'AD', 'JD', 'JD', 'JH', 'JS', 'KD', 'KD', 'QD', 'QD', 'TD', 'TD'], 'D'], 300]], [[[['9D', '9H', '9S', 'AD', 'AH', 'JD', 'JS', 'KS', 'QS', 'TD', 'TS', 'TS'], 'C'], 60], [[['9C', 'AC', 'AC', 'AD', 'AH', 'AH', 'JD', 'JH', 'QC', 'QD', 'QH', 'TS'], 'C'], 0], [[['9C', '9D', '9S', 'AD', 'JH', 'JS', 'KC', 'QD', 'QH', 'TC', 'TD', 'TH'], 'D'], 0], [[['AC', 'AC', 'AD', 'AD', 'AH', 'AH', 'AS', 'AS', 'AS', 'QC', 'TC', 'TD'], 'H'], 1000], [[['9C', '9H', 'AC', 'AS', 'JC', 'KD', 'KH', 'QC', 'QH', 'TD', 'TH', 'TH'], 'S'], 20], [[['9D', '9S', 'AS', 'JC', 'JH', 'JS', 'KD', 'KH', 'KS', 'QC', 'QD', 'QS'], 'D'], 60], [[['AC', 'AC', 'JC', 'JD', 'JD', 'JD', 'KC', 'QC', 'QS', 'QS', 'TC', 'TC'], 'C'], 450], [[['AH', 'TH', 'KH', 'QH', 'JH', 'AH', 'TH', 'KH', 'QH', 'JH', '9S', '9D'], 'H'], 300]], [[[['9C', 'AS', 'JC', 'JH', 'KD', 'KD', 'KH', 'KS', 'QS', 'QS', 'TD', 'TH'], 'S'], 40], [[['AH', 'AH', 'JC', 'JH', 'JH', 'KH', 'KH', 'QH', 'QH', 'QS', 'TH', 'TH'], 'C'], 40], [[['AC', 'AC', 'AD', 'AD', 'AH', 'AH', 'AS', 'AS', 'JD', 'JD', 'QS', 'QS'], 'H'], 1300], [[['9C', '9D', 'AC', 'AD', 'AD', 'JD', 'JH', 'KD', 'KD', 'QD', 'QH', 'TD'], 'C'], 20], [[['9D', '9S', 'AD', 'JD', 'JD', 'KS', 'QD', 'QD', 'QH', 'QS', 'QS', 'TH'], 'S'], 340], [[['AC', 'AC', 'AC', 'AD', 'AD', 'AH', 'AH', 'AS', 'AS', 'KC', 'QC', 'TC'], 'D'], 1020], [[['9D', '9D', '9H', 'AC', 'JC', 'JH', 'KC', 'KS', 'QC', 'QD', 'TC', 'TH'], 'C'], 150], [[['AD', 'AD', 'AH', 'JC', 'JD', 'JD', 'KD', 'KD', 'QD', 'QD', 'TD', 'TD'], 'D'], 300]], [[[['9C', '9D', 'AC', 'AH', 'AH', 'KC', 'KD', 'KS', 'QC', 'QD', 'QS', 'TH'], 'H'], 60], [[['9C', '9C', 'AC', 'JD', 'KD', 'KD', 'KH', 'KS', 'QC', 'QH', 'TC', 'TD'], 'H'], 40], [[['9H', 'AC', 'AD', 'AS', 'JH', 'JS', 'KC', 'KD', 'QD', 'QH', 'TC', 'TD'], 'D'], 40], [[['AC', 'AC', 'AD', 'AD', 'AH', 'AH', 'AS', 'AS', 'JC', 'KS', 'QH', 'TS'], 'H'], 1000], [[['9C', '9D', '9D', '9H', 'AC', 'AH', 'JC', 'KC', 'KS', 'TC', 'TD', 'TH'], 'S'], 0], [[['AH', 'AH', 'JH', 'JH', 'JS', 'KH', 'KH', 'QH', 'QH', 'TD', 'TH', 'TH'], 'D'], 40], [[['AD', 'AD', 'JD', 'JD', 'JH', 'JS', 'KD', 'KD', 'QD', 'QD', 'TD', 'TD'], 'D'], 300], [[['AD', 'AS', 'JH', 'JS', 'JS', 'KS', 'KS', 'QD', 'QD', 'QS', 'TS', 'TS'], 'S'], 150]], [[[['9D', '9S', 'AH', 'JH', 'KC', 'KD', 'KS', 'QD', 'QD', 'TC', 'TC', 'TS'], 'D'], 40], [[['9D', 'AC', 'AH', 'JC', 'JH', 'JS', 'KC', 'KH', 'QC', 'TC', 'TH', 'TS'], 'S'], 20], [[['AC', 'AC', 'AD', 'AD', 'AH', 'AH', 'AS', 'AS', 'JD', 'JD', 'QS', 'QS'], 'S'], 1300], [[['AH', 'AH', 'JH', 'JH', 'KD', 'KD', 'KH', 'KH', 'QH', 'QH', 'TH', 'TH'], 'C'], 40], [[['9C', '9D', '9S', '9S', 'AD', 'AD', 'AH', 'AS', 'JC', 'JD', 'KH', 'QS'], 'C'], 40], [[['9C', '9H', 'AD', 'JC', 'JD', 'JS', 'JS', 'KC', 'KD', 'KH', 'TD', 'TH'], 'D'], 0], [[['9H', 'AC', 'AC', 'AD', 'AS', 'JC', 'KC', 'KD', 'QC', 'QD', 'TC', 'TS'], 'C'], 170], [[['AH', 'TH', 'KH', 'QH', 'JH', 'AH', 'TH', 'KH', 'QH', 'JH', '9S', '9D'], 'H'], 300]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("meld points case %d" % i, solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
meld points case 013001300Passed
meld points case 12020Passed
meld points case 2320320Passed
meld points case 313001300Passed
meld points case 4210170Failed
meld points case 52020Passed
meld points case 6360360Passed
meld points case 7380300Failed

SHA-256 / 3e779543ba6ba4cbe7920884f926d35848bf8fc3eff8626f6557d428d4ab39b5

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
from collections import Counter
N = 1
observations = []
def solve(x):
    hand, trump = x
    cnt = Counter(hand)
    pts = 0
    for r, v in (('A', 100), ('K', 80), ('Q', 60), ('J', 40)):
        k = min(cnt[r + s] for s in 'SHDC')
        if k >= 2:
            pts += v * 10
        elif k == 1:
            pts += v
    runs = min(cnt[r + trump] for r in 'ATKQJ')
    pts += 150 * runs
    for s in 'SHDC':
        m = min(cnt['K' + s], cnt['Q' + s])
        if s == trump:
            m -= 1 if runs else 0
            pts += 40 * m
        else:
            pts += 20 * m
    p = min(cnt['JD'], cnt['QS'])
    pts += 300 if p == 2 else 40 * p
    return pts
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[['AC', 'AC', 'AD', 'AD', 'AH', 'AH', 'AS', 'AS', 'JD', 'JD', 'QS', 'QS'], 'D'], 1300], [[['9C', '9D', '9S', 'AC', 'AH', 'JH', 'JS', 'KH', 'KH', 'KS', 'QH', 'TD'], 'C'], 20], [[['9D', 'JC', 'JD', 'JD', 'JH', 'KD', 'KS', 'QH', 'QS', 'QS', 'TC', 'TD'], 'H'], 320], [[['AC', 'AC', 'AD', 'AD', 'AH', 'AH', 'AS', 'AS', 'JD', 'JD', 'QS', 'QS'], 'D'], 1300], [[['9S', 'AH', 'AS', 'JC', 'JS', 'KD', 'KS', 'KS', 'QD', 'QS', 'TC', 'TS'], 'S'], 170], [[['AH', 'AH', 'AS', 'AS', 'JH', 'KC', 'KH', 'QH', 'QS', 'TH', 'TH', 'TS'], 'C'], 20], [[['9S', '9S', 'AC', 'JD', 'JD', 'KD', 'KS', 'QD', 'QS', 'QS', 'QS', 'TD'], 'D'], 360], [[['AD', 'AD', 'JD', 'JD', 'JH', 'JS', 'KD', 'KD', 'QD', 'QD', 'TD', 'TD'], 'D'], 300]], [[[['9D', '9H', '9S', 'AD', 'AH', 'JD', 'JS', 'KS', 'QS', 'TD', 'TS', 'TS'], 'C'], 60], [[['9C', 'AC', 'AC', 'AD', 'AH', 'AH', 'JD', 'JH', 'QC', 'QD', 'QH', 'TS'], 'C'], 0], [[['9C', '9D', '9S', 'AD', 'JH', 'JS', 'KC', 'QD', 'QH', 'TC', 'TD', 'TH'], 'D'], 0], [[['AC', 'AC', 'AD', 'AD', 'AH', 'AH', 'AS', 'AS', 'AS', 'QC', 'TC', 'TD'], 'H'], 1000], [[['9C', '9H', 'AC', 'AS', 'JC', 'KD', 'KH', 'QC', 'QH', 'TD', 'TH', 'TH'], 'S'], 20], [[['9D', '9S', 'AS', 'JC', 'JH', 'JS', 'KD', 'KH', 'KS', 'QC', 'QD', 'QS'], 'D'], 60], [[['AC', 'AC', 'JC', 'JD', 'JD', 'JD', 'KC', 'QC', 'QS', 'QS', 'TC', 'TC'], 'C'], 450], [[['AH', 'TH', 'KH', 'QH', 'JH', 'AH', 'TH', 'KH', 'QH', 'JH', '9S', '9D'], 'H'], 300]], [[[['9C', 'AS', 'JC', 'JH', 'KD', 'KD', 'KH', 'KS', 'QS', 'QS', 'TD', 'TH'], 'S'], 40], [[['AH', 'AH', 'JC', 'JH', 'JH', 'KH', 'KH', 'QH', 'QH', 'QS', 'TH', 'TH'], 'C'], 40], [[['AC', 'AC', 'AD', 'AD', 'AH', 'AH', 'AS', 'AS', 'JD', 'JD', 'QS', 'QS'], 'H'], 1300], [[['9C', '9D', 'AC', 'AD', 'AD', 'JD', 'JH', 'KD', 'KD', 'QD', 'QH', 'TD'], 'C'], 20], [[['9D', '9S', 'AD', 'JD', 'JD', 'KS', 'QD', 'QD', 'QH', 'QS', 'QS', 'TH'], 'S'], 340], [[['AC', 'AC', 'AC', 'AD', 'AD', 'AH', 'AH', 'AS', 'AS', 'KC', 'QC', 'TC'], 'D'], 1020], [[['9D', '9D', '9H', 'AC', 'JC', 'JH', 'KC', 'KS', 'QC', 'QD', 'TC', 'TH'], 'C'], 150], [[['AD', 'AD', 'AH', 'JC', 'JD', 'JD', 'KD', 'KD', 'QD', 'QD', 'TD', 'TD'], 'D'], 300]], [[[['9C', '9D', 'AC', 'AH', 'AH', 'KC', 'KD', 'KS', 'QC', 'QD', 'QS', 'TH'], 'H'], 60], [[['9C', '9C', 'AC', 'JD', 'KD', 'KD', 'KH', 'KS', 'QC', 'QH', 'TC', 'TD'], 'H'], 40], [[['9H', 'AC', 'AD', 'AS', 'JH', 'JS', 'KC', 'KD', 'QD', 'QH', 'TC', 'TD'], 'D'], 40], [[['AC', 'AC', 'AD', 'AD', 'AH', 'AH', 'AS', 'AS', 'JC', 'KS', 'QH', 'TS'], 'H'], 1000], [[['9C', '9D', '9D', '9H', 'AC', 'AH', 'JC', 'KC', 'KS', 'TC', 'TD', 'TH'], 'S'], 0], [[['AH', 'AH', 'JH', 'JH', 'JS', 'KH', 'KH', 'QH', 'QH', 'TD', 'TH', 'TH'], 'D'], 40], [[['AD', 'AD', 'JD', 'JD', 'JH', 'JS', 'KD', 'KD', 'QD', 'QD', 'TD', 'TD'], 'D'], 300], [[['AD', 'AS', 'JH', 'JS', 'JS', 'KS', 'KS', 'QD', 'QD', 'QS', 'TS', 'TS'], 'S'], 150]], [[[['9D', '9S', 'AH', 'JH', 'KC', 'KD', 'KS', 'QD', 'QD', 'TC', 'TC', 'TS'], 'D'], 40], [[['9D', 'AC', 'AH', 'JC', 'JH', 'JS', 'KC', 'KH', 'QC', 'TC', 'TH', 'TS'], 'S'], 20], [[['AC', 'AC', 'AD', 'AD', 'AH', 'AH', 'AS', 'AS', 'JD', 'JD', 'QS', 'QS'], 'S'], 1300], [[['AH', 'AH', 'JH', 'JH', 'KD', 'KD', 'KH', 'KH', 'QH', 'QH', 'TH', 'TH'], 'C'], 40], [[['9C', '9D', '9S', '9S', 'AD', 'AD', 'AH', 'AS', 'JC', 'JD', 'KH', 'QS'], 'C'], 40], [[['9C', '9H', 'AD', 'JC', 'JD', 'JS', 'JS', 'KC', 'KD', 'KH', 'TD', 'TH'], 'D'], 0], [[['9H', 'AC', 'AC', 'AD', 'AS', 'JC', 'KC', 'KD', 'QC', 'QD', 'TC', 'TS'], 'C'], 170], [[['AH', 'TH', 'KH', 'QH', 'JH', 'AH', 'TH', 'KH', 'QH', 'JH', '9S', '9D'], 'H'], 300]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("meld points case %d" % i, solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
meld points case 013001300Passed
meld points case 12020Passed
meld points case 2320320Passed
meld points case 313001300Passed
meld points case 4170170Passed
meld points case 52020Passed
meld points case 6360360Passed
meld points case 7340300Failed

SHA-256 / 5987e73b213ccba209adf85be84f7308e7e9bd0936daa042bed73e1c2ae914c6

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json
from collections import Counter
N = 1
observations = []
def solve(x):
    hand, trump = x
    cnt = Counter(hand)
    pts = 0
    for r, v in (('A', 100), ('K', 80), ('Q', 60), ('J', 40)):
        k = min(cnt[r + s] for s in 'SHDC')
        if k >= 2:
            pts += v * 10
        elif k == 1:
            pts += v
    runs = min(cnt[r + trump] for r in 'ATKQJ')
    pts += 150 * runs
    for s in 'SHDC':
        m = min(cnt['K' + s], cnt['Q' + s])
        if s == trump:
            m -= runs
            pts += 40 * m
        else:
            pts += 20 * m
    p = min(cnt['JD'], cnt['QS'])
    pts += 300 if p == 2 else 40 * p
    return pts
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[['AC', 'AC', 'AD', 'AD', 'AH', 'AH', 'AS', 'AS', 'JD', 'JD', 'QS', 'QS'], 'D'], 1300], [[['9C', '9D', '9S', 'AC', 'AH', 'JH', 'JS', 'KH', 'KH', 'KS', 'QH', 'TD'], 'C'], 20], [[['9D', 'JC', 'JD', 'JD', 'JH', 'KD', 'KS', 'QH', 'QS', 'QS', 'TC', 'TD'], 'H'], 320], [[['AC', 'AC', 'AD', 'AD', 'AH', 'AH', 'AS', 'AS', 'JD', 'JD', 'QS', 'QS'], 'D'], 1300], [[['9S', 'AH', 'AS', 'JC', 'JS', 'KD', 'KS', 'KS', 'QD', 'QS', 'TC', 'TS'], 'S'], 170], [[['AH', 'AH', 'AS', 'AS', 'JH', 'KC', 'KH', 'QH', 'QS', 'TH', 'TH', 'TS'], 'C'], 20], [[['9S', '9S', 'AC', 'JD', 'JD', 'KD', 'KS', 'QD', 'QS', 'QS', 'QS', 'TD'], 'D'], 360], [[['AD', 'AD', 'JD', 'JD', 'JH', 'JS', 'KD', 'KD', 'QD', 'QD', 'TD', 'TD'], 'D'], 300]], [[[['9D', '9H', '9S', 'AD', 'AH', 'JD', 'JS', 'KS', 'QS', 'TD', 'TS', 'TS'], 'C'], 60], [[['9C', 'AC', 'AC', 'AD', 'AH', 'AH', 'JD', 'JH', 'QC', 'QD', 'QH', 'TS'], 'C'], 0], [[['9C', '9D', '9S', 'AD', 'JH', 'JS', 'KC', 'QD', 'QH', 'TC', 'TD', 'TH'], 'D'], 0], [[['AC', 'AC', 'AD', 'AD', 'AH', 'AH', 'AS', 'AS', 'AS', 'QC', 'TC', 'TD'], 'H'], 1000], [[['9C', '9H', 'AC', 'AS', 'JC', 'KD', 'KH', 'QC', 'QH', 'TD', 'TH', 'TH'], 'S'], 20], [[['9D', '9S', 'AS', 'JC', 'JH', 'JS', 'KD', 'KH', 'KS', 'QC', 'QD', 'QS'], 'D'], 60], [[['AC', 'AC', 'JC', 'JD', 'JD', 'JD', 'KC', 'QC', 'QS', 'QS', 'TC', 'TC'], 'C'], 450], [[['AH', 'TH', 'KH', 'QH', 'JH', 'AH', 'TH', 'KH', 'QH', 'JH', '9S', '9D'], 'H'], 300]], [[[['9C', 'AS', 'JC', 'JH', 'KD', 'KD', 'KH', 'KS', 'QS', 'QS', 'TD', 'TH'], 'S'], 40], [[['AH', 'AH', 'JC', 'JH', 'JH', 'KH', 'KH', 'QH', 'QH', 'QS', 'TH', 'TH'], 'C'], 40], [[['AC', 'AC', 'AD', 'AD', 'AH', 'AH', 'AS', 'AS', 'JD', 'JD', 'QS', 'QS'], 'H'], 1300], [[['9C', '9D', 'AC', 'AD', 'AD', 'JD', 'JH', 'KD', 'KD', 'QD', 'QH', 'TD'], 'C'], 20], [[['9D', '9S', 'AD', 'JD', 'JD', 'KS', 'QD', 'QD', 'QH', 'QS', 'QS', 'TH'], 'S'], 340], [[['AC', 'AC', 'AC', 'AD', 'AD', 'AH', 'AH', 'AS', 'AS', 'KC', 'QC', 'TC'], 'D'], 1020], [[['9D', '9D', '9H', 'AC', 'JC', 'JH', 'KC', 'KS', 'QC', 'QD', 'TC', 'TH'], 'C'], 150], [[['AD', 'AD', 'AH', 'JC', 'JD', 'JD', 'KD', 'KD', 'QD', 'QD', 'TD', 'TD'], 'D'], 300]], [[[['9C', '9D', 'AC', 'AH', 'AH', 'KC', 'KD', 'KS', 'QC', 'QD', 'QS', 'TH'], 'H'], 60], [[['9C', '9C', 'AC', 'JD', 'KD', 'KD', 'KH', 'KS', 'QC', 'QH', 'TC', 'TD'], 'H'], 40], [[['9H', 'AC', 'AD', 'AS', 'JH', 'JS', 'KC', 'KD', 'QD', 'QH', 'TC', 'TD'], 'D'], 40], [[['AC', 'AC', 'AD', 'AD', 'AH', 'AH', 'AS', 'AS', 'JC', 'KS', 'QH', 'TS'], 'H'], 1000], [[['9C', '9D', '9D', '9H', 'AC', 'AH', 'JC', 'KC', 'KS', 'TC', 'TD', 'TH'], 'S'], 0], [[['AH', 'AH', 'JH', 'JH', 'JS', 'KH', 'KH', 'QH', 'QH', 'TD', 'TH', 'TH'], 'D'], 40], [[['AD', 'AD', 'JD', 'JD', 'JH', 'JS', 'KD', 'KD', 'QD', 'QD', 'TD', 'TD'], 'D'], 300], [[['AD', 'AS', 'JH', 'JS', 'JS', 'KS', 'KS', 'QD', 'QD', 'QS', 'TS', 'TS'], 'S'], 150]], [[[['9D', '9S', 'AH', 'JH', 'KC', 'KD', 'KS', 'QD', 'QD', 'TC', 'TC', 'TS'], 'D'], 40], [[['9D', 'AC', 'AH', 'JC', 'JH', 'JS', 'KC', 'KH', 'QC', 'TC', 'TH', 'TS'], 'S'], 20], [[['AC', 'AC', 'AD', 'AD', 'AH', 'AH', 'AS', 'AS', 'JD', 'JD', 'QS', 'QS'], 'S'], 1300], [[['AH', 'AH', 'JH', 'JH', 'KD', 'KD', 'KH', 'KH', 'QH', 'QH', 'TH', 'TH'], 'C'], 40], [[['9C', '9D', '9S', '9S', 'AD', 'AD', 'AH', 'AS', 'JC', 'JD', 'KH', 'QS'], 'C'], 40], [[['9C', '9H', 'AD', 'JC', 'JD', 'JS', 'JS', 'KC', 'KD', 'KH', 'TD', 'TH'], 'D'], 0], [[['9H', 'AC', 'AC', 'AD', 'AS', 'JC', 'KC', 'KD', 'QC', 'QD', 'TC', 'TS'], 'C'], 170], [[['AH', 'TH', 'KH', 'QH', 'JH', 'AH', 'TH', 'KH', 'QH', 'JH', '9S', '9D'], 'H'], 300]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("meld points case %d" % i, solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
meld points case 013001300Passed
meld points case 12020Passed
meld points case 2320320Passed
meld points case 313001300Passed
meld points case 4170170Passed
meld points case 52020Passed
meld points case 6360360Passed
meld points case 7300300Passed

SHA-256 / 9da4cc983f65c36bebec48fcced43e0f1cdd61b65e74b4439ef72182a2255a13

Verification & scope

A bounded toy rule contract stated explicitly in the contract field; cards are two-character codes (rank, suit). Not a complete implementation of any published rulebook or casino table rules. This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.

Observations recorded using Python 3.12.14 at 2026-09-29T14:50:24.582029+00:00.

Case digest / 517727dcc2305a0cb72c4e9aea5a0e5ec9a05581b76b2f664e85b1a9ecc0ab1d