FA-83671 / Card game rule engines / Open access
A banker natural does not stop the player from drawing · case 01
Player draws against a banker 8 or 9.
ROOT CAUSE
The natural check only looks at the player hand.
VERIFIED REPAIR
Either side holding 8 or 9 ends the coup.
Unsuccessful approach: Treating only banker 9 as a natural lets the player draw against banker 8.
Case contract
Input [player_cards, banker_cards, next_shoe_cards]. Values A=1, 2-9 pip, T/J/Q/K 0; totals mod 10. A natural 8/9 on either side stops the coup. Player draws on 0-5. If player stood, banker draws on 0-5; otherwise banker draws on 0-2, on 3 unless the player third card is 8, on 4 vs 2-7, on 5 vs 4-7, on 6 vs 6-7. Return [player_total, banker_total, winner, cards_drawn].
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):
p, b, shoe = x
def val(c):
r = c[0]
if r == 'A':
return 1
if r in 'TJQK':
return 0
return int(r)
def tot(h):
return sum(val(c) for c in h) % 10
p = list(p)
b = list(b)
k = 0
pt, bt = tot(p), tot(b)
if pt < 8:
third = None
if pt <= 5:
p.append(shoe[k])
k += 1
third = val(p[-1])
if third is None:
draw = bt <= 5
elif bt <= 2:
draw = True
elif bt == 3:
draw = third != 8
elif bt == 4:
draw = 2 <= third <= 7
elif bt == 5:
draw = 4 <= third <= 7
elif bt == 6:
draw = 6 <= third <= 7
else:
draw = False
if draw:
b.append(shoe[k])
k += 1
pt, bt = tot(p), tot(b)
winner = 'player' if pt > bt else 'banker' if bt > pt else 'tie'
return [pt, bt, winner, k]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[['6C', '8D'], ['3H', 'TS'], ['9D', 'QS']], [3, 3, 'tie', 2]], [[['JD', '4H'], ['QC', '8D'], ['TS', '7H']], [4, 8, 'banker', 0]], [[['2H', '8C'], ['7C', 'JS'], ['2C', '7D']], [2, 7, 'banker', 1]], [[['2C', '9D'], ['7C', 'JH'], ['2S', '8H']], [3, 7, 'banker', 1]], [[['5C', '3C'], ['TC', '5H'], ['AC', 'TH']], [8, 5, 'player', 0]], [[['7C', '2C'], ['6H', '3S'], ['AH', '5S']], [9, 9, 'tie', 0]], [[['KC', 'JD'], ['TC', 'TD'], ['AH', '4S']], [1, 4, 'banker', 2]], [[['JD', 'QD'], ['7S', 'AC'], ['5C', '6H']], [0, 8, 'banker', 0]]], [[[['6S', 'QD'], ['6C', '7D'], ['7S', '4D']], [6, 0, 'player', 1]], [[['7H', '3D'], ['JS', 'JH'], ['6H', 'AC']], [6, 1, 'player', 2]], [[['2S', '2C'], ['AS', '7D'], ['2H', '9H']], [4, 8, 'banker', 0]], [[['KC', '6H'], ['9D', 'QS'], ['2C', 'KD']], [6, 9, 'banker', 0]], [[['5S', '6C'], ['6S', '3S'], ['KC', 'KH']], [1, 9, 'banker', 0]], [[['9C', '2H'], ['JC', 'JS'], ['TH', 'QC']], [1, 0, 'player', 2]], [[['4S', '8H'], ['9C', 'KD'], ['JH', 'AD']], [2, 9, 'banker', 0]], [[['KS', 'QH'], ['4C', '4D'], ['4C', '5S']], [0, 8, 'banker', 0]]], [[[['4C', '5S'], ['6S', '4H'], ['QC', '3C']], [9, 0, 'player', 0]], [[['5H', '2C'], ['TD', '6C'], ['7S', 'KC']], [7, 6, 'player', 0]], [[['2C', '4D'], ['8D', '3H'], ['KS', '6C']], [6, 1, 'player', 1]], [[['6S', 'QD'], ['8H', '9D'], ['3S', 'TD']], [6, 7, 'banker', 0]], [[['3H', 'TD'], ['QS', '5C'], ['5D', 'AD']], [8, 6, 'player', 2]], [[['6S', 'JS'], ['4D', '6D'], ['2C', 'KD']], [6, 2, 'player', 1]], [[['5H', '5S'], ['AC', '7C'], ['KC', 'KH']], [0, 8, 'banker', 0]], [[['3H', '2D'], ['KH', '8H'], ['3C', 'QC']], [5, 8, 'banker', 0]]], [[[['8D', 'TH'], ['QS', '9S'], ['3S', '9H']], [8, 9, 'banker', 0]], [[['AS', '5H'], ['5D', '9D'], ['7S', '5S']], [6, 1, 'player', 1]], [[['7C', 'JD'], ['2H', 'KC'], ['JS', 'AS']], [7, 2, 'player', 1]], [[['TH', '8C'], ['2C', '7H'], ['JH', '4D']], [8, 9, 'banker', 0]], [[['TC', '5D'], ['JC', '7S'], ['7C', '4C']], [2, 7, 'banker', 1]], [[['AS', '5H'], ['6C', '8C'], ['7D', '9S']], [6, 1, 'player', 1]], [[['6S', '9D'], ['4S', '5S'], ['4D', 'AC']], [5, 9, 'banker', 0]], [[['JH', 'AD'], ['7D', 'AC'], ['TS', '5D']], [1, 8, 'banker', 0]]], [[[['5S', 'JS'], ['KH', 'TC'], ['4C', '9S']], [9, 9, 'tie', 2]], [[['9H', '9S'], ['TS', '4S'], ['TD', 'TC']], [8, 4, 'player', 0]], [[['9D', '9S'], ['2S', '6D'], ['6S', '4C']], [8, 8, 'tie', 0]], [[['2S', '9H'], ['7H', 'AS'], ['AH', '5H']], [1, 8, 'banker', 0]], [[['2C', '6H'], ['3D', 'TH'], ['QD', 'KS']], [8, 3, 'player', 0]], [[['2S', '2H'], ['3C', '9D'], ['KH', '6C']], [4, 8, 'banker', 2]], [[['JC', '5H'], ['AH', '3D'], ['2H', '9H']], [7, 3, 'player', 2]], [[['QS', 'TD'], ['AS', '7S'], ['KS', 'JH']], [0, 8, 'banker', 0]]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
check("coup 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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| coup case 0 | [3, 3, 'tie', 2] | [3, 3, 'tie', 2] | Passed |
| coup case 1 | [4, 8, 'banker', 1] | [4, 8, 'banker', 0] | Failed |
| coup case 2 | [2, 7, 'banker', 1] | [2, 7, 'banker', 1] | Passed |
| coup case 3 | [3, 7, 'banker', 1] | [3, 7, 'banker', 1] | Passed |
| coup case 4 | [8, 5, 'player', 0] | [8, 5, 'player', 0] | Passed |
| coup case 5 | [9, 9, 'tie', 0] | [9, 9, 'tie', 0] | Passed |
| coup case 6 | [1, 4, 'banker', 2] | [1, 4, 'banker', 2] | Passed |
| coup case 7 | [5, 8, 'banker', 1] | [0, 8, 'banker', 0] | Failed |
SHA-256 / 6095b7c659d194f1eda6892cd701a6bbb043018f3806b7d65a875fa8f1f5162f
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
p, b, shoe = x
def val(c):
r = c[0]
if r == 'A':
return 1
if r in 'TJQK':
return 0
return int(r)
def tot(h):
return sum(val(c) for c in h) % 10
p = list(p)
b = list(b)
k = 0
pt, bt = tot(p), tot(b)
if pt < 8 and bt < 9:
third = None
if pt <= 5:
p.append(shoe[k])
k += 1
third = val(p[-1])
if third is None:
draw = bt <= 5
elif bt <= 2:
draw = True
elif bt == 3:
draw = third != 8
elif bt == 4:
draw = 2 <= third <= 7
elif bt == 5:
draw = 4 <= third <= 7
elif bt == 6:
draw = 6 <= third <= 7
else:
draw = False
if draw:
b.append(shoe[k])
k += 1
pt, bt = tot(p), tot(b)
winner = 'player' if pt > bt else 'banker' if bt > pt else 'tie'
return [pt, bt, winner, k]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[['6C', '8D'], ['3H', 'TS'], ['9D', 'QS']], [3, 3, 'tie', 2]], [[['JD', '4H'], ['QC', '8D'], ['TS', '7H']], [4, 8, 'banker', 0]], [[['2H', '8C'], ['7C', 'JS'], ['2C', '7D']], [2, 7, 'banker', 1]], [[['2C', '9D'], ['7C', 'JH'], ['2S', '8H']], [3, 7, 'banker', 1]], [[['5C', '3C'], ['TC', '5H'], ['AC', 'TH']], [8, 5, 'player', 0]], [[['7C', '2C'], ['6H', '3S'], ['AH', '5S']], [9, 9, 'tie', 0]], [[['KC', 'JD'], ['TC', 'TD'], ['AH', '4S']], [1, 4, 'banker', 2]], [[['JD', 'QD'], ['7S', 'AC'], ['5C', '6H']], [0, 8, 'banker', 0]]], [[[['6S', 'QD'], ['6C', '7D'], ['7S', '4D']], [6, 0, 'player', 1]], [[['7H', '3D'], ['JS', 'JH'], ['6H', 'AC']], [6, 1, 'player', 2]], [[['2S', '2C'], ['AS', '7D'], ['2H', '9H']], [4, 8, 'banker', 0]], [[['KC', '6H'], ['9D', 'QS'], ['2C', 'KD']], [6, 9, 'banker', 0]], [[['5S', '6C'], ['6S', '3S'], ['KC', 'KH']], [1, 9, 'banker', 0]], [[['9C', '2H'], ['JC', 'JS'], ['TH', 'QC']], [1, 0, 'player', 2]], [[['4S', '8H'], ['9C', 'KD'], ['JH', 'AD']], [2, 9, 'banker', 0]], [[['KS', 'QH'], ['4C', '4D'], ['4C', '5S']], [0, 8, 'banker', 0]]], [[[['4C', '5S'], ['6S', '4H'], ['QC', '3C']], [9, 0, 'player', 0]], [[['5H', '2C'], ['TD', '6C'], ['7S', 'KC']], [7, 6, 'player', 0]], [[['2C', '4D'], ['8D', '3H'], ['KS', '6C']], [6, 1, 'player', 1]], [[['6S', 'QD'], ['8H', '9D'], ['3S', 'TD']], [6, 7, 'banker', 0]], [[['3H', 'TD'], ['QS', '5C'], ['5D', 'AD']], [8, 6, 'player', 2]], [[['6S', 'JS'], ['4D', '6D'], ['2C', 'KD']], [6, 2, 'player', 1]], [[['5H', '5S'], ['AC', '7C'], ['KC', 'KH']], [0, 8, 'banker', 0]], [[['3H', '2D'], ['KH', '8H'], ['3C', 'QC']], [5, 8, 'banker', 0]]], [[[['8D', 'TH'], ['QS', '9S'], ['3S', '9H']], [8, 9, 'banker', 0]], [[['AS', '5H'], ['5D', '9D'], ['7S', '5S']], [6, 1, 'player', 1]], [[['7C', 'JD'], ['2H', 'KC'], ['JS', 'AS']], [7, 2, 'player', 1]], [[['TH', '8C'], ['2C', '7H'], ['JH', '4D']], [8, 9, 'banker', 0]], [[['TC', '5D'], ['JC', '7S'], ['7C', '4C']], [2, 7, 'banker', 1]], [[['AS', '5H'], ['6C', '8C'], ['7D', '9S']], [6, 1, 'player', 1]], [[['6S', '9D'], ['4S', '5S'], ['4D', 'AC']], [5, 9, 'banker', 0]], [[['JH', 'AD'], ['7D', 'AC'], ['TS', '5D']], [1, 8, 'banker', 0]]], [[[['5S', 'JS'], ['KH', 'TC'], ['4C', '9S']], [9, 9, 'tie', 2]], [[['9H', '9S'], ['TS', '4S'], ['TD', 'TC']], [8, 4, 'player', 0]], [[['9D', '9S'], ['2S', '6D'], ['6S', '4C']], [8, 8, 'tie', 0]], [[['2S', '9H'], ['7H', 'AS'], ['AH', '5H']], [1, 8, 'banker', 0]], [[['2C', '6H'], ['3D', 'TH'], ['QD', 'KS']], [8, 3, 'player', 0]], [[['2S', '2H'], ['3C', '9D'], ['KH', '6C']], [4, 8, 'banker', 2]], [[['JC', '5H'], ['AH', '3D'], ['2H', '9H']], [7, 3, 'player', 2]], [[['QS', 'TD'], ['AS', '7S'], ['KS', 'JH']], [0, 8, 'banker', 0]]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
check("coup 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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| coup case 0 | [3, 3, 'tie', 2] | [3, 3, 'tie', 2] | Passed |
| coup case 1 | [4, 8, 'banker', 1] | [4, 8, 'banker', 0] | Failed |
| coup case 2 | [2, 7, 'banker', 1] | [2, 7, 'banker', 1] | Passed |
| coup case 3 | [3, 7, 'banker', 1] | [3, 7, 'banker', 1] | Passed |
| coup case 4 | [8, 5, 'player', 0] | [8, 5, 'player', 0] | Passed |
| coup case 5 | [9, 9, 'tie', 0] | [9, 9, 'tie', 0] | Passed |
| coup case 6 | [1, 4, 'banker', 2] | [1, 4, 'banker', 2] | Passed |
| coup case 7 | [5, 8, 'banker', 1] | [0, 8, 'banker', 0] | Failed |
SHA-256 / 898fe62f0b4dac37dc45e324b733ce34c6fd47f8d2ab9f8f114b689e9ba3bccb
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
p, b, shoe = x
def val(c):
r = c[0]
if r == 'A':
return 1
if r in 'TJQK':
return 0
return int(r)
def tot(h):
return sum(val(c) for c in h) % 10
p = list(p)
b = list(b)
k = 0
pt, bt = tot(p), tot(b)
if pt < 8 and bt < 8:
third = None
if pt <= 5:
p.append(shoe[k])
k += 1
third = val(p[-1])
if third is None:
draw = bt <= 5
elif bt <= 2:
draw = True
elif bt == 3:
draw = third != 8
elif bt == 4:
draw = 2 <= third <= 7
elif bt == 5:
draw = 4 <= third <= 7
elif bt == 6:
draw = 6 <= third <= 7
else:
draw = False
if draw:
b.append(shoe[k])
k += 1
pt, bt = tot(p), tot(b)
winner = 'player' if pt > bt else 'banker' if bt > pt else 'tie'
return [pt, bt, winner, k]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[['6C', '8D'], ['3H', 'TS'], ['9D', 'QS']], [3, 3, 'tie', 2]], [[['JD', '4H'], ['QC', '8D'], ['TS', '7H']], [4, 8, 'banker', 0]], [[['2H', '8C'], ['7C', 'JS'], ['2C', '7D']], [2, 7, 'banker', 1]], [[['2C', '9D'], ['7C', 'JH'], ['2S', '8H']], [3, 7, 'banker', 1]], [[['5C', '3C'], ['TC', '5H'], ['AC', 'TH']], [8, 5, 'player', 0]], [[['7C', '2C'], ['6H', '3S'], ['AH', '5S']], [9, 9, 'tie', 0]], [[['KC', 'JD'], ['TC', 'TD'], ['AH', '4S']], [1, 4, 'banker', 2]], [[['JD', 'QD'], ['7S', 'AC'], ['5C', '6H']], [0, 8, 'banker', 0]]], [[[['6S', 'QD'], ['6C', '7D'], ['7S', '4D']], [6, 0, 'player', 1]], [[['7H', '3D'], ['JS', 'JH'], ['6H', 'AC']], [6, 1, 'player', 2]], [[['2S', '2C'], ['AS', '7D'], ['2H', '9H']], [4, 8, 'banker', 0]], [[['KC', '6H'], ['9D', 'QS'], ['2C', 'KD']], [6, 9, 'banker', 0]], [[['5S', '6C'], ['6S', '3S'], ['KC', 'KH']], [1, 9, 'banker', 0]], [[['9C', '2H'], ['JC', 'JS'], ['TH', 'QC']], [1, 0, 'player', 2]], [[['4S', '8H'], ['9C', 'KD'], ['JH', 'AD']], [2, 9, 'banker', 0]], [[['KS', 'QH'], ['4C', '4D'], ['4C', '5S']], [0, 8, 'banker', 0]]], [[[['4C', '5S'], ['6S', '4H'], ['QC', '3C']], [9, 0, 'player', 0]], [[['5H', '2C'], ['TD', '6C'], ['7S', 'KC']], [7, 6, 'player', 0]], [[['2C', '4D'], ['8D', '3H'], ['KS', '6C']], [6, 1, 'player', 1]], [[['6S', 'QD'], ['8H', '9D'], ['3S', 'TD']], [6, 7, 'banker', 0]], [[['3H', 'TD'], ['QS', '5C'], ['5D', 'AD']], [8, 6, 'player', 2]], [[['6S', 'JS'], ['4D', '6D'], ['2C', 'KD']], [6, 2, 'player', 1]], [[['5H', '5S'], ['AC', '7C'], ['KC', 'KH']], [0, 8, 'banker', 0]], [[['3H', '2D'], ['KH', '8H'], ['3C', 'QC']], [5, 8, 'banker', 0]]], [[[['8D', 'TH'], ['QS', '9S'], ['3S', '9H']], [8, 9, 'banker', 0]], [[['AS', '5H'], ['5D', '9D'], ['7S', '5S']], [6, 1, 'player', 1]], [[['7C', 'JD'], ['2H', 'KC'], ['JS', 'AS']], [7, 2, 'player', 1]], [[['TH', '8C'], ['2C', '7H'], ['JH', '4D']], [8, 9, 'banker', 0]], [[['TC', '5D'], ['JC', '7S'], ['7C', '4C']], [2, 7, 'banker', 1]], [[['AS', '5H'], ['6C', '8C'], ['7D', '9S']], [6, 1, 'player', 1]], [[['6S', '9D'], ['4S', '5S'], ['4D', 'AC']], [5, 9, 'banker', 0]], [[['JH', 'AD'], ['7D', 'AC'], ['TS', '5D']], [1, 8, 'banker', 0]]], [[[['5S', 'JS'], ['KH', 'TC'], ['4C', '9S']], [9, 9, 'tie', 2]], [[['9H', '9S'], ['TS', '4S'], ['TD', 'TC']], [8, 4, 'player', 0]], [[['9D', '9S'], ['2S', '6D'], ['6S', '4C']], [8, 8, 'tie', 0]], [[['2S', '9H'], ['7H', 'AS'], ['AH', '5H']], [1, 8, 'banker', 0]], [[['2C', '6H'], ['3D', 'TH'], ['QD', 'KS']], [8, 3, 'player', 0]], [[['2S', '2H'], ['3C', '9D'], ['KH', '6C']], [4, 8, 'banker', 2]], [[['JC', '5H'], ['AH', '3D'], ['2H', '9H']], [7, 3, 'player', 2]], [[['QS', 'TD'], ['AS', '7S'], ['KS', 'JH']], [0, 8, 'banker', 0]]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
check("coup 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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| coup case 0 | [3, 3, 'tie', 2] | [3, 3, 'tie', 2] | Passed |
| coup case 1 | [4, 8, 'banker', 0] | [4, 8, 'banker', 0] | Passed |
| coup case 2 | [2, 7, 'banker', 1] | [2, 7, 'banker', 1] | Passed |
| coup case 3 | [3, 7, 'banker', 1] | [3, 7, 'banker', 1] | Passed |
| coup case 4 | [8, 5, 'player', 0] | [8, 5, 'player', 0] | Passed |
| coup case 5 | [9, 9, 'tie', 0] | [9, 9, 'tie', 0] | Passed |
| coup case 6 | [1, 4, 'banker', 2] | [1, 4, 'banker', 2] | Passed |
| coup case 7 | [0, 8, 'banker', 0] | [0, 8, 'banker', 0] | Passed |
SHA-256 / b6c221587caba3cd3b889c8d7ca7c680eaccc6f65355280ae328ea43774fe659
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:23.888891+00:00.
Case digest / 2e80c89860a63fc957de39524939d472f74ddd70ae201e7fab52209882156390