FA-82551 / Chess move legality / Open access
Positions without castling rights rejected · case 01
Every FEN with "-" in the castling field is reported invalid.
ROOT CAUSE
The "-" placeholder is validated as if it were a castling letter.
VERIFIED REPAIR
Map "-" to the empty rights string before validating letters.
Unsuccessful approach: Upper-casing the field turns black's kq rights into white's KQ.
Case contract
Input: a FEN string. Return {"pieces": {square: piece}, "turn", "castling", "ep", "halfmove", "fullmove"} or "invalid". Placement lists rank 8 first; digits skip empty squares; each rank must total 8; exactly one king per side. Turn is w or b; castling is "-" or letters from KQkq (returned as "" when "-"); ep is "-" (null) or a square on rank 6 when white is to move, rank 3 when black is; halfmove is a non-negative integer and fullmove at least 1.
Why this case matters
Every position-based legality check starts from a parsed FEN; a misparse silently changes which moves are legal.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
parts=x.split()
if len(parts)!=6: return 'invalid'
rows=parts[0].split('/')
if len(rows)!=8: return 'invalid'
board={}
for i,row in enumerate(rows):
rank=8-i; f=0
for ch in row:
if ch.isdigit(): f+=int(ch)
elif ch in 'pnbrqkPNBRQK':
if f>7: return 'invalid'
board[chr(97+f)+str(rank)]=ch; f+=1
else: return 'invalid'
if f!=8: return 'invalid'
vals=list(board.values())
if vals.count('K')!=1 or vals.count('k')!=1: return 'invalid'
turn=parts[1]
if turn not in ('w','b'): return 'invalid'
cast=parts[2]
if any(c not in 'KQkq' for c in cast): return 'invalid'
ep=None if parts[3]=='-' else parts[3]
if ep is not None and ep[1:]!=('6' if turn=='w' else '3'): return 'invalid'
if not (parts[4].isdigit() and parts[5].isdigit()) or int(parts[5])<1: return 'invalid'
return {'pieces':board,'turn':turn,'castling':cast,'ep':ep,'halfmove':int(parts[4]),'fullmove':int(parts[5])}
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('kings and rook', '4k3/8/8/8/8/8/8/R3K3 w Q - 0 1',
{'castling': 'Q',
'ep': None,
'fullmove': 1,
'halfmove': 0,
'pieces': {'a1': 'R', 'e1': 'K', 'e8': 'k'},
'turn': 'w'}),
('black to move ep', '4k3/8/8/8/3Pp3/8/8/4K3 b - d3 0 12',
{'castling': '',
'ep': 'd3',
'fullmove': 12,
'halfmove': 0,
'pieces': {'d4': 'P', 'e1': 'K', 'e4': 'p', 'e8': 'k'},
'turn': 'b'}),
('white ep target', '4k3/8/8/3pP3/8/8/8/4K3 w - d6 0 9',
{'castling': '',
'ep': 'd6',
'fullmove': 9,
'halfmove': 0,
'pieces': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'},
'turn': 'w'}),
('ep wrong side', '4k3/8/8/3pP3/8/8/8/4K3 w - d3 0 9', 'invalid'),
('black rights only', 'r3k2r/8/8/8/8/8/8/R3K2R w kq - 0 5',
{'castling': 'kq',
'ep': None,
'fullmove': 5,
'halfmove': 0,
'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
'turn': 'w'}),
('two white kings', '4k3/8/8/8/8/8/8/K3K3 w - - 0 1', 'invalid'),
('two white kings no black', '8/8/8/8/8/8/8/K3K3 w - - 0 1', 'invalid'),
('missing black king', '8/8/8/8/8/8/8/4K3 w - - 0 1', 'invalid')],
[('white ep target', '4k3/8/8/3pP3/8/8/8/4K3 w - d6 0 9',
{'castling': '',
'ep': 'd6',
'fullmove': 9,
'halfmove': 0,
'pieces': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'},
'turn': 'w'}),
('no castling dash', 'r3k2r/8/8/8/8/8/8/R3K2R b - - 3 20',
{'castling': '',
'ep': None,
'fullmove': 20,
'halfmove': 3,
'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
'turn': 'b'}),
('black rights only', 'r3k2r/8/8/8/8/8/8/R3K2R w kq - 0 5',
{'castling': 'kq',
'ep': None,
'fullmove': 5,
'halfmove': 0,
'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
'turn': 'w'}),
('two white kings no black', '8/8/8/8/8/8/8/K3K3 w - - 0 1', 'invalid'),
('missing black king', '8/8/8/8/8/8/8/4K3 w - - 0 1', 'invalid'),
('short rank', '4k3/8/8/8/8/8/8/4K2 w - - 0 1', 'invalid'),
('fullmove zero', '4k3/8/8/8/8/8/8/4K3 w - - 0 0', 'invalid'),
('halfmove dash', '4k3/8/8/8/8/8/8/4K3 w - - - 1', 'invalid')],
[('black to move ep', '4k3/8/8/8/3Pp3/8/8/4K3 b - d3 0 12',
{'castling': '',
'ep': 'd3',
'fullmove': 12,
'halfmove': 0,
'pieces': {'d4': 'P', 'e1': 'K', 'e4': 'p', 'e8': 'k'},
'turn': 'b'}),
('no castling dash', 'r3k2r/8/8/8/8/8/8/R3K2R b - - 3 20',
{'castling': '',
'ep': None,
'fullmove': 20,
'halfmove': 3,
'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
'turn': 'b'}),
('black rights only', 'r3k2r/8/8/8/8/8/8/R3K2R w kq - 0 5',
{'castling': 'kq',
'ep': None,
'fullmove': 5,
'halfmove': 0,
'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
'turn': 'w'}),
('fullmove zero', '4k3/8/8/8/8/8/8/4K3 w - - 0 0', 'invalid'),
('halfmove dash', '4k3/8/8/8/8/8/8/4K3 w - - - 1', 'invalid'),
('pawns and knights', 'rn2k3/pp6/8/8/8/8/6PP/4K1NR w K - 7 30',
{'castling': 'K',
'ep': None,
'fullmove': 30,
'halfmove': 7,
'pieces': {'a7': 'p',
'a8': 'r',
'b7': 'p',
'b8': 'n',
'e1': 'K',
'e8': 'k',
'g1': 'N',
'g2': 'P',
'h1': 'R',
'h2': 'P'},
'turn': 'w'}),
('bad castling letter', '4k3/8/8/8/8/8/8/4K3 w X - 0 1', 'invalid'),
('bad turn', '4k3/8/8/8/8/8/8/4K3 x - - 0 1', 'invalid')],
[('kings and rook', '4k3/8/8/8/8/8/8/R3K3 w Q - 0 1',
{'castling': 'Q',
'ep': None,
'fullmove': 1,
'halfmove': 0,
'pieces': {'a1': 'R', 'e1': 'K', 'e8': 'k'},
'turn': 'w'}),
('black to move ep', '4k3/8/8/8/3Pp3/8/8/4K3 b - d3 0 12',
{'castling': '',
'ep': 'd3',
'fullmove': 12,
'halfmove': 0,
'pieces': {'d4': 'P', 'e1': 'K', 'e4': 'p', 'e8': 'k'},
'turn': 'b'}),
('white ep target', '4k3/8/8/3pP3/8/8/8/4K3 w - d6 0 9',
{'castling': '',
'ep': 'd6',
'fullmove': 9,
'halfmove': 0,
'pieces': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'},
'turn': 'w'}),
('no castling dash', 'r3k2r/8/8/8/8/8/8/R3K2R b - - 3 20',
{'castling': '',
'ep': None,
'fullmove': 20,
'halfmove': 3,
'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
'turn': 'b'}),
('black rights only', 'r3k2r/8/8/8/8/8/8/R3K2R w kq - 0 5',
{'castling': 'kq',
'ep': None,
'fullmove': 5,
'halfmove': 0,
'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
'turn': 'w'}),
('bad castling letter', '4k3/8/8/8/8/8/8/4K3 w X - 0 1', 'invalid'),
('bad turn', '4k3/8/8/8/8/8/8/4K3 x - - 0 1', 'invalid'),
('fullmove dash', '4k3/8/8/8/8/8/8/4K3 w - - 0 -', 'invalid')],
[('kings and rook', '4k3/8/8/8/8/8/8/R3K3 w Q - 0 1',
{'castling': 'Q',
'ep': None,
'fullmove': 1,
'halfmove': 0,
'pieces': {'a1': 'R', 'e1': 'K', 'e8': 'k'},
'turn': 'w'}),
('black to move ep', '4k3/8/8/8/3Pp3/8/8/4K3 b - d3 0 12',
{'castling': '',
'ep': 'd3',
'fullmove': 12,
'halfmove': 0,
'pieces': {'d4': 'P', 'e1': 'K', 'e4': 'p', 'e8': 'k'},
'turn': 'b'}),
('white ep target', '4k3/8/8/3pP3/8/8/8/4K3 w - d6 0 9',
{'castling': '',
'ep': 'd6',
'fullmove': 9,
'halfmove': 0,
'pieces': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'},
'turn': 'w'}),
('ep wrong side', '4k3/8/8/3pP3/8/8/8/4K3 w - d3 0 9', 'invalid'),
('no castling dash', 'r3k2r/8/8/8/8/8/8/R3K2R b - - 3 20',
{'castling': '',
'ep': None,
'fullmove': 20,
'halfmove': 3,
'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
'turn': 'b'}),
('black rights only', 'r3k2r/8/8/8/8/8/8/R3K2R w kq - 0 5',
{'castling': 'kq',
'ep': None,
'fullmove': 5,
'halfmove': 0,
'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
'turn': 'w'}),
('two white kings', '4k3/8/8/8/8/8/8/K3K3 w - - 0 1', 'invalid'),
('two white kings no black', '8/8/8/8/8/8/8/K3K3 w - - 0 1', 'invalid')]]
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 |
|---|---|---|---|
| kings and rook | {'castling': 'Q', 'ep': None, 'fullmove': 1, 'halfmove': 0, 'pieces': {'a1': 'R', 'e1': 'K', 'e8': 'k'}, 'turn': 'w'} | {'castling': 'Q', 'ep': None, 'fullmove': 1, 'halfmove': 0, 'pieces': {'a1': 'R', 'e1': 'K', 'e8': 'k'}, 'turn': 'w'} | Passed |
| black to move ep | invalid | {'castling': '', 'ep': 'd3', 'fullmove': 12, 'halfmove': 0, 'pieces': {'d4': 'P', 'e1': 'K', 'e4': 'p', 'e8': 'k'}, 'turn': 'b'} | Failed |
| white ep target | invalid | {'castling': '', 'ep': 'd6', 'fullmove': 9, 'halfmove': 0, 'pieces': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'}, 'turn': 'w'} | Failed |
| ep wrong side | invalid | invalid | Passed |
| black rights only | {'castling': 'kq', 'ep': None, 'fullmove': 5, 'halfmove': 0, 'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'}, 'turn': 'w'} | {'castling': 'kq', 'ep': None, 'fullmove': 5, 'halfmove': 0, 'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'}, 'turn': 'w'} | Passed |
| two white kings | invalid | invalid | Passed |
| two white kings no black | invalid | invalid | Passed |
| missing black king | invalid | invalid | Passed |
SHA-256 / 00501fc585e3a4b69f7075edd275af80475e4b394efd3d781dcbfb44e96d713b
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
parts=x.split()
if len(parts)!=6: return 'invalid'
rows=parts[0].split('/')
if len(rows)!=8: return 'invalid'
board={}
for i,row in enumerate(rows):
rank=8-i; f=0
for ch in row:
if ch.isdigit(): f+=int(ch)
elif ch in 'pnbrqkPNBRQK':
if f>7: return 'invalid'
board[chr(97+f)+str(rank)]=ch; f+=1
else: return 'invalid'
if f!=8: return 'invalid'
vals=list(board.values())
if vals.count('K')!=1 or vals.count('k')!=1: return 'invalid'
turn=parts[1]
if turn not in ('w','b'): return 'invalid'
cast='' if parts[2]=='-' else parts[2].upper()
if any(c not in 'KQkq' for c in cast): return 'invalid'
ep=None if parts[3]=='-' else parts[3]
if ep is not None and ep[1:]!=('6' if turn=='w' else '3'): return 'invalid'
if not (parts[4].isdigit() and parts[5].isdigit()) or int(parts[5])<1: return 'invalid'
return {'pieces':board,'turn':turn,'castling':cast,'ep':ep,'halfmove':int(parts[4]),'fullmove':int(parts[5])}
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('kings and rook', '4k3/8/8/8/8/8/8/R3K3 w Q - 0 1',
{'castling': 'Q',
'ep': None,
'fullmove': 1,
'halfmove': 0,
'pieces': {'a1': 'R', 'e1': 'K', 'e8': 'k'},
'turn': 'w'}),
('black to move ep', '4k3/8/8/8/3Pp3/8/8/4K3 b - d3 0 12',
{'castling': '',
'ep': 'd3',
'fullmove': 12,
'halfmove': 0,
'pieces': {'d4': 'P', 'e1': 'K', 'e4': 'p', 'e8': 'k'},
'turn': 'b'}),
('white ep target', '4k3/8/8/3pP3/8/8/8/4K3 w - d6 0 9',
{'castling': '',
'ep': 'd6',
'fullmove': 9,
'halfmove': 0,
'pieces': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'},
'turn': 'w'}),
('ep wrong side', '4k3/8/8/3pP3/8/8/8/4K3 w - d3 0 9', 'invalid'),
('black rights only', 'r3k2r/8/8/8/8/8/8/R3K2R w kq - 0 5',
{'castling': 'kq',
'ep': None,
'fullmove': 5,
'halfmove': 0,
'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
'turn': 'w'}),
('two white kings', '4k3/8/8/8/8/8/8/K3K3 w - - 0 1', 'invalid'),
('two white kings no black', '8/8/8/8/8/8/8/K3K3 w - - 0 1', 'invalid'),
('missing black king', '8/8/8/8/8/8/8/4K3 w - - 0 1', 'invalid')],
[('white ep target', '4k3/8/8/3pP3/8/8/8/4K3 w - d6 0 9',
{'castling': '',
'ep': 'd6',
'fullmove': 9,
'halfmove': 0,
'pieces': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'},
'turn': 'w'}),
('no castling dash', 'r3k2r/8/8/8/8/8/8/R3K2R b - - 3 20',
{'castling': '',
'ep': None,
'fullmove': 20,
'halfmove': 3,
'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
'turn': 'b'}),
('black rights only', 'r3k2r/8/8/8/8/8/8/R3K2R w kq - 0 5',
{'castling': 'kq',
'ep': None,
'fullmove': 5,
'halfmove': 0,
'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
'turn': 'w'}),
('two white kings no black', '8/8/8/8/8/8/8/K3K3 w - - 0 1', 'invalid'),
('missing black king', '8/8/8/8/8/8/8/4K3 w - - 0 1', 'invalid'),
('short rank', '4k3/8/8/8/8/8/8/4K2 w - - 0 1', 'invalid'),
('fullmove zero', '4k3/8/8/8/8/8/8/4K3 w - - 0 0', 'invalid'),
('halfmove dash', '4k3/8/8/8/8/8/8/4K3 w - - - 1', 'invalid')],
[('black to move ep', '4k3/8/8/8/3Pp3/8/8/4K3 b - d3 0 12',
{'castling': '',
'ep': 'd3',
'fullmove': 12,
'halfmove': 0,
'pieces': {'d4': 'P', 'e1': 'K', 'e4': 'p', 'e8': 'k'},
'turn': 'b'}),
('no castling dash', 'r3k2r/8/8/8/8/8/8/R3K2R b - - 3 20',
{'castling': '',
'ep': None,
'fullmove': 20,
'halfmove': 3,
'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
'turn': 'b'}),
('black rights only', 'r3k2r/8/8/8/8/8/8/R3K2R w kq - 0 5',
{'castling': 'kq',
'ep': None,
'fullmove': 5,
'halfmove': 0,
'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
'turn': 'w'}),
('fullmove zero', '4k3/8/8/8/8/8/8/4K3 w - - 0 0', 'invalid'),
('halfmove dash', '4k3/8/8/8/8/8/8/4K3 w - - - 1', 'invalid'),
('pawns and knights', 'rn2k3/pp6/8/8/8/8/6PP/4K1NR w K - 7 30',
{'castling': 'K',
'ep': None,
'fullmove': 30,
'halfmove': 7,
'pieces': {'a7': 'p',
'a8': 'r',
'b7': 'p',
'b8': 'n',
'e1': 'K',
'e8': 'k',
'g1': 'N',
'g2': 'P',
'h1': 'R',
'h2': 'P'},
'turn': 'w'}),
('bad castling letter', '4k3/8/8/8/8/8/8/4K3 w X - 0 1', 'invalid'),
('bad turn', '4k3/8/8/8/8/8/8/4K3 x - - 0 1', 'invalid')],
[('kings and rook', '4k3/8/8/8/8/8/8/R3K3 w Q - 0 1',
{'castling': 'Q',
'ep': None,
'fullmove': 1,
'halfmove': 0,
'pieces': {'a1': 'R', 'e1': 'K', 'e8': 'k'},
'turn': 'w'}),
('black to move ep', '4k3/8/8/8/3Pp3/8/8/4K3 b - d3 0 12',
{'castling': '',
'ep': 'd3',
'fullmove': 12,
'halfmove': 0,
'pieces': {'d4': 'P', 'e1': 'K', 'e4': 'p', 'e8': 'k'},
'turn': 'b'}),
('white ep target', '4k3/8/8/3pP3/8/8/8/4K3 w - d6 0 9',
{'castling': '',
'ep': 'd6',
'fullmove': 9,
'halfmove': 0,
'pieces': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'},
'turn': 'w'}),
('no castling dash', 'r3k2r/8/8/8/8/8/8/R3K2R b - - 3 20',
{'castling': '',
'ep': None,
'fullmove': 20,
'halfmove': 3,
'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
'turn': 'b'}),
('black rights only', 'r3k2r/8/8/8/8/8/8/R3K2R w kq - 0 5',
{'castling': 'kq',
'ep': None,
'fullmove': 5,
'halfmove': 0,
'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
'turn': 'w'}),
('bad castling letter', '4k3/8/8/8/8/8/8/4K3 w X - 0 1', 'invalid'),
('bad turn', '4k3/8/8/8/8/8/8/4K3 x - - 0 1', 'invalid'),
('fullmove dash', '4k3/8/8/8/8/8/8/4K3 w - - 0 -', 'invalid')],
[('kings and rook', '4k3/8/8/8/8/8/8/R3K3 w Q - 0 1',
{'castling': 'Q',
'ep': None,
'fullmove': 1,
'halfmove': 0,
'pieces': {'a1': 'R', 'e1': 'K', 'e8': 'k'},
'turn': 'w'}),
('black to move ep', '4k3/8/8/8/3Pp3/8/8/4K3 b - d3 0 12',
{'castling': '',
'ep': 'd3',
'fullmove': 12,
'halfmove': 0,
'pieces': {'d4': 'P', 'e1': 'K', 'e4': 'p', 'e8': 'k'},
'turn': 'b'}),
('white ep target', '4k3/8/8/3pP3/8/8/8/4K3 w - d6 0 9',
{'castling': '',
'ep': 'd6',
'fullmove': 9,
'halfmove': 0,
'pieces': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'},
'turn': 'w'}),
('ep wrong side', '4k3/8/8/3pP3/8/8/8/4K3 w - d3 0 9', 'invalid'),
('no castling dash', 'r3k2r/8/8/8/8/8/8/R3K2R b - - 3 20',
{'castling': '',
'ep': None,
'fullmove': 20,
'halfmove': 3,
'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
'turn': 'b'}),
('black rights only', 'r3k2r/8/8/8/8/8/8/R3K2R w kq - 0 5',
{'castling': 'kq',
'ep': None,
'fullmove': 5,
'halfmove': 0,
'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
'turn': 'w'}),
('two white kings', '4k3/8/8/8/8/8/8/K3K3 w - - 0 1', 'invalid'),
('two white kings no black', '8/8/8/8/8/8/8/K3K3 w - - 0 1', 'invalid')]]
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 |
|---|---|---|---|
| kings and rook | {'castling': 'Q', 'ep': None, 'fullmove': 1, 'halfmove': 0, 'pieces': {'a1': 'R', 'e1': 'K', 'e8': 'k'}, 'turn': 'w'} | {'castling': 'Q', 'ep': None, 'fullmove': 1, 'halfmove': 0, 'pieces': {'a1': 'R', 'e1': 'K', 'e8': 'k'}, 'turn': 'w'} | Passed |
| black to move ep | {'castling': '', 'ep': 'd3', 'fullmove': 12, 'halfmove': 0, 'pieces': {'d4': 'P', 'e1': 'K', 'e4': 'p', 'e8': 'k'}, 'turn': 'b'} | {'castling': '', 'ep': 'd3', 'fullmove': 12, 'halfmove': 0, 'pieces': {'d4': 'P', 'e1': 'K', 'e4': 'p', 'e8': 'k'}, 'turn': 'b'} | Passed |
| white ep target | {'castling': '', 'ep': 'd6', 'fullmove': 9, 'halfmove': 0, 'pieces': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'}, 'turn': 'w'} | {'castling': '', 'ep': 'd6', 'fullmove': 9, 'halfmove': 0, 'pieces': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'}, 'turn': 'w'} | Passed |
| ep wrong side | invalid | invalid | Passed |
| black rights only | {'castling': 'KQ', 'ep': None, 'fullmove': 5, 'halfmove': 0, 'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'}, 'turn': 'w'} | {'castling': 'kq', 'ep': None, 'fullmove': 5, 'halfmove': 0, 'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'}, 'turn': 'w'} | Failed |
| two white kings | invalid | invalid | Passed |
| two white kings no black | invalid | invalid | Passed |
| missing black king | invalid | invalid | Passed |
SHA-256 / f65f9775b7199e0526df6d532bbe4587cb0d4287317ca28de263df1f79f1f274
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
parts=x.split()
if len(parts)!=6: return 'invalid'
rows=parts[0].split('/')
if len(rows)!=8: return 'invalid'
board={}
for i,row in enumerate(rows):
rank=8-i; f=0
for ch in row:
if ch.isdigit(): f+=int(ch)
elif ch in 'pnbrqkPNBRQK':
if f>7: return 'invalid'
board[chr(97+f)+str(rank)]=ch; f+=1
else: return 'invalid'
if f!=8: return 'invalid'
vals=list(board.values())
if vals.count('K')!=1 or vals.count('k')!=1: return 'invalid'
turn=parts[1]
if turn not in ('w','b'): return 'invalid'
cast='' if parts[2]=='-' else parts[2]
if any(c not in 'KQkq' for c in cast): return 'invalid'
ep=None if parts[3]=='-' else parts[3]
if ep is not None and ep[1:]!=('6' if turn=='w' else '3'): return 'invalid'
if not (parts[4].isdigit() and parts[5].isdigit()) or int(parts[5])<1: return 'invalid'
return {'pieces':board,'turn':turn,'castling':cast,'ep':ep,'halfmove':int(parts[4]),'fullmove':int(parts[5])}
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('kings and rook', '4k3/8/8/8/8/8/8/R3K3 w Q - 0 1',
{'castling': 'Q',
'ep': None,
'fullmove': 1,
'halfmove': 0,
'pieces': {'a1': 'R', 'e1': 'K', 'e8': 'k'},
'turn': 'w'}),
('black to move ep', '4k3/8/8/8/3Pp3/8/8/4K3 b - d3 0 12',
{'castling': '',
'ep': 'd3',
'fullmove': 12,
'halfmove': 0,
'pieces': {'d4': 'P', 'e1': 'K', 'e4': 'p', 'e8': 'k'},
'turn': 'b'}),
('white ep target', '4k3/8/8/3pP3/8/8/8/4K3 w - d6 0 9',
{'castling': '',
'ep': 'd6',
'fullmove': 9,
'halfmove': 0,
'pieces': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'},
'turn': 'w'}),
('ep wrong side', '4k3/8/8/3pP3/8/8/8/4K3 w - d3 0 9', 'invalid'),
('black rights only', 'r3k2r/8/8/8/8/8/8/R3K2R w kq - 0 5',
{'castling': 'kq',
'ep': None,
'fullmove': 5,
'halfmove': 0,
'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
'turn': 'w'}),
('two white kings', '4k3/8/8/8/8/8/8/K3K3 w - - 0 1', 'invalid'),
('two white kings no black', '8/8/8/8/8/8/8/K3K3 w - - 0 1', 'invalid'),
('missing black king', '8/8/8/8/8/8/8/4K3 w - - 0 1', 'invalid')],
[('white ep target', '4k3/8/8/3pP3/8/8/8/4K3 w - d6 0 9',
{'castling': '',
'ep': 'd6',
'fullmove': 9,
'halfmove': 0,
'pieces': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'},
'turn': 'w'}),
('no castling dash', 'r3k2r/8/8/8/8/8/8/R3K2R b - - 3 20',
{'castling': '',
'ep': None,
'fullmove': 20,
'halfmove': 3,
'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
'turn': 'b'}),
('black rights only', 'r3k2r/8/8/8/8/8/8/R3K2R w kq - 0 5',
{'castling': 'kq',
'ep': None,
'fullmove': 5,
'halfmove': 0,
'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
'turn': 'w'}),
('two white kings no black', '8/8/8/8/8/8/8/K3K3 w - - 0 1', 'invalid'),
('missing black king', '8/8/8/8/8/8/8/4K3 w - - 0 1', 'invalid'),
('short rank', '4k3/8/8/8/8/8/8/4K2 w - - 0 1', 'invalid'),
('fullmove zero', '4k3/8/8/8/8/8/8/4K3 w - - 0 0', 'invalid'),
('halfmove dash', '4k3/8/8/8/8/8/8/4K3 w - - - 1', 'invalid')],
[('black to move ep', '4k3/8/8/8/3Pp3/8/8/4K3 b - d3 0 12',
{'castling': '',
'ep': 'd3',
'fullmove': 12,
'halfmove': 0,
'pieces': {'d4': 'P', 'e1': 'K', 'e4': 'p', 'e8': 'k'},
'turn': 'b'}),
('no castling dash', 'r3k2r/8/8/8/8/8/8/R3K2R b - - 3 20',
{'castling': '',
'ep': None,
'fullmove': 20,
'halfmove': 3,
'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
'turn': 'b'}),
('black rights only', 'r3k2r/8/8/8/8/8/8/R3K2R w kq - 0 5',
{'castling': 'kq',
'ep': None,
'fullmove': 5,
'halfmove': 0,
'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
'turn': 'w'}),
('fullmove zero', '4k3/8/8/8/8/8/8/4K3 w - - 0 0', 'invalid'),
('halfmove dash', '4k3/8/8/8/8/8/8/4K3 w - - - 1', 'invalid'),
('pawns and knights', 'rn2k3/pp6/8/8/8/8/6PP/4K1NR w K - 7 30',
{'castling': 'K',
'ep': None,
'fullmove': 30,
'halfmove': 7,
'pieces': {'a7': 'p',
'a8': 'r',
'b7': 'p',
'b8': 'n',
'e1': 'K',
'e8': 'k',
'g1': 'N',
'g2': 'P',
'h1': 'R',
'h2': 'P'},
'turn': 'w'}),
('bad castling letter', '4k3/8/8/8/8/8/8/4K3 w X - 0 1', 'invalid'),
('bad turn', '4k3/8/8/8/8/8/8/4K3 x - - 0 1', 'invalid')],
[('kings and rook', '4k3/8/8/8/8/8/8/R3K3 w Q - 0 1',
{'castling': 'Q',
'ep': None,
'fullmove': 1,
'halfmove': 0,
'pieces': {'a1': 'R', 'e1': 'K', 'e8': 'k'},
'turn': 'w'}),
('black to move ep', '4k3/8/8/8/3Pp3/8/8/4K3 b - d3 0 12',
{'castling': '',
'ep': 'd3',
'fullmove': 12,
'halfmove': 0,
'pieces': {'d4': 'P', 'e1': 'K', 'e4': 'p', 'e8': 'k'},
'turn': 'b'}),
('white ep target', '4k3/8/8/3pP3/8/8/8/4K3 w - d6 0 9',
{'castling': '',
'ep': 'd6',
'fullmove': 9,
'halfmove': 0,
'pieces': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'},
'turn': 'w'}),
('no castling dash', 'r3k2r/8/8/8/8/8/8/R3K2R b - - 3 20',
{'castling': '',
'ep': None,
'fullmove': 20,
'halfmove': 3,
'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
'turn': 'b'}),
('black rights only', 'r3k2r/8/8/8/8/8/8/R3K2R w kq - 0 5',
{'castling': 'kq',
'ep': None,
'fullmove': 5,
'halfmove': 0,
'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
'turn': 'w'}),
('bad castling letter', '4k3/8/8/8/8/8/8/4K3 w X - 0 1', 'invalid'),
('bad turn', '4k3/8/8/8/8/8/8/4K3 x - - 0 1', 'invalid'),
('fullmove dash', '4k3/8/8/8/8/8/8/4K3 w - - 0 -', 'invalid')],
[('kings and rook', '4k3/8/8/8/8/8/8/R3K3 w Q - 0 1',
{'castling': 'Q',
'ep': None,
'fullmove': 1,
'halfmove': 0,
'pieces': {'a1': 'R', 'e1': 'K', 'e8': 'k'},
'turn': 'w'}),
('black to move ep', '4k3/8/8/8/3Pp3/8/8/4K3 b - d3 0 12',
{'castling': '',
'ep': 'd3',
'fullmove': 12,
'halfmove': 0,
'pieces': {'d4': 'P', 'e1': 'K', 'e4': 'p', 'e8': 'k'},
'turn': 'b'}),
('white ep target', '4k3/8/8/3pP3/8/8/8/4K3 w - d6 0 9',
{'castling': '',
'ep': 'd6',
'fullmove': 9,
'halfmove': 0,
'pieces': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'},
'turn': 'w'}),
('ep wrong side', '4k3/8/8/3pP3/8/8/8/4K3 w - d3 0 9', 'invalid'),
('no castling dash', 'r3k2r/8/8/8/8/8/8/R3K2R b - - 3 20',
{'castling': '',
'ep': None,
'fullmove': 20,
'halfmove': 3,
'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
'turn': 'b'}),
('black rights only', 'r3k2r/8/8/8/8/8/8/R3K2R w kq - 0 5',
{'castling': 'kq',
'ep': None,
'fullmove': 5,
'halfmove': 0,
'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
'turn': 'w'}),
('two white kings', '4k3/8/8/8/8/8/8/K3K3 w - - 0 1', 'invalid'),
('two white kings no black', '8/8/8/8/8/8/8/K3K3 w - - 0 1', 'invalid')]]
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 |
|---|---|---|---|
| kings and rook | {'castling': 'Q', 'ep': None, 'fullmove': 1, 'halfmove': 0, 'pieces': {'a1': 'R', 'e1': 'K', 'e8': 'k'}, 'turn': 'w'} | {'castling': 'Q', 'ep': None, 'fullmove': 1, 'halfmove': 0, 'pieces': {'a1': 'R', 'e1': 'K', 'e8': 'k'}, 'turn': 'w'} | Passed |
| black to move ep | {'castling': '', 'ep': 'd3', 'fullmove': 12, 'halfmove': 0, 'pieces': {'d4': 'P', 'e1': 'K', 'e4': 'p', 'e8': 'k'}, 'turn': 'b'} | {'castling': '', 'ep': 'd3', 'fullmove': 12, 'halfmove': 0, 'pieces': {'d4': 'P', 'e1': 'K', 'e4': 'p', 'e8': 'k'}, 'turn': 'b'} | Passed |
| white ep target | {'castling': '', 'ep': 'd6', 'fullmove': 9, 'halfmove': 0, 'pieces': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'}, 'turn': 'w'} | {'castling': '', 'ep': 'd6', 'fullmove': 9, 'halfmove': 0, 'pieces': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'}, 'turn': 'w'} | Passed |
| ep wrong side | invalid | invalid | Passed |
| black rights only | {'castling': 'kq', 'ep': None, 'fullmove': 5, 'halfmove': 0, 'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'}, 'turn': 'w'} | {'castling': 'kq', 'ep': None, 'fullmove': 5, 'halfmove': 0, 'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'}, 'turn': 'w'} | Passed |
| two white kings | invalid | invalid | Passed |
| two white kings no black | invalid | invalid | Passed |
| missing black king | invalid | invalid | Passed |
SHA-256 / 53f10238e0510bf6d9c880ae9fa3c2efbd2b5d1de7c970b3dafb8ead58e56452
Verification & scope
A deterministic toy model with an explicitly stated contract; boards are {square: piece} with white upper-case and black lower-case pieces; no claim of full FIDE Laws conformance. 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:13.330763+00:00.
Case digest / 05273a0f89e28e26209fe33475cd1cbaab70367a8e4fb60ff703eebdf3977242