FA-82196 / Poker hand evaluation / Open access
Kicker announced as the second pair · case 01
Kings and sevens with a deuce kicker is announced "Two Pair, Kings and Deuces".
ROOT CAUSE
The second pair is read from the last rank group, which is the kicker.
VERIFIED REPAIR
Name the first two rank groups (the two pairs).
Unsuccessful approach: Indexing the sorted cards works only when the kicker is the lowest card.
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(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'),
('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')],
[('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'),
('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'),
('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'),
('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'),
('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 |
| two pair ace kicker | Two Pair, Kings and Aces | Two Pair, Kings and Sevens | Failed |
| two pair low kicker | Two Pair, Kings and Deuces | Two Pair, Kings and Sevens | Failed |
SHA-256 / d0d969c3bc1627cef7fb331c903d3254287736c0739d4d36e8e6206b1a95c9b8
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[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(vals[0]), pl(vals[2]))
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'),
('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')],
[('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'),
('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'),
('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'),
('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'),
('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 |
| two pair ace kicker | Two Pair, Aces and Kings | Two Pair, Kings and Sevens | Failed |
| two pair low kicker | Two Pair, Kings and Sevens | Two Pair, Kings and Sevens | Passed |
SHA-256 / a51ac7dffe2c054ebeb78864a5f06402b2ac7a26e906dce920d7856f616499a7
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'),
('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')],
[('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'),
('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'),
('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'),
('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'),
('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 |
| two pair ace kicker | Two Pair, Kings and Sevens | Two Pair, Kings and Sevens | Passed |
| two pair low kicker | Two Pair, Kings and Sevens | Two Pair, Kings and Sevens | Passed |
SHA-256 / 8339fca89dc14d3aaef3ccad846db0a21d0f42b0854a8233237c1882a11709b5
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.968257+00:00.
Case digest / 6c7441906d26053b31ff8aa832f2a27e64bf96e83c7002650285e59ff278f637