FA-82191 / Poker hand evaluation / Open access
Full house named by highest rank instead of trips · case 01
Threes full of kings is announced as "Kings full of Threes".
ROOT CAUSE
The two ranks are ordered by rank value rather than by which rank forms the trips.
VERIFIED REPAIR
Name the trips rank first, then the pair rank.
Unsuccessful approach: Swapping the group order names the pair first for every full house.
Case contract
Input: five distinct cards. Return the showdown announcement: "Royal Flush", "Straight Flush, <top> high", "Four <plural>", "Full House, <trips plural> full of <pair plural>", "Flush, <top> high", "Straight, <top> high" (wheel is Five high), "Three <plural>", "Two Pair, <higher plural> and <lower plural>", "Pair of <plural>", "High Card, <top>". Rank names Two..Ace; plurals add "s" except Deuces and Sixes.
Why this case matters
Dealer announcements and hand histories must name the same hand the evaluator paid.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import collections
N = 1
observations = []
def solve(x):
R='23456789TJQKA'
NAME={2:'Two',3:'Three',4:'Four',5:'Five',6:'Six',7:'Seven',8:'Eight',9:'Nine',10:'Ten',11:'Jack',12:'Queen',13:'King',14:'Ace'}
def pl(v): return {2:'Deuces',6:'Sixes'}.get(v, NAME[v]+'s')
vals=sorted((R.index(c[0])+2 for c in x), reverse=True)
cnt=collections.Counter(vals)
groups=sorted(cnt, key=lambda v:(cnt[v],v), reverse=True)
shape=sorted(cnt.values(), reverse=True)
flush=len({c[1] for c in x})==1
wheel=vals==[14,5,4,3,2]
straight=len(cnt)==5 and (vals[0]-vals[4]==4 or wheel)
top=5 if wheel else vals[0]
if straight and flush: return 'Royal Flush' if top==14 else 'Straight Flush, %s high' % NAME[top]
if shape==[4,1]: return 'Four %s' % pl(groups[0])
if shape==[3,2]: return 'Full House, %s full of %s' % (pl(max(cnt)), pl(min(cnt)))
if flush: return 'Flush, %s high' % NAME[vals[0]]
if straight: return 'Straight, %s high' % NAME[top]
if shape==[3,1,1]: return 'Three %s' % pl(groups[0])
if shape==[2,2,1]: return 'Two Pair, %s and %s' % (pl(groups[0]), pl(groups[1]))
if shape==[2,1,1,1]: return 'Pair of %s' % pl(groups[0])
return 'High Card, %s' % NAME[vals[0]]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('pair of sixes', ['6h', '6d', 'Kc', '9s', '2h'], 'Pair of Sixes'),
('pair of deuces', ['2h', '2d', 'Kc', '9s', '5h'], 'Pair of Deuces'),
('wheel', ['Ah', '2d', '3c', '4s', '5h'], 'Straight, Five high'),
('steel wheel', ['As', '2s', '3s', '4s', '5s'], 'Straight Flush, Five high'),
('royal', ['Th', 'Jh', 'Qh', 'Kh', 'Ah'], 'Royal Flush'),
('king-high straight flush', ['9d', 'Td', 'Jd', 'Qd', 'Kd'], 'Straight Flush, King high'),
('threes full of kings', ['3h', '3d', '3c', 'Ks', 'Kh'], 'Full House, Threes full of Kings'),
('kings full of threes', ['Kh', 'Kd', 'Kc', '3s', '3h'], 'Full House, Kings full of Threes')],
[('steel wheel', ['As', '2s', '3s', '4s', '5s'], 'Straight Flush, Five high'),
('royal', ['Th', 'Jh', 'Qh', 'Kh', 'Ah'], 'Royal Flush'),
('king-high straight flush', ['9d', 'Td', 'Jd', 'Qd', 'Kd'], 'Straight Flush, King high'),
('threes full of kings', ['3h', '3d', '3c', 'Ks', 'Kh'], 'Full House, Threes full of Kings'),
('kings full of threes', ['Kh', 'Kd', 'Kc', '3s', '3h'], 'Full House, Kings full of Threes'),
('two pair ace kicker', ['Ah', 'Kd', 'Kc', '7s', '7h'], 'Two Pair, Kings and Sevens'),
('two pair low kicker', ['Kh', 'Kd', '7c', '7s', '2h'], 'Two Pair, Kings and Sevens'),
('pair below high cards', ['Ah', 'Kd', '5c', '5s', '9h'], 'Pair of Fives')],
[('threes full of kings', ['3h', '3d', '3c', 'Ks', 'Kh'], 'Full House, Threes full of Kings'),
('kings full of threes', ['Kh', 'Kd', 'Kc', '3s', '3h'], 'Full House, Kings full of Threes'),
('two pair ace kicker', ['Ah', 'Kd', 'Kc', '7s', '7h'], 'Two Pair, Kings and Sevens'),
('two pair low kicker', ['Kh', 'Kd', '7c', '7s', '2h'], 'Two Pair, Kings and Sevens'),
('pair below high cards', ['Ah', 'Kd', '5c', '5s', '9h'], 'Pair of Fives'),
('high card', ['Ah', 'Jd', '8c', '5s', '3h'], 'High Card, Ace'),
('four nines', ['9h', '9d', '9c', '9s', '2h'], 'Four Nines'),
('flush', ['2c', '7c', '9c', 'Jc', 'Qc'], 'Flush, Queen high')],
[('pair of sixes', ['6h', '6d', 'Kc', '9s', '2h'], 'Pair of Sixes'),
('threes full of kings', ['3h', '3d', '3c', 'Ks', 'Kh'], 'Full House, Threes full of Kings'),
('kings full of threes', ['Kh', 'Kd', 'Kc', '3s', '3h'], 'Full House, Kings full of Threes'),
('high card', ['Ah', 'Jd', '8c', '5s', '3h'], 'High Card, Ace'),
('four nines', ['9h', '9d', '9c', '9s', '2h'], 'Four Nines'),
('flush', ['2c', '7c', '9c', 'Jc', 'Qc'], 'Flush, Queen high'),
('six-high straight', ['2h', '3d', '4c', '5s', '6h'], 'Straight, Six high'),
('three sixes', ['6h', '6d', '6c', 'Ks', '2h'], 'Three Sixes')],
[('pair of sixes', ['6h', '6d', 'Kc', '9s', '2h'], 'Pair of Sixes'),
('pair of deuces', ['2h', '2d', 'Kc', '9s', '5h'], 'Pair of Deuces'),
('wheel', ['Ah', '2d', '3c', '4s', '5h'], 'Straight, Five high'),
('steel wheel', ['As', '2s', '3s', '4s', '5s'], 'Straight Flush, Five high'),
('threes full of kings', ['3h', '3d', '3c', 'Ks', 'Kh'], 'Full House, Threes full of Kings'),
('kings full of threes', ['Kh', 'Kd', 'Kc', '3s', '3h'], 'Full House, Kings full of Threes'),
('six-high straight', ['2h', '3d', '4c', '5s', '6h'], 'Straight, Six high'),
('three sixes', ['6h', '6d', '6c', 'Ks', '2h'], 'Three Sixes')]]
for label, args, expected in fixtures[N-1]:
try:
actual = solve(args)
except Exception as exc:
actual = 'error:' + type(exc).__name__
check(label, actual, 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 |
|---|---|---|---|
| pair of sixes | Pair of Sixes | Pair of Sixes | Passed |
| pair of deuces | Pair of Deuces | Pair of Deuces | Passed |
| wheel | Straight, Five high | Straight, Five high | Passed |
| steel wheel | Straight Flush, Five high | Straight Flush, Five high | Passed |
| royal | Royal Flush | Royal Flush | Passed |
| king-high straight flush | Straight Flush, King high | Straight Flush, King high | Passed |
| threes full of kings | Full House, Kings full of Threes | Full House, Threes full of Kings | Failed |
| kings full of threes | Full House, Kings full of Threes | Full House, Kings full of Threes | Passed |
SHA-256 / d430cb6d1d56ac4aadd0d86de988f38bf93689930b1b219f1cb613fa2f91a90d
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import collections
N = 1
observations = []
def solve(x):
R='23456789TJQKA'
NAME={2:'Two',3:'Three',4:'Four',5:'Five',6:'Six',7:'Seven',8:'Eight',9:'Nine',10:'Ten',11:'Jack',12:'Queen',13:'King',14:'Ace'}
def pl(v): return {2:'Deuces',6:'Sixes'}.get(v, NAME[v]+'s')
vals=sorted((R.index(c[0])+2 for c in x), reverse=True)
cnt=collections.Counter(vals)
groups=sorted(cnt, key=lambda v:(cnt[v],v), reverse=True)
shape=sorted(cnt.values(), reverse=True)
flush=len({c[1] for c in x})==1
wheel=vals==[14,5,4,3,2]
straight=len(cnt)==5 and (vals[0]-vals[4]==4 or wheel)
top=5 if wheel else vals[0]
if straight and flush: return 'Royal Flush' if top==14 else 'Straight Flush, %s high' % NAME[top]
if shape==[4,1]: return 'Four %s' % pl(groups[0])
if shape==[3,2]: return 'Full House, %s full of %s' % (pl(groups[1]), pl(groups[0]))
if flush: return 'Flush, %s high' % NAME[vals[0]]
if straight: return 'Straight, %s high' % NAME[top]
if shape==[3,1,1]: return 'Three %s' % pl(groups[0])
if shape==[2,2,1]: return 'Two Pair, %s and %s' % (pl(groups[0]), pl(groups[1]))
if shape==[2,1,1,1]: return 'Pair of %s' % pl(groups[0])
return 'High Card, %s' % NAME[vals[0]]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('pair of sixes', ['6h', '6d', 'Kc', '9s', '2h'], 'Pair of Sixes'),
('pair of deuces', ['2h', '2d', 'Kc', '9s', '5h'], 'Pair of Deuces'),
('wheel', ['Ah', '2d', '3c', '4s', '5h'], 'Straight, Five high'),
('steel wheel', ['As', '2s', '3s', '4s', '5s'], 'Straight Flush, Five high'),
('royal', ['Th', 'Jh', 'Qh', 'Kh', 'Ah'], 'Royal Flush'),
('king-high straight flush', ['9d', 'Td', 'Jd', 'Qd', 'Kd'], 'Straight Flush, King high'),
('threes full of kings', ['3h', '3d', '3c', 'Ks', 'Kh'], 'Full House, Threes full of Kings'),
('kings full of threes', ['Kh', 'Kd', 'Kc', '3s', '3h'], 'Full House, Kings full of Threes')],
[('steel wheel', ['As', '2s', '3s', '4s', '5s'], 'Straight Flush, Five high'),
('royal', ['Th', 'Jh', 'Qh', 'Kh', 'Ah'], 'Royal Flush'),
('king-high straight flush', ['9d', 'Td', 'Jd', 'Qd', 'Kd'], 'Straight Flush, King high'),
('threes full of kings', ['3h', '3d', '3c', 'Ks', 'Kh'], 'Full House, Threes full of Kings'),
('kings full of threes', ['Kh', 'Kd', 'Kc', '3s', '3h'], 'Full House, Kings full of Threes'),
('two pair ace kicker', ['Ah', 'Kd', 'Kc', '7s', '7h'], 'Two Pair, Kings and Sevens'),
('two pair low kicker', ['Kh', 'Kd', '7c', '7s', '2h'], 'Two Pair, Kings and Sevens'),
('pair below high cards', ['Ah', 'Kd', '5c', '5s', '9h'], 'Pair of Fives')],
[('threes full of kings', ['3h', '3d', '3c', 'Ks', 'Kh'], 'Full House, Threes full of Kings'),
('kings full of threes', ['Kh', 'Kd', 'Kc', '3s', '3h'], 'Full House, Kings full of Threes'),
('two pair ace kicker', ['Ah', 'Kd', 'Kc', '7s', '7h'], 'Two Pair, Kings and Sevens'),
('two pair low kicker', ['Kh', 'Kd', '7c', '7s', '2h'], 'Two Pair, Kings and Sevens'),
('pair below high cards', ['Ah', 'Kd', '5c', '5s', '9h'], 'Pair of Fives'),
('high card', ['Ah', 'Jd', '8c', '5s', '3h'], 'High Card, Ace'),
('four nines', ['9h', '9d', '9c', '9s', '2h'], 'Four Nines'),
('flush', ['2c', '7c', '9c', 'Jc', 'Qc'], 'Flush, Queen high')],
[('pair of sixes', ['6h', '6d', 'Kc', '9s', '2h'], 'Pair of Sixes'),
('threes full of kings', ['3h', '3d', '3c', 'Ks', 'Kh'], 'Full House, Threes full of Kings'),
('kings full of threes', ['Kh', 'Kd', 'Kc', '3s', '3h'], 'Full House, Kings full of Threes'),
('high card', ['Ah', 'Jd', '8c', '5s', '3h'], 'High Card, Ace'),
('four nines', ['9h', '9d', '9c', '9s', '2h'], 'Four Nines'),
('flush', ['2c', '7c', '9c', 'Jc', 'Qc'], 'Flush, Queen high'),
('six-high straight', ['2h', '3d', '4c', '5s', '6h'], 'Straight, Six high'),
('three sixes', ['6h', '6d', '6c', 'Ks', '2h'], 'Three Sixes')],
[('pair of sixes', ['6h', '6d', 'Kc', '9s', '2h'], 'Pair of Sixes'),
('pair of deuces', ['2h', '2d', 'Kc', '9s', '5h'], 'Pair of Deuces'),
('wheel', ['Ah', '2d', '3c', '4s', '5h'], 'Straight, Five high'),
('steel wheel', ['As', '2s', '3s', '4s', '5s'], 'Straight Flush, Five high'),
('threes full of kings', ['3h', '3d', '3c', 'Ks', 'Kh'], 'Full House, Threes full of Kings'),
('kings full of threes', ['Kh', 'Kd', 'Kc', '3s', '3h'], 'Full House, Kings full of Threes'),
('six-high straight', ['2h', '3d', '4c', '5s', '6h'], 'Straight, Six high'),
('three sixes', ['6h', '6d', '6c', 'Ks', '2h'], 'Three Sixes')]]
for label, args, expected in fixtures[N-1]:
try:
actual = solve(args)
except Exception as exc:
actual = 'error:' + type(exc).__name__
check(label, actual, 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 |
|---|---|---|---|
| pair of sixes | Pair of Sixes | Pair of Sixes | Passed |
| pair of deuces | Pair of Deuces | Pair of Deuces | Passed |
| wheel | Straight, Five high | Straight, Five high | Passed |
| steel wheel | Straight Flush, Five high | Straight Flush, Five high | Passed |
| royal | Royal Flush | Royal Flush | Passed |
| king-high straight flush | Straight Flush, King high | Straight Flush, King high | Passed |
| threes full of kings | Full House, Kings full of Threes | Full House, Threes full of Kings | Failed |
| kings full of threes | Full House, Threes full of Kings | Full House, Kings full of Threes | Failed |
SHA-256 / 1be43cbd0ac960a9d91bc48139fa34b15eea8f26d142ea070f0101975c2b3af2
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
import collections
N = 1
observations = []
def solve(x):
R='23456789TJQKA'
NAME={2:'Two',3:'Three',4:'Four',5:'Five',6:'Six',7:'Seven',8:'Eight',9:'Nine',10:'Ten',11:'Jack',12:'Queen',13:'King',14:'Ace'}
def pl(v): return {2:'Deuces',6:'Sixes'}.get(v, NAME[v]+'s')
vals=sorted((R.index(c[0])+2 for c in x), reverse=True)
cnt=collections.Counter(vals)
groups=sorted(cnt, key=lambda v:(cnt[v],v), reverse=True)
shape=sorted(cnt.values(), reverse=True)
flush=len({c[1] for c in x})==1
wheel=vals==[14,5,4,3,2]
straight=len(cnt)==5 and (vals[0]-vals[4]==4 or wheel)
top=5 if wheel else vals[0]
if straight and flush: return 'Royal Flush' if top==14 else 'Straight Flush, %s high' % NAME[top]
if shape==[4,1]: return 'Four %s' % pl(groups[0])
if shape==[3,2]: return 'Full House, %s full of %s' % (pl(groups[0]), pl(groups[1]))
if flush: return 'Flush, %s high' % NAME[vals[0]]
if straight: return 'Straight, %s high' % NAME[top]
if shape==[3,1,1]: return 'Three %s' % pl(groups[0])
if shape==[2,2,1]: return 'Two Pair, %s and %s' % (pl(groups[0]), pl(groups[1]))
if shape==[2,1,1,1]: return 'Pair of %s' % pl(groups[0])
return 'High Card, %s' % NAME[vals[0]]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('pair of sixes', ['6h', '6d', 'Kc', '9s', '2h'], 'Pair of Sixes'),
('pair of deuces', ['2h', '2d', 'Kc', '9s', '5h'], 'Pair of Deuces'),
('wheel', ['Ah', '2d', '3c', '4s', '5h'], 'Straight, Five high'),
('steel wheel', ['As', '2s', '3s', '4s', '5s'], 'Straight Flush, Five high'),
('royal', ['Th', 'Jh', 'Qh', 'Kh', 'Ah'], 'Royal Flush'),
('king-high straight flush', ['9d', 'Td', 'Jd', 'Qd', 'Kd'], 'Straight Flush, King high'),
('threes full of kings', ['3h', '3d', '3c', 'Ks', 'Kh'], 'Full House, Threes full of Kings'),
('kings full of threes', ['Kh', 'Kd', 'Kc', '3s', '3h'], 'Full House, Kings full of Threes')],
[('steel wheel', ['As', '2s', '3s', '4s', '5s'], 'Straight Flush, Five high'),
('royal', ['Th', 'Jh', 'Qh', 'Kh', 'Ah'], 'Royal Flush'),
('king-high straight flush', ['9d', 'Td', 'Jd', 'Qd', 'Kd'], 'Straight Flush, King high'),
('threes full of kings', ['3h', '3d', '3c', 'Ks', 'Kh'], 'Full House, Threes full of Kings'),
('kings full of threes', ['Kh', 'Kd', 'Kc', '3s', '3h'], 'Full House, Kings full of Threes'),
('two pair ace kicker', ['Ah', 'Kd', 'Kc', '7s', '7h'], 'Two Pair, Kings and Sevens'),
('two pair low kicker', ['Kh', 'Kd', '7c', '7s', '2h'], 'Two Pair, Kings and Sevens'),
('pair below high cards', ['Ah', 'Kd', '5c', '5s', '9h'], 'Pair of Fives')],
[('threes full of kings', ['3h', '3d', '3c', 'Ks', 'Kh'], 'Full House, Threes full of Kings'),
('kings full of threes', ['Kh', 'Kd', 'Kc', '3s', '3h'], 'Full House, Kings full of Threes'),
('two pair ace kicker', ['Ah', 'Kd', 'Kc', '7s', '7h'], 'Two Pair, Kings and Sevens'),
('two pair low kicker', ['Kh', 'Kd', '7c', '7s', '2h'], 'Two Pair, Kings and Sevens'),
('pair below high cards', ['Ah', 'Kd', '5c', '5s', '9h'], 'Pair of Fives'),
('high card', ['Ah', 'Jd', '8c', '5s', '3h'], 'High Card, Ace'),
('four nines', ['9h', '9d', '9c', '9s', '2h'], 'Four Nines'),
('flush', ['2c', '7c', '9c', 'Jc', 'Qc'], 'Flush, Queen high')],
[('pair of sixes', ['6h', '6d', 'Kc', '9s', '2h'], 'Pair of Sixes'),
('threes full of kings', ['3h', '3d', '3c', 'Ks', 'Kh'], 'Full House, Threes full of Kings'),
('kings full of threes', ['Kh', 'Kd', 'Kc', '3s', '3h'], 'Full House, Kings full of Threes'),
('high card', ['Ah', 'Jd', '8c', '5s', '3h'], 'High Card, Ace'),
('four nines', ['9h', '9d', '9c', '9s', '2h'], 'Four Nines'),
('flush', ['2c', '7c', '9c', 'Jc', 'Qc'], 'Flush, Queen high'),
('six-high straight', ['2h', '3d', '4c', '5s', '6h'], 'Straight, Six high'),
('three sixes', ['6h', '6d', '6c', 'Ks', '2h'], 'Three Sixes')],
[('pair of sixes', ['6h', '6d', 'Kc', '9s', '2h'], 'Pair of Sixes'),
('pair of deuces', ['2h', '2d', 'Kc', '9s', '5h'], 'Pair of Deuces'),
('wheel', ['Ah', '2d', '3c', '4s', '5h'], 'Straight, Five high'),
('steel wheel', ['As', '2s', '3s', '4s', '5s'], 'Straight Flush, Five high'),
('threes full of kings', ['3h', '3d', '3c', 'Ks', 'Kh'], 'Full House, Threes full of Kings'),
('kings full of threes', ['Kh', 'Kd', 'Kc', '3s', '3h'], 'Full House, Kings full of Threes'),
('six-high straight', ['2h', '3d', '4c', '5s', '6h'], 'Straight, Six high'),
('three sixes', ['6h', '6d', '6c', 'Ks', '2h'], 'Three Sixes')]]
for label, args, expected in fixtures[N-1]:
try:
actual = solve(args)
except Exception as exc:
actual = 'error:' + type(exc).__name__
check(label, actual, 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 |
|---|---|---|---|
| pair of sixes | Pair of Sixes | Pair of Sixes | Passed |
| pair of deuces | Pair of Deuces | Pair of Deuces | Passed |
| wheel | Straight, Five high | Straight, Five high | Passed |
| steel wheel | Straight Flush, Five high | Straight Flush, Five high | Passed |
| royal | Royal Flush | Royal Flush | Passed |
| king-high straight flush | Straight Flush, King high | Straight Flush, King high | Passed |
| threes full of kings | Full House, Threes full of Kings | Full House, Threes full of Kings | Passed |
| kings full of threes | Full House, Kings full of Threes | Full House, Kings full of Threes | Passed |
SHA-256 / 3e60fb45225231f6a933d915ad0e5a0e6e4735896b5d4c0a8ef180bc55f0f336
Verification & scope
A deterministic toy model with an explicitly stated contract; card strings are rank+suit (for example "As", "Td"); no claim of conformance to any casino or tournament rulebook. 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:09.850074+00:00.
Case digest / f65de52802e4b1b0fcc64652afcf19f9eb7d2c797c933ec34b79f3908105a6f4