FAILURE MAP
← Case archive

FA-83441 / Card game rule engines / Open access

Bag penalty discards bags beyond ten · case 01

Twelve bags reset to zero instead of two.

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

ROOT CAUSE

The penalty branch zeroes the bag count.

VERIFIED REPAIR

Subtract ten bags per penalty and keep the remainder.

Unsuccessful approach: Penalising only above ten lets a team sit at exactly ten bags.

Case contract

Input [[bid1, bid2], [tricks1, tricks2], bags_before]. Nil (0) bids score +100 if the player took no tricks, else -100 and their tricks become bags. Other bids combine into a contract made by the non-nil players tricks: made -> 10*bid + 1 per overtrick (overtricks are bags); set -> -10*bid. Every 10 accumulated bags costs 100 and removes 10 bags. Return [score_delta, bags].

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

N = 1
observations = []
def solve(x):
    bids, tricks, bags = x
    score = 0
    contract = 0
    made = 0
    for b, t in zip(bids, tricks):
        if b == 0:
            if t == 0:
                score += 100
            else:
                score -= 100
                bags += t
        else:
            contract += b
            made += t
    if made >= contract:
        score += 10 * contract
        over = made - contract
        score += over
        bags += over
    else:
        score -= 10 * contract
    if bags >= 10:
        score -= 100
        bags = 0
    return [score, bags]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[[6, 1], [11, 1], 8], [-25, 3]], [[[0, 2], [12, 1], 4], [-220, 6]], [[[3, 5], [1, 12], 3], [85, 8]], [[[5, 5], [12, 1], 1], [103, 4]], [[[0, 4], [3, 10], 5], [-154, 4]], [[[3, 6], [3, 8], 9], [-8, 1]], [[[5, 5], [12, 0], 5], [102, 7]], [[[5, 1], [12, 1], 3], [-33, 0]]], [[[[0, 2], [12, 1], 4], [-220, 6]], [[[4, 0], [1, 8], 8], [-240, 6]], [[[1, 0], [9, 2], 4], [-182, 4]], [[[5, 1], [6, 7], 3], [-33, 0]], [[[1, 4], [3, 8], 0], [56, 6]], [[[1, 6], [2, 0], 5], [-70, 5]], [[[4, 5], [9, 4], 4], [94, 8]], [[[6, 0], [0, 10], 0], [-260, 0]]], [[[[4, 0], [1, 8], 8], [-240, 6]], [[[1, 5], [7, 0], 2], [61, 3]], [[[3, 4], [11, 1], 1], [75, 6]], [[[3, 1], [12, 0], 9], [-52, 7]], [[[5, 6], [7, 3], 6], [-110, 6]], [[[6, 0], [8, 3], 7], [-138, 2]], [[[2, 5], [13, 0], 1], [76, 7]], [[[1, 1], [7, 4], 1], [-71, 0]]], [[[[1, 4], [6, 4], 5], [-45, 0]], [[[6, 0], [8, 3], 7], [-138, 2]], [[[0, 4], [1, 4], 9], [-160, 0]], [[[6, 2], [3, 4], 8], [-80, 8]], [[[3, 2], [8, 2], 6], [-45, 1]], [[[3, 4], [7, 2], 9], [-28, 1]], [[[3, 5], [7, 3], 2], [82, 4]], [[[5, 3], [7, 2], 7], [81, 8]]], [[[[3, 4], [7, 2], 9], [-28, 1]], [[[2, 2], [10, 1], 9], [-53, 6]], [[[3, 5], [9, 2], 5], [83, 8]], [[[5, 3], [7, 5], 2], [84, 6]], [[[6, 2], [8, 0], 9], [80, 9]], [[[3, 0], [2, 0], 9], [70, 9]], [[[6, 4], [1, 10], 5], [101, 6]], [[[5, 1], [12, 1], 3], [-33, 0]]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("team score 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
team score case 0[-25, 0][-25, 3]Failed
team score case 1[-220, 0][-220, 6]Failed
team score case 2[85, 8][85, 8]Passed
team score case 3[103, 4][103, 4]Passed
team score case 4[-154, 0][-154, 4]Failed
team score case 5[-8, 0][-8, 1]Failed
team score case 6[102, 7][102, 7]Passed
team score case 7[-33, 0][-33, 0]Passed

SHA-256 / ccf12418676c32f7c2b020b877762f76446b5dfc615b9f973f26a5a480d9bcc4

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    bids, tricks, bags = x
    score = 0
    contract = 0
    made = 0
    for b, t in zip(bids, tricks):
        if b == 0:
            if t == 0:
                score += 100
            else:
                score -= 100
                bags += t
        else:
            contract += b
            made += t
    if made >= contract:
        score += 10 * contract
        over = made - contract
        score += over
        bags += over
    else:
        score -= 10 * contract
    while bags > 10:
        score -= 100
        bags -= 10
    return [score, bags]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[[6, 1], [11, 1], 8], [-25, 3]], [[[0, 2], [12, 1], 4], [-220, 6]], [[[3, 5], [1, 12], 3], [85, 8]], [[[5, 5], [12, 1], 1], [103, 4]], [[[0, 4], [3, 10], 5], [-154, 4]], [[[3, 6], [3, 8], 9], [-8, 1]], [[[5, 5], [12, 0], 5], [102, 7]], [[[5, 1], [12, 1], 3], [-33, 0]]], [[[[0, 2], [12, 1], 4], [-220, 6]], [[[4, 0], [1, 8], 8], [-240, 6]], [[[1, 0], [9, 2], 4], [-182, 4]], [[[5, 1], [6, 7], 3], [-33, 0]], [[[1, 4], [3, 8], 0], [56, 6]], [[[1, 6], [2, 0], 5], [-70, 5]], [[[4, 5], [9, 4], 4], [94, 8]], [[[6, 0], [0, 10], 0], [-260, 0]]], [[[[4, 0], [1, 8], 8], [-240, 6]], [[[1, 5], [7, 0], 2], [61, 3]], [[[3, 4], [11, 1], 1], [75, 6]], [[[3, 1], [12, 0], 9], [-52, 7]], [[[5, 6], [7, 3], 6], [-110, 6]], [[[6, 0], [8, 3], 7], [-138, 2]], [[[2, 5], [13, 0], 1], [76, 7]], [[[1, 1], [7, 4], 1], [-71, 0]]], [[[[1, 4], [6, 4], 5], [-45, 0]], [[[6, 0], [8, 3], 7], [-138, 2]], [[[0, 4], [1, 4], 9], [-160, 0]], [[[6, 2], [3, 4], 8], [-80, 8]], [[[3, 2], [8, 2], 6], [-45, 1]], [[[3, 4], [7, 2], 9], [-28, 1]], [[[3, 5], [7, 3], 2], [82, 4]], [[[5, 3], [7, 2], 7], [81, 8]]], [[[[3, 4], [7, 2], 9], [-28, 1]], [[[2, 2], [10, 1], 9], [-53, 6]], [[[3, 5], [9, 2], 5], [83, 8]], [[[5, 3], [7, 5], 2], [84, 6]], [[[6, 2], [8, 0], 9], [80, 9]], [[[3, 0], [2, 0], 9], [70, 9]], [[[6, 4], [1, 10], 5], [101, 6]], [[[5, 1], [12, 1], 3], [-33, 0]]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("team score 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
team score case 0[-25, 3][-25, 3]Passed
team score case 1[-220, 6][-220, 6]Passed
team score case 2[85, 8][85, 8]Passed
team score case 3[103, 4][103, 4]Passed
team score case 4[-154, 4][-154, 4]Passed
team score case 5[-8, 1][-8, 1]Passed
team score case 6[102, 7][102, 7]Passed
team score case 7[67, 10][-33, 0]Failed

SHA-256 / 5977eb90dddfec4042ca23a8b440076ae5a94abeaf7fac5b01a33458626939fc

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    bids, tricks, bags = x
    score = 0
    contract = 0
    made = 0
    for b, t in zip(bids, tricks):
        if b == 0:
            if t == 0:
                score += 100
            else:
                score -= 100
                bags += t
        else:
            contract += b
            made += t
    if made >= contract:
        score += 10 * contract
        over = made - contract
        score += over
        bags += over
    else:
        score -= 10 * contract
    while bags >= 10:
        score -= 100
        bags -= 10
    return [score, bags]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[[6, 1], [11, 1], 8], [-25, 3]], [[[0, 2], [12, 1], 4], [-220, 6]], [[[3, 5], [1, 12], 3], [85, 8]], [[[5, 5], [12, 1], 1], [103, 4]], [[[0, 4], [3, 10], 5], [-154, 4]], [[[3, 6], [3, 8], 9], [-8, 1]], [[[5, 5], [12, 0], 5], [102, 7]], [[[5, 1], [12, 1], 3], [-33, 0]]], [[[[0, 2], [12, 1], 4], [-220, 6]], [[[4, 0], [1, 8], 8], [-240, 6]], [[[1, 0], [9, 2], 4], [-182, 4]], [[[5, 1], [6, 7], 3], [-33, 0]], [[[1, 4], [3, 8], 0], [56, 6]], [[[1, 6], [2, 0], 5], [-70, 5]], [[[4, 5], [9, 4], 4], [94, 8]], [[[6, 0], [0, 10], 0], [-260, 0]]], [[[[4, 0], [1, 8], 8], [-240, 6]], [[[1, 5], [7, 0], 2], [61, 3]], [[[3, 4], [11, 1], 1], [75, 6]], [[[3, 1], [12, 0], 9], [-52, 7]], [[[5, 6], [7, 3], 6], [-110, 6]], [[[6, 0], [8, 3], 7], [-138, 2]], [[[2, 5], [13, 0], 1], [76, 7]], [[[1, 1], [7, 4], 1], [-71, 0]]], [[[[1, 4], [6, 4], 5], [-45, 0]], [[[6, 0], [8, 3], 7], [-138, 2]], [[[0, 4], [1, 4], 9], [-160, 0]], [[[6, 2], [3, 4], 8], [-80, 8]], [[[3, 2], [8, 2], 6], [-45, 1]], [[[3, 4], [7, 2], 9], [-28, 1]], [[[3, 5], [7, 3], 2], [82, 4]], [[[5, 3], [7, 2], 7], [81, 8]]], [[[[3, 4], [7, 2], 9], [-28, 1]], [[[2, 2], [10, 1], 9], [-53, 6]], [[[3, 5], [9, 2], 5], [83, 8]], [[[5, 3], [7, 5], 2], [84, 6]], [[[6, 2], [8, 0], 9], [80, 9]], [[[3, 0], [2, 0], 9], [70, 9]], [[[6, 4], [1, 10], 5], [101, 6]], [[[5, 1], [12, 1], 3], [-33, 0]]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("team score 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
team score case 0[-25, 3][-25, 3]Passed
team score case 1[-220, 6][-220, 6]Passed
team score case 2[85, 8][85, 8]Passed
team score case 3[103, 4][103, 4]Passed
team score case 4[-154, 4][-154, 4]Passed
team score case 5[-8, 1][-8, 1]Passed
team score case 6[102, 7][102, 7]Passed
team score case 7[-33, 0][-33, 0]Passed

SHA-256 / 43892ac272b7825df13ce4cdee6a01292a5ca72239f3a739359a5ea0de72a4e7

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:21.565259+00:00.

Case digest / bca9c09f3c829c85187b4935fa711b3e9f2717f4a61e6ca8a5834f4b52a5d8bc