broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    def c(q): return ord(q[0])-97,int(q[1])-1
    wk,wq,bk=c(x['wk']),c(x['wq']),c(x['bk'])
    def queen_hits(t, occupied):
        if t==wq: return False
        df,dr=t[0]-wq[0],t[1]-wq[1]
        if not (df==0 or dr==0 or abs(df)==abs(dr)): return False
        sf=(df>0)-(df<0); sr=(dr>0)-(dr<0)
        f,r=wq[0]+sf,wq[1]+sr
        while (f,r)!=t:
            if (f,r) in occupied: return False
            f+=sf; r+=sr
        return True
    def near(a,b2): return max(abs(a[0]-b2[0]),abs(a[1]-b2[1]))<=1
    in_check=queen_hits(bk,{wk})
    moves=0
    for df in (-1,0,1):
        for dr in (-1,0,1):
            t=(bk[0]+df,bk[1]+dr)
            if not (0<=t[0]<8 and 0<=t[1]<8): continue
            if near(t,wk): continue
            if queen_hits(t,{wk}): continue
            moves+=1
    if moves: return 'ongoing'
    return 'checkmate' if in_check else 'stalemate'
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('corner stalemate', {'bk': 'a8', 'wk': 'c6', 'wq': 'b6'}, 'stalemate'),
  ('queen kiss mate', {'bk': 'a8', 'wk': 'b6', 'wq': 'b7'}, 'checkmate'),
  ('back rank long mate', {'bk': 'h8', 'wk': 'g6', 'wq': 'a8'}, 'checkmate'),
  ('capture free queen', {'bk': 'a8', 'wk': 'h1', 'wq': 'b7'}, 'ongoing'),
  ('queen check escape', {'bk': 'e5', 'wk': 'a1', 'wq': 'e1'}, 'ongoing'),
  ('stalemate h-file', {'bk': 'h8', 'wk': 'f7', 'wq': 'g6'}, 'stalemate'),
  ('queen behind white king', {'bk': 'a1', 'wk': 'b3', 'wq': 'b5'}, 'ongoing'),
  ('orthogonal free capture', {'bk': 'a8', 'wk': 'h1', 'wq': 'a7'}, 'ongoing')],
 [('corner stalemate', {'bk': 'a8', 'wk': 'c6', 'wq': 'b6'}, 'stalemate'),
  ('queen check escape', {'bk': 'e5', 'wk': 'a1', 'wq': 'e1'}, 'ongoing'),
  ('shielded by king', {'bk': 'e5', 'wk': 'e3', 'wq': 'e1'}, 'ongoing'),
  ('stalemate h-file', {'bk': 'h8', 'wk': 'f7', 'wq': 'g6'}, 'stalemate'),
  ('queen behind white king', {'bk': 'a1', 'wk': 'b3', 'wq': 'b5'}, 'ongoing'),
  ('mate with rank retreat', {'bk': 'b1', 'wk': 'a3', 'wq': 'd1'}, 'checkmate'),
  ('queen kiss far side', {'bk': 'b8', 'wk': 'a6', 'wq': 'd8'}, 'checkmate'),
  ('orthogonal free capture', {'bk': 'a8', 'wk': 'h1', 'wq': 'a7'}, 'ongoing')],
 [('corner stalemate', {'bk': 'a8', 'wk': 'c6', 'wq': 'b6'}, 'stalemate'),
  ('stalemate h-file', {'bk': 'h8', 'wk': 'f7', 'wq': 'g6'}, 'stalemate'),
  ('queen behind white king', {'bk': 'a1', 'wk': 'b3', 'wq': 'b5'}, 'ongoing'),
  ('queen kiss far side', {'bk': 'b8', 'wk': 'a6', 'wq': 'd8'}, 'checkmate'),
  ('edge mate', {'bk': 'e8', 'wk': 'e6', 'wq': 'e7'}, 'checkmate'),
  ('orthogonal free capture', {'bk': 'a8', 'wk': 'h1', 'wq': 'a7'}, 'ongoing'),
  ('far queen ongoing', {'bk': 'd5', 'wk': 'a1', 'wq': 'h2'}, 'ongoing'),
  ('king retreat along queen file', {'bk': 'd7', 'wk': 'a1', 'wq': 'd1'}, 'ongoing')],
 [('corner stalemate', {'bk': 'a8', 'wk': 'c6', 'wq': 'b6'}, 'stalemate'),
  ('queen kiss mate', {'bk': 'a8', 'wk': 'b6', 'wq': 'b7'}, 'checkmate'),
  ('back rank long mate', {'bk': 'h8', 'wk': 'g6', 'wq': 'a8'}, 'checkmate'),
  ('capture free queen', {'bk': 'a8', 'wk': 'h1', 'wq': 'b7'}, 'ongoing'),
  ('stalemate h-file', {'bk': 'h8', 'wk': 'f7', 'wq': 'g6'}, 'stalemate'),
  ('queen behind white king', {'bk': 'a1', 'wk': 'b3', 'wq': 'b5'}, 'ongoing'),
  ('orthogonal free capture', {'bk': 'a8', 'wk': 'h1', 'wq': 'a7'}, 'ongoing'),
  ('king retreat along queen file', {'bk': 'd7', 'wk': 'a1', 'wq': 'd1'}, 'ongoing')],
 [('corner stalemate', {'bk': 'a8', 'wk': 'c6', 'wq': 'b6'}, 'stalemate'),
  ('queen kiss mate', {'bk': 'a8', 'wk': 'b6', 'wq': 'b7'}, 'checkmate'),
  ('back rank long mate', {'bk': 'h8', 'wk': 'g6', 'wq': 'a8'}, 'checkmate'),
  ('capture free queen', {'bk': 'a8', 'wk': 'h1', 'wq': 'b7'}, 'ongoing'),
  ('queen check escape', {'bk': 'e5', 'wk': 'a1', 'wq': 'e1'}, 'ongoing'),
  ('stalemate h-file', {'bk': 'h8', 'wk': 'f7', 'wq': 'g6'}, 'stalemate'),
  ('queen behind white king', {'bk': 'a1', 'wk': 'b3', 'wq': 'b5'}, 'ongoing'),
  ('orthogonal free capture', {'bk': 'a8', 'wk': 'h1', 'wq': 'a7'}, 'ongoing')]]
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)

source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    def c(q): return ord(q[0])-97,int(q[1])-1
    wk,wq,bk=c(x['wk']),c(x['wq']),c(x['bk'])
    def queen_hits(t, occupied):
        if t==wq: return False
        df,dr=t[0]-wq[0],t[1]-wq[1]
        if not (df==0 or dr==0 or abs(df)==abs(dr)): return False
        sf=(df>0)-(df<0); sr=(dr>0)-(dr<0)
        f,r=wq[0]+sf,wq[1]+sr
        while (f,r)!=t:
            if (f,r) in occupied: return False
            f+=sf; r+=sr
        return True
    def near(a,b2): return max(abs(a[0]-b2[0]),abs(a[1]-b2[1]))<=1
    in_check=queen_hits(bk,{wk})
    moves=0
    for df in (-1,0,1):
        for dr in (-1,0,1):
            if not (df and dr): continue
            t=(bk[0]+df,bk[1]+dr)
            if not (0<=t[0]<8 and 0<=t[1]<8): continue
            if near(t,wk): continue
            if queen_hits(t,{wk}): continue
            moves+=1
    if moves: return 'ongoing'
    return 'checkmate' if in_check else 'stalemate'
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('corner stalemate', {'bk': 'a8', 'wk': 'c6', 'wq': 'b6'}, 'stalemate'),
  ('queen kiss mate', {'bk': 'a8', 'wk': 'b6', 'wq': 'b7'}, 'checkmate'),
  ('back rank long mate', {'bk': 'h8', 'wk': 'g6', 'wq': 'a8'}, 'checkmate'),
  ('capture free queen', {'bk': 'a8', 'wk': 'h1', 'wq': 'b7'}, 'ongoing'),
  ('queen check escape', {'bk': 'e5', 'wk': 'a1', 'wq': 'e1'}, 'ongoing'),
  ('stalemate h-file', {'bk': 'h8', 'wk': 'f7', 'wq': 'g6'}, 'stalemate'),
  ('queen behind white king', {'bk': 'a1', 'wk': 'b3', 'wq': 'b5'}, 'ongoing'),
  ('orthogonal free capture', {'bk': 'a8', 'wk': 'h1', 'wq': 'a7'}, 'ongoing')],
 [('corner stalemate', {'bk': 'a8', 'wk': 'c6', 'wq': 'b6'}, 'stalemate'),
  ('queen check escape', {'bk': 'e5', 'wk': 'a1', 'wq': 'e1'}, 'ongoing'),
  ('shielded by king', {'bk': 'e5', 'wk': 'e3', 'wq': 'e1'}, 'ongoing'),
  ('stalemate h-file', {'bk': 'h8', 'wk': 'f7', 'wq': 'g6'}, 'stalemate'),
  ('queen behind white king', {'bk': 'a1', 'wk': 'b3', 'wq': 'b5'}, 'ongoing'),
  ('mate with rank retreat', {'bk': 'b1', 'wk': 'a3', 'wq': 'd1'}, 'checkmate'),
  ('queen kiss far side', {'bk': 'b8', 'wk': 'a6', 'wq': 'd8'}, 'checkmate'),
  ('orthogonal free capture', {'bk': 'a8', 'wk': 'h1', 'wq': 'a7'}, 'ongoing')],
 [('corner stalemate', {'bk': 'a8', 'wk': 'c6', 'wq': 'b6'}, 'stalemate'),
  ('stalemate h-file', {'bk': 'h8', 'wk': 'f7', 'wq': 'g6'}, 'stalemate'),
  ('queen behind white king', {'bk': 'a1', 'wk': 'b3', 'wq': 'b5'}, 'ongoing'),
  ('queen kiss far side', {'bk': 'b8', 'wk': 'a6', 'wq': 'd8'}, 'checkmate'),
  ('edge mate', {'bk': 'e8', 'wk': 'e6', 'wq': 'e7'}, 'checkmate'),
  ('orthogonal free capture', {'bk': 'a8', 'wk': 'h1', 'wq': 'a7'}, 'ongoing'),
  ('far queen ongoing', {'bk': 'd5', 'wk': 'a1', 'wq': 'h2'}, 'ongoing'),
  ('king retreat along queen file', {'bk': 'd7', 'wk': 'a1', 'wq': 'd1'}, 'ongoing')],
 [('corner stalemate', {'bk': 'a8', 'wk': 'c6', 'wq': 'b6'}, 'stalemate'),
  ('queen kiss mate', {'bk': 'a8', 'wk': 'b6', 'wq': 'b7'}, 'checkmate'),
  ('back rank long mate', {'bk': 'h8', 'wk': 'g6', 'wq': 'a8'}, 'checkmate'),
  ('capture free queen', {'bk': 'a8', 'wk': 'h1', 'wq': 'b7'}, 'ongoing'),
  ('stalemate h-file', {'bk': 'h8', 'wk': 'f7', 'wq': 'g6'}, 'stalemate'),
  ('queen behind white king', {'bk': 'a1', 'wk': 'b3', 'wq': 'b5'}, 'ongoing'),
  ('orthogonal free capture', {'bk': 'a8', 'wk': 'h1', 'wq': 'a7'}, 'ongoing'),
  ('king retreat along queen file', {'bk': 'd7', 'wk': 'a1', 'wq': 'd1'}, 'ongoing')],
 [('corner stalemate', {'bk': 'a8', 'wk': 'c6', 'wq': 'b6'}, 'stalemate'),
  ('queen kiss mate', {'bk': 'a8', 'wk': 'b6', 'wq': 'b7'}, 'checkmate'),
  ('back rank long mate', {'bk': 'h8', 'wk': 'g6', 'wq': 'a8'}, 'checkmate'),
  ('capture free queen', {'bk': 'a8', 'wk': 'h1', 'wq': 'b7'}, 'ongoing'),
  ('queen check escape', {'bk': 'e5', 'wk': 'a1', 'wq': 'e1'}, 'ongoing'),
  ('stalemate h-file', {'bk': 'h8', 'wk': 'f7', 'wq': 'g6'}, 'stalemate'),
  ('queen behind white king', {'bk': 'a1', 'wk': 'b3', 'wq': 'b5'}, 'ongoing'),
  ('orthogonal free capture', {'bk': 'a8', 'wk': 'h1', 'wq': 'a7'}, 'ongoing')]]
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)

prompt:
Stalemated kings are reported as "ongoing".

Input: {"wk", "wq", "bk"} squares, black to move. Return "checkmate" if black has no legal king move and is attacked by the queen, "stalemate" if it has none and is not attacked, else "ongoing". The queen attacks along ranks, files and diagonals and is blocked only by the white king; the black king may capture the queen when it is not adjacent to the white king.

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    b=dict(x['board']); fr,to=x['move'][:2]; p=b.pop(fr)
    pass
    b[to]=p
    white=p.isupper()
    ks=[s for s,v in b.items() if v==('k' if white else 'K')][0]
    def hits(src, tgt):
        v=b[src]; t=v.upper()
        f,r=ord(src[0])-97,int(src[1])-1
        tf,tr=ord(tgt[0])-97,int(tgt[1])-1
        df,dr=tf-f,tr-r
        if t=='P': return abs(df)==1 and dr==(1 if v.isupper() else -1)
        if t=='N': return (abs(df),abs(dr)) in ((1,2),(2,1))
        if t=='K': return max(abs(df),abs(dr))==1
        orth=(df==0)!=(dr==0); diag=abs(df)==abs(dr) and df!=0
        if not ((t in ('R','Q') and orth) or (t in ('B','Q') and diag)): return False
        sf=(df>0)-(df<0); sr=(dr>0)-(dr<0)
        cf,cr=f+sf,r+sr
        while (cf,cr)!=(tf,tr):
            if chr(97+cf)+str(cr+1) in b: return False
            cf+=sf; cr+=sr
        return True
    direct=hits(to,ks)
    disc=any(hits(s,ks) for s,v in b.items() if s!=to and v.isupper()==white and v.upper()!='K')
    if direct and disc: return 'double'
    if direct: return 'direct'
    if disc: return 'discovered'
    return 'none'
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('promotion gives check', {'board': {'a1': 'K', 'b7': 'P', 'e8': 'k'}, 'move': ['b7', 'b8', 'q']},
   'direct'),
  ('knight promotion check',
   {'board': {'a1': 'K', 'e7': 'P', 'g7': 'k'}, 'move': ['e7', 'e8', 'n']}, 'direct'),
  ('simple direct', {'board': {'b1': 'N', 'd4': 'k', 'h1': 'K'}, 'move': ['b1', 'c2']}, 'direct'),
  ('discovered by bishop',
   {'board': {'a1': 'K', 'c3': 'B', 'd4': 'N', 'h8': 'k'}, 'move': ['d4', 'b5']}, 'discovered'),
  ('double check', {'board': {'a1': 'K', 'e1': 'R', 'e4': 'N', 'e8': 'k'}, 'move': ['e4', 'f6']},
   'double'),
  ('queen diagonal direct', {'board': {'a2': 'K', 'd1': 'Q', 'h8': 'k'}, 'move': ['d1', 'd4']},
   'direct'),
  ('rook lands on king diagonal',
   {'board': {'b1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['b1', 'b2']}, 'none'),
  ('rook quiet', {'board': {'a1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['a1', 'b1']}, 'none')],
 [('promotion gives check', {'board': {'a1': 'K', 'b7': 'P', 'e8': 'k'}, 'move': ['b7', 'b8', 'q']},
   'direct'),
  ('knight promotion check',
   {'board': {'a1': 'K', 'e7': 'P', 'g7': 'k'}, 'move': ['e7', 'e8', 'n']}, 'direct'),
  ('queen diagonal direct', {'board': {'a2': 'K', 'd1': 'Q', 'h8': 'k'}, 'move': ['d1', 'd4']},
   'direct'),
  ('rook lands on king diagonal',
   {'board': {'b1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['b1', 'b2']}, 'none'),
  ('rook quiet', {'board': {'a1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['a1', 'b1']}, 'none'),
  ('black rook direct', {'board': {'a8': 'r', 'e1': 'K', 'h8': 'k'}, 'move': ['a8', 'a1']},
   'direct'),
  ('defender rook on own king line',
   {'board': {'a1': 'K', 'b1': 'N', 'e5': 'r', 'e8': 'k'}, 'move': ['b1', 'c3']}, 'none'),
  ('black discovered',
   {'board': {'a8': 'k', 'e1': 'K', 'e7': 'n', 'e8': 'r'}, 'move': ['e7', 'c6']}, 'discovered')],
 [('promotion gives check', {'board': {'a1': 'K', 'b7': 'P', 'e8': 'k'}, 'move': ['b7', 'b8', 'q']},
   'direct'),
  ('knight promotion check',
   {'board': {'a1': 'K', 'e7': 'P', 'g7': 'k'}, 'move': ['e7', 'e8', 'n']}, 'direct'),
  ('black rook direct', {'board': {'a8': 'r', 'e1': 'K', 'h8': 'k'}, 'move': ['a8', 'a1']},
   'direct'),
  ('defender rook on own king line',
   {'board': {'a1': 'K', 'b1': 'N', 'e5': 'r', 'e8': 'k'}, 'move': ['b1', 'c3']}, 'none'),
  ('black discovered',
   {'board': {'a8': 'k', 'e1': 'K', 'e7': 'n', 'e8': 'r'}, 'move': ['e7', 'c6']}, 'discovered'),
  ('bishop direct', {'board': {'a1': 'K', 'e8': 'k', 'f1': 'B'}, 'move': ['f1', 'b5']}, 'direct'),
  ('pawn push check', {'board': {'a1': 'K', 'd5': 'P', 'e7': 'k'}, 'move': ['d5', 'd6']}, 'direct'),
  ('white piece near own line',
   {'board': {'a1': 'K', 'a2': 'r', 'c1': 'B', 'e3': 'P', 'h6': 'k'}, 'move': ['e3', 'e4']},
   'discovered')],
 [('promotion gives check', {'board': {'a1': 'K', 'b7': 'P', 'e8': 'k'}, 'move': ['b7', 'b8', 'q']},
   'direct'),
  ('knight promotion check',
   {'board': {'a1': 'K', 'e7': 'P', 'g7': 'k'}, 'move': ['e7', 'e8', 'n']}, 'direct'),
  ('simple direct', {'board': {'b1': 'N', 'd4': 'k', 'h1': 'K'}, 'move': ['b1', 'c2']}, 'direct'),
  ('discovered by bishop',
   {'board': {'a1': 'K', 'c3': 'B', 'd4': 'N', 'h8': 'k'}, 'move': ['d4', 'b5']}, 'discovered'),
  ('double check', {'board': {'a1': 'K', 'e1': 'R', 'e4': 'N', 'e8': 'k'}, 'move': ['e4', 'f6']},
   'double'),
  ('bishop direct', {'board': {'a1': 'K', 'e8': 'k', 'f1': 'B'}, 'move': ['f1', 'b5']}, 'direct'),
  ('pawn push check', {'board': {'a1': 'K', 'd5': 'P', 'e7': 'k'}, 'move': ['d5', 'd6']}, 'direct'),
  ('white piece near own line',
   {'board': {'a1': 'K', 'a2': 'r', 'c1': 'B', 'e3': 'P', 'h6': 'k'}, 'move': ['e3', 'e4']},
   'discovered')],
 [('promotion gives check', {'board': {'a1': 'K', 'b7': 'P', 'e8': 'k'}, 'move': ['b7', 'b8', 'q']},
   'direct'),
  ('knight promotion check',
   {'board': {'a1': 'K', 'e7': 'P', 'g7': 'k'}, 'move': ['e7', 'e8', 'n']}, 'direct'),
  ('simple direct', {'board': {'b1': 'N', 'd4': 'k', 'h1': 'K'}, 'move': ['b1', 'c2']}, 'direct'),
  ('discovered by bishop',
   {'board': {'a1': 'K', 'c3': 'B', 'd4': 'N', 'h8': 'k'}, 'move': ['d4', 'b5']}, 'discovered'),
  ('double check', {'board': {'a1': 'K', 'e1': 'R', 'e4': 'N', 'e8': 'k'}, 'move': ['e4', 'f6']},
   'double'),
  ('queen diagonal direct', {'board': {'a2': 'K', 'd1': 'Q', 'h8': 'k'}, 'move': ['d1', 'd4']},
   'direct'),
  ('rook lands on king diagonal',
   {'board': {'b1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['b1', 'b2']}, 'none'),
  ('rook quiet', {'board': {'a1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['a1', 'b1']}, 'none')]]
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)

meaning: Fixture-count band, not measured model difficulty

deps: stdlib

source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    b=dict(x['board']); fr,to=x['move'][:2]; p=b.pop(fr)
    if len(x['move'])>2: p=x['move'][2]
    b[to]=p
    white=p.isupper()
    ks=[s for s,v in b.items() if v==('k' if white else 'K')][0]
    def hits(src, tgt):
        v=b[src]; t=v.upper()
        f,r=ord(src[0])-97,int(src[1])-1
        tf,tr=ord(tgt[0])-97,int(tgt[1])-1
        df,dr=tf-f,tr-r
        if t=='P': return abs(df)==1 and dr==(1 if v.isupper() else -1)
        if t=='N': return (abs(df),abs(dr)) in ((1,2),(2,1))
        if t=='K': return max(abs(df),abs(dr))==1
        orth=(df==0)!=(dr==0); diag=abs(df)==abs(dr) and df!=0
        if not ((t in ('R','Q') and orth) or (t in ('B','Q') and diag)): return False
        sf=(df>0)-(df<0); sr=(dr>0)-(dr<0)
        cf,cr=f+sf,r+sr
        while (cf,cr)!=(tf,tr):
            if chr(97+cf)+str(cr+1) in b: return False
            cf+=sf; cr+=sr
        return True
    direct=hits(to,ks)
    disc=any(hits(s,ks) for s,v in b.items() if s!=to and v.isupper()==white and v.upper()!='K')
    if direct and disc: return 'double'
    if direct: return 'direct'
    if disc: return 'discovered'
    return 'none'
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('promotion gives check', {'board': {'a1': 'K', 'b7': 'P', 'e8': 'k'}, 'move': ['b7', 'b8', 'q']},
   'direct'),
  ('knight promotion check',
   {'board': {'a1': 'K', 'e7': 'P', 'g7': 'k'}, 'move': ['e7', 'e8', 'n']}, 'direct'),
  ('simple direct', {'board': {'b1': 'N', 'd4': 'k', 'h1': 'K'}, 'move': ['b1', 'c2']}, 'direct'),
  ('discovered by bishop',
   {'board': {'a1': 'K', 'c3': 'B', 'd4': 'N', 'h8': 'k'}, 'move': ['d4', 'b5']}, 'discovered'),
  ('double check', {'board': {'a1': 'K', 'e1': 'R', 'e4': 'N', 'e8': 'k'}, 'move': ['e4', 'f6']},
   'double'),
  ('queen diagonal direct', {'board': {'a2': 'K', 'd1': 'Q', 'h8': 'k'}, 'move': ['d1', 'd4']},
   'direct'),
  ('rook lands on king diagonal',
   {'board': {'b1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['b1', 'b2']}, 'none'),
  ('rook quiet', {'board': {'a1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['a1', 'b1']}, 'none')],
 [('promotion gives check', {'board': {'a1': 'K', 'b7': 'P', 'e8': 'k'}, 'move': ['b7', 'b8', 'q']},
   'direct'),
  ('knight promotion check',
   {'board': {'a1': 'K', 'e7': 'P', 'g7': 'k'}, 'move': ['e7', 'e8', 'n']}, 'direct'),
  ('queen diagonal direct', {'board': {'a2': 'K', 'd1': 'Q', 'h8': 'k'}, 'move': ['d1', 'd4']},
   'direct'),
  ('rook lands on king diagonal',
   {'board': {'b1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['b1', 'b2']}, 'none'),
  ('rook quiet', {'board': {'a1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['a1', 'b1']}, 'none'),
  ('black rook direct', {'board': {'a8': 'r', 'e1': 'K', 'h8': 'k'}, 'move': ['a8', 'a1']},
   'direct'),
  ('defender rook on own king line',
   {'board': {'a1': 'K', 'b1': 'N', 'e5': 'r', 'e8': 'k'}, 'move': ['b1', 'c3']}, 'none'),
  ('black discovered',
   {'board': {'a8': 'k', 'e1': 'K', 'e7': 'n', 'e8': 'r'}, 'move': ['e7', 'c6']}, 'discovered')],
 [('promotion gives check', {'board': {'a1': 'K', 'b7': 'P', 'e8': 'k'}, 'move': ['b7', 'b8', 'q']},
   'direct'),
  ('knight promotion check',
   {'board': {'a1': 'K', 'e7': 'P', 'g7': 'k'}, 'move': ['e7', 'e8', 'n']}, 'direct'),
  ('black rook direct', {'board': {'a8': 'r', 'e1': 'K', 'h8': 'k'}, 'move': ['a8', 'a1']},
   'direct'),
  ('defender rook on own king line',
   {'board': {'a1': 'K', 'b1': 'N', 'e5': 'r', 'e8': 'k'}, 'move': ['b1', 'c3']}, 'none'),
  ('black discovered',
   {'board': {'a8': 'k', 'e1': 'K', 'e7': 'n', 'e8': 'r'}, 'move': ['e7', 'c6']}, 'discovered'),
  ('bishop direct', {'board': {'a1': 'K', 'e8': 'k', 'f1': 'B'}, 'move': ['f1', 'b5']}, 'direct'),
  ('pawn push check', {'board': {'a1': 'K', 'd5': 'P', 'e7': 'k'}, 'move': ['d5', 'd6']}, 'direct'),
  ('white piece near own line',
   {'board': {'a1': 'K', 'a2': 'r', 'c1': 'B', 'e3': 'P', 'h6': 'k'}, 'move': ['e3', 'e4']},
   'discovered')],
 [('promotion gives check', {'board': {'a1': 'K', 'b7': 'P', 'e8': 'k'}, 'move': ['b7', 'b8', 'q']},
   'direct'),
  ('knight promotion check',
   {'board': {'a1': 'K', 'e7': 'P', 'g7': 'k'}, 'move': ['e7', 'e8', 'n']}, 'direct'),
  ('simple direct', {'board': {'b1': 'N', 'd4': 'k', 'h1': 'K'}, 'move': ['b1', 'c2']}, 'direct'),
  ('discovered by bishop',
   {'board': {'a1': 'K', 'c3': 'B', 'd4': 'N', 'h8': 'k'}, 'move': ['d4', 'b5']}, 'discovered'),
  ('double check', {'board': {'a1': 'K', 'e1': 'R', 'e4': 'N', 'e8': 'k'}, 'move': ['e4', 'f6']},
   'double'),
  ('bishop direct', {'board': {'a1': 'K', 'e8': 'k', 'f1': 'B'}, 'move': ['f1', 'b5']}, 'direct'),
  ('pawn push check', {'board': {'a1': 'K', 'd5': 'P', 'e7': 'k'}, 'move': ['d5', 'd6']}, 'direct'),
  ('white piece near own line',
   {'board': {'a1': 'K', 'a2': 'r', 'c1': 'B', 'e3': 'P', 'h6': 'k'}, 'move': ['e3', 'e4']},
   'discovered')],
 [('promotion gives check', {'board': {'a1': 'K', 'b7': 'P', 'e8': 'k'}, 'move': ['b7', 'b8', 'q']},
   'direct'),
  ('knight promotion check',
   {'board': {'a1': 'K', 'e7': 'P', 'g7': 'k'}, 'move': ['e7', 'e8', 'n']}, 'direct'),
  ('simple direct', {'board': {'b1': 'N', 'd4': 'k', 'h1': 'K'}, 'move': ['b1', 'c2']}, 'direct'),
  ('discovered by bishop',
   {'board': {'a1': 'K', 'c3': 'B', 'd4': 'N', 'h8': 'k'}, 'move': ['d4', 'b5']}, 'discovered'),
  ('double check', {'board': {'a1': 'K', 'e1': 'R', 'e4': 'N', 'e8': 'k'}, 'move': ['e4', 'f6']},
   'double'),
  ('queen diagonal direct', {'board': {'a2': 'K', 'd1': 'Q', 'h8': 'k'}, 'move': ['d1', 'd4']},
   'direct'),
  ('rook lands on king diagonal',
   {'board': {'b1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['b1', 'b2']}, 'none'),
  ('rook quiet', {'board': {'a1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['a1', 'b1']}, 'none')]]
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)

prompt:
b7-b8=Q with the king on e8 is classified "none".

Input: {"board", "move": [from, to] or [from, to, promotion letter]}. Apply the move (promotion letter becomes a piece of the mover's colour) and classify the check it gives to the enemy king: "direct" (the moved piece attacks it), "discovered" (another of the mover's pieces now attacks it), "double" (both) or "none". Pawns attack diagonally forward, sliders need a clear path.

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    b=dict(x['board']); fr,to=x['move'][:2]; p=b.pop(fr)
    if len(x['move'])>2: p=x['move'][2].upper() if p.isupper() else x['move'][2].lower()
    b[to]=p
    white=p.isupper()
    ks=[s for s,v in b.items() if v==('k' if white else 'K')][0]
    def hits(src, tgt):
        v=b[src]; t=v.upper()
        f,r=ord(src[0])-97,int(src[1])-1
        tf,tr=ord(tgt[0])-97,int(tgt[1])-1
        df,dr=tf-f,tr-r
        if t=='P': return abs(df)==1 and dr==(1 if v.isupper() else -1)
        if t=='N': return (abs(df),abs(dr)) in ((1,2),(2,1))
        if t=='K': return max(abs(df),abs(dr))==1
        orth=(df==0)!=(dr==0); diag=abs(df)==abs(dr) and df!=0
        if not ((t in ('R','Q') and orth) or (t in ('B','Q') and diag)): return False
        sf=(df>0)-(df<0); sr=(dr>0)-(dr<0)
        cf,cr=f+sf,r+sr
        while (cf,cr)!=(tf,tr):
            if chr(97+cf)+str(cr+1) in b: return False
            cf+=sf; cr+=sr
        return True
    direct=hits(to,ks)
    disc=any(hits(s,ks) for s,v in b.items() if v.isupper()==white and v.upper()!='K')
    if direct and disc: return 'double'
    if direct: return 'direct'
    if disc: return 'discovered'
    return 'none'
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('promotion gives check', {'board': {'a1': 'K', 'b7': 'P', 'e8': 'k'}, 'move': ['b7', 'b8', 'q']},
   'direct'),
  ('knight promotion check',
   {'board': {'a1': 'K', 'e7': 'P', 'g7': 'k'}, 'move': ['e7', 'e8', 'n']}, 'direct'),
  ('discovered by bishop',
   {'board': {'a1': 'K', 'c3': 'B', 'd4': 'N', 'h8': 'k'}, 'move': ['d4', 'b5']}, 'discovered'),
  ('double check', {'board': {'a1': 'K', 'e1': 'R', 'e4': 'N', 'e8': 'k'}, 'move': ['e4', 'f6']},
   'double'),
  ('rook lands on king diagonal',
   {'board': {'b1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['b1', 'b2']}, 'none'),
  ('rook quiet', {'board': {'a1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['a1', 'b1']}, 'none'),
  ('defender rook on own king line',
   {'board': {'a1': 'K', 'b1': 'N', 'e5': 'r', 'e8': 'k'}, 'move': ['b1', 'c3']}, 'none'),
  ('black discovered',
   {'board': {'a8': 'k', 'e1': 'K', 'e7': 'n', 'e8': 'r'}, 'move': ['e7', 'c6']}, 'discovered')],
 [('promotion gives check', {'board': {'a1': 'K', 'b7': 'P', 'e8': 'k'}, 'move': ['b7', 'b8', 'q']},
   'direct'),
  ('knight promotion check',
   {'board': {'a1': 'K', 'e7': 'P', 'g7': 'k'}, 'move': ['e7', 'e8', 'n']}, 'direct'),
  ('simple direct', {'board': {'b1': 'N', 'd4': 'k', 'h1': 'K'}, 'move': ['b1', 'c2']}, 'direct'),
  ('queen diagonal direct', {'board': {'a2': 'K', 'd1': 'Q', 'h8': 'k'}, 'move': ['d1', 'd4']},
   'direct'),
  ('rook quiet', {'board': {'a1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['a1', 'b1']}, 'none'),
  ('defender rook on own king line',
   {'board': {'a1': 'K', 'b1': 'N', 'e5': 'r', 'e8': 'k'}, 'move': ['b1', 'c3']}, 'none'),
  ('black discovered',
   {'board': {'a8': 'k', 'e1': 'K', 'e7': 'n', 'e8': 'r'}, 'move': ['e7', 'c6']}, 'discovered'),
  ('white piece near own line',
   {'board': {'a1': 'K', 'a2': 'r', 'c1': 'B', 'e3': 'P', 'h6': 'k'}, 'move': ['e3', 'e4']},
   'discovered')],
 [('promotion gives check', {'board': {'a1': 'K', 'b7': 'P', 'e8': 'k'}, 'move': ['b7', 'b8', 'q']},
   'direct'),
  ('knight promotion check',
   {'board': {'a1': 'K', 'e7': 'P', 'g7': 'k'}, 'move': ['e7', 'e8', 'n']}, 'direct'),
  ('simple direct', {'board': {'b1': 'N', 'd4': 'k', 'h1': 'K'}, 'move': ['b1', 'c2']}, 'direct'),
  ('queen diagonal direct', {'board': {'a2': 'K', 'd1': 'Q', 'h8': 'k'}, 'move': ['d1', 'd4']},
   'direct'),
  ('black rook direct', {'board': {'a8': 'r', 'e1': 'K', 'h8': 'k'}, 'move': ['a8', 'a1']},
   'direct'),
  ('bishop direct', {'board': {'a1': 'K', 'e8': 'k', 'f1': 'B'}, 'move': ['f1', 'b5']}, 'direct'),
  ('pawn push check', {'board': {'a1': 'K', 'd5': 'P', 'e7': 'k'}, 'move': ['d5', 'd6']}, 'direct'),
  ('white piece near own line',
   {'board': {'a1': 'K', 'a2': 'r', 'c1': 'B', 'e3': 'P', 'h6': 'k'}, 'move': ['e3', 'e4']},
   'discovered')],
 [('simple direct', {'board': {'b1': 'N', 'd4': 'k', 'h1': 'K'}, 'move': ['b1', 'c2']}, 'direct'),
  ('discovered by bishop',
   {'board': {'a1': 'K', 'c3': 'B', 'd4': 'N', 'h8': 'k'}, 'move': ['d4', 'b5']}, 'discovered'),
  ('double check', {'board': {'a1': 'K', 'e1': 'R', 'e4': 'N', 'e8': 'k'}, 'move': ['e4', 'f6']},
   'double'),
  ('queen diagonal direct', {'board': {'a2': 'K', 'd1': 'Q', 'h8': 'k'}, 'move': ['d1', 'd4']},
   'direct'),
  ('rook lands on king diagonal',
   {'board': {'b1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['b1', 'b2']}, 'none'),
  ('black rook direct', {'board': {'a8': 'r', 'e1': 'K', 'h8': 'k'}, 'move': ['a8', 'a1']},
   'direct'),
  ('bishop direct', {'board': {'a1': 'K', 'e8': 'k', 'f1': 'B'}, 'move': ['f1', 'b5']}, 'direct'),
  ('pawn push check', {'board': {'a1': 'K', 'd5': 'P', 'e7': 'k'}, 'move': ['d5', 'd6']},
   'direct')],
 [('discovered by bishop',
   {'board': {'a1': 'K', 'c3': 'B', 'd4': 'N', 'h8': 'k'}, 'move': ['d4', 'b5']}, 'discovered'),
  ('double check', {'board': {'a1': 'K', 'e1': 'R', 'e4': 'N', 'e8': 'k'}, 'move': ['e4', 'f6']},
   'double'),
  ('rook lands on king diagonal',
   {'board': {'b1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['b1', 'b2']}, 'none'),
  ('rook quiet', {'board': {'a1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['a1', 'b1']}, 'none'),
  ('black rook direct', {'board': {'a8': 'r', 'e1': 'K', 'h8': 'k'}, 'move': ['a8', 'a1']},
   'direct'),
  ('defender rook on own king line',
   {'board': {'a1': 'K', 'b1': 'N', 'e5': 'r', 'e8': 'k'}, 'move': ['b1', 'c3']}, 'none'),
  ('bishop direct', {'board': {'a1': 'K', 'e8': 'k', 'f1': 'B'}, 'move': ['f1', 'b5']}, 'direct'),
  ('pawn push check', {'board': {'a1': 'K', 'd5': 'P', 'e7': 'k'}, 'move': ['d5', 'd6']},
   'direct')]]
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)

source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    b=dict(x['board']); fr,to=x['move'][:2]; p=b.pop(fr)
    if len(x['move'])>2: p=x['move'][2].upper() if p.isupper() else x['move'][2].lower()
    b[to]=p
    white=p.isupper()
    ks=[s for s,v in b.items() if v==('k' if white else 'K')][0]
    def hits(src, tgt):
        v=b[src]; t=v.upper()
        f,r=ord(src[0])-97,int(src[1])-1
        tf,tr=ord(tgt[0])-97,int(tgt[1])-1
        df,dr=tf-f,tr-r
        if t=='P': return abs(df)==1 and dr==(1 if v.isupper() else -1)
        if t=='N': return (abs(df),abs(dr)) in ((1,2),(2,1))
        if t=='K': return max(abs(df),abs(dr))==1
        orth=(df==0)!=(dr==0); diag=abs(df)==abs(dr) and df!=0
        if not ((t in ('R','Q') and orth) or (t in ('B','Q') and diag)): return False
        sf=(df>0)-(df<0); sr=(dr>0)-(dr<0)
        cf,cr=f+sf,r+sr
        while (cf,cr)!=(tf,tr):
            if chr(97+cf)+str(cr+1) in b: return False
            cf+=sf; cr+=sr
        return True
    direct=hits(to,ks)
    disc=any(hits(s,ks) for s,v in b.items() if s!=fr and v.isupper()==white and v.upper()!='K')
    if direct and disc: return 'double'
    if direct: return 'direct'
    if disc: return 'discovered'
    return 'none'
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('promotion gives check', {'board': {'a1': 'K', 'b7': 'P', 'e8': 'k'}, 'move': ['b7', 'b8', 'q']},
   'direct'),
  ('knight promotion check',
   {'board': {'a1': 'K', 'e7': 'P', 'g7': 'k'}, 'move': ['e7', 'e8', 'n']}, 'direct'),
  ('discovered by bishop',
   {'board': {'a1': 'K', 'c3': 'B', 'd4': 'N', 'h8': 'k'}, 'move': ['d4', 'b5']}, 'discovered'),
  ('double check', {'board': {'a1': 'K', 'e1': 'R', 'e4': 'N', 'e8': 'k'}, 'move': ['e4', 'f6']},
   'double'),
  ('rook lands on king diagonal',
   {'board': {'b1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['b1', 'b2']}, 'none'),
  ('rook quiet', {'board': {'a1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['a1', 'b1']}, 'none'),
  ('defender rook on own king line',
   {'board': {'a1': 'K', 'b1': 'N', 'e5': 'r', 'e8': 'k'}, 'move': ['b1', 'c3']}, 'none'),
  ('black discovered',
   {'board': {'a8': 'k', 'e1': 'K', 'e7': 'n', 'e8': 'r'}, 'move': ['e7', 'c6']}, 'discovered')],
 [('promotion gives check', {'board': {'a1': 'K', 'b7': 'P', 'e8': 'k'}, 'move': ['b7', 'b8', 'q']},
   'direct'),
  ('knight promotion check',
   {'board': {'a1': 'K', 'e7': 'P', 'g7': 'k'}, 'move': ['e7', 'e8', 'n']}, 'direct'),
  ('simple direct', {'board': {'b1': 'N', 'd4': 'k', 'h1': 'K'}, 'move': ['b1', 'c2']}, 'direct'),
  ('queen diagonal direct', {'board': {'a2': 'K', 'd1': 'Q', 'h8': 'k'}, 'move': ['d1', 'd4']},
   'direct'),
  ('rook quiet', {'board': {'a1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['a1', 'b1']}, 'none'),
  ('defender rook on own king line',
   {'board': {'a1': 'K', 'b1': 'N', 'e5': 'r', 'e8': 'k'}, 'move': ['b1', 'c3']}, 'none'),
  ('black discovered',
   {'board': {'a8': 'k', 'e1': 'K', 'e7': 'n', 'e8': 'r'}, 'move': ['e7', 'c6']}, 'discovered'),
  ('white piece near own line',
   {'board': {'a1': 'K', 'a2': 'r', 'c1': 'B', 'e3': 'P', 'h6': 'k'}, 'move': ['e3', 'e4']},
   'discovered')],
 [('promotion gives check', {'board': {'a1': 'K', 'b7': 'P', 'e8': 'k'}, 'move': ['b7', 'b8', 'q']},
   'direct'),
  ('knight promotion check',
   {'board': {'a1': 'K', 'e7': 'P', 'g7': 'k'}, 'move': ['e7', 'e8', 'n']}, 'direct'),
  ('simple direct', {'board': {'b1': 'N', 'd4': 'k', 'h1': 'K'}, 'move': ['b1', 'c2']}, 'direct'),
  ('queen diagonal direct', {'board': {'a2': 'K', 'd1': 'Q', 'h8': 'k'}, 'move': ['d1', 'd4']},
   'direct'),
  ('black rook direct', {'board': {'a8': 'r', 'e1': 'K', 'h8': 'k'}, 'move': ['a8', 'a1']},
   'direct'),
  ('bishop direct', {'board': {'a1': 'K', 'e8': 'k', 'f1': 'B'}, 'move': ['f1', 'b5']}, 'direct'),
  ('pawn push check', {'board': {'a1': 'K', 'd5': 'P', 'e7': 'k'}, 'move': ['d5', 'd6']}, 'direct'),
  ('white piece near own line',
   {'board': {'a1': 'K', 'a2': 'r', 'c1': 'B', 'e3': 'P', 'h6': 'k'}, 'move': ['e3', 'e4']},
   'discovered')],
 [('simple direct', {'board': {'b1': 'N', 'd4': 'k', 'h1': 'K'}, 'move': ['b1', 'c2']}, 'direct'),
  ('discovered by bishop',
   {'board': {'a1': 'K', 'c3': 'B', 'd4': 'N', 'h8': 'k'}, 'move': ['d4', 'b5']}, 'discovered'),
  ('double check', {'board': {'a1': 'K', 'e1': 'R', 'e4': 'N', 'e8': 'k'}, 'move': ['e4', 'f6']},
   'double'),
  ('queen diagonal direct', {'board': {'a2': 'K', 'd1': 'Q', 'h8': 'k'}, 'move': ['d1', 'd4']},
   'direct'),
  ('rook lands on king diagonal',
   {'board': {'b1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['b1', 'b2']}, 'none'),
  ('black rook direct', {'board': {'a8': 'r', 'e1': 'K', 'h8': 'k'}, 'move': ['a8', 'a1']},
   'direct'),
  ('bishop direct', {'board': {'a1': 'K', 'e8': 'k', 'f1': 'B'}, 'move': ['f1', 'b5']}, 'direct'),
  ('pawn push check', {'board': {'a1': 'K', 'd5': 'P', 'e7': 'k'}, 'move': ['d5', 'd6']},
   'direct')],
 [('discovered by bishop',
   {'board': {'a1': 'K', 'c3': 'B', 'd4': 'N', 'h8': 'k'}, 'move': ['d4', 'b5']}, 'discovered'),
  ('double check', {'board': {'a1': 'K', 'e1': 'R', 'e4': 'N', 'e8': 'k'}, 'move': ['e4', 'f6']},
   'double'),
  ('rook lands on king diagonal',
   {'board': {'b1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['b1', 'b2']}, 'none'),
  ('rook quiet', {'board': {'a1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['a1', 'b1']}, 'none'),
  ('black rook direct', {'board': {'a8': 'r', 'e1': 'K', 'h8': 'k'}, 'move': ['a8', 'a1']},
   'direct'),
  ('defender rook on own king line',
   {'board': {'a1': 'K', 'b1': 'N', 'e5': 'r', 'e8': 'k'}, 'move': ['b1', 'c3']}, 'none'),
  ('bishop direct', {'board': {'a1': 'K', 'e8': 'k', 'f1': 'B'}, 'move': ['f1', 'b5']}, 'direct'),
  ('pawn push check', {'board': {'a1': 'K', 'd5': 'P', 'e7': 'k'}, 'move': ['d5', 'd6']},
   'direct')]]
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)

prompt:
A knight check with no other attacker is classified "double".

Input: {"board", "move": [from, to] or [from, to, promotion letter]}. Apply the move (promotion letter becomes a piece of the mover's colour) and classify the check it gives to the enemy king: "direct" (the moved piece attacks it), "discovered" (another of the mover's pieces now attacks it), "double" (both) or "none". Pawns attack diagonally forward, sliders need a clear path.

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    b=dict(x['board']); fr,to=x['move'][:2]; p=b.pop(fr)
    if len(x['move'])>2: p=x['move'][2].upper() if p.isupper() else x['move'][2].lower()
    b[to]=p
    white=p.isupper()
    ks=[s for s,v in b.items() if v==('k' if white else 'K')][0]
    def hits(src, tgt):
        v=b[src]; t=v.upper()
        f,r=ord(src[0])-97,int(src[1])-1
        tf,tr=ord(tgt[0])-97,int(tgt[1])-1
        df,dr=tf-f,tr-r
        if t=='P': return abs(df)==1 and dr==(1 if v.isupper() else -1)
        if t=='N': return (abs(df),abs(dr)) in ((1,2),(2,1))
        if t=='K': return max(abs(df),abs(dr))==1
        orth=(df==0)!=(dr==0); diag=abs(df)==abs(dr) and df!=0
        if not ((t in ('R','Q') and orth) or (t=='B' and diag)): return False
        sf=(df>0)-(df<0); sr=(dr>0)-(dr<0)
        cf,cr=f+sf,r+sr
        while (cf,cr)!=(tf,tr):
            if chr(97+cf)+str(cr+1) in b: return False
            cf+=sf; cr+=sr
        return True
    direct=hits(to,ks)
    disc=any(hits(s,ks) for s,v in b.items() if s!=to and v.isupper()==white and v.upper()!='K')
    if direct and disc: return 'double'
    if direct: return 'direct'
    if disc: return 'discovered'
    return 'none'
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('promotion gives check', {'board': {'a1': 'K', 'b7': 'P', 'e8': 'k'}, 'move': ['b7', 'b8', 'q']},
   'direct'),
  ('knight promotion check',
   {'board': {'a1': 'K', 'e7': 'P', 'g7': 'k'}, 'move': ['e7', 'e8', 'n']}, 'direct'),
  ('simple direct', {'board': {'b1': 'N', 'd4': 'k', 'h1': 'K'}, 'move': ['b1', 'c2']}, 'direct'),
  ('discovered by bishop',
   {'board': {'a1': 'K', 'c3': 'B', 'd4': 'N', 'h8': 'k'}, 'move': ['d4', 'b5']}, 'discovered'),
  ('double check', {'board': {'a1': 'K', 'e1': 'R', 'e4': 'N', 'e8': 'k'}, 'move': ['e4', 'f6']},
   'double'),
  ('queen diagonal direct', {'board': {'a2': 'K', 'd1': 'Q', 'h8': 'k'}, 'move': ['d1', 'd4']},
   'direct'),
  ('rook lands on king diagonal',
   {'board': {'b1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['b1', 'b2']}, 'none'),
  ('rook quiet', {'board': {'a1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['a1', 'b1']}, 'none')],
 [('discovered by bishop',
   {'board': {'a1': 'K', 'c3': 'B', 'd4': 'N', 'h8': 'k'}, 'move': ['d4', 'b5']}, 'discovered'),
  ('double check', {'board': {'a1': 'K', 'e1': 'R', 'e4': 'N', 'e8': 'k'}, 'move': ['e4', 'f6']},
   'double'),
  ('queen diagonal direct', {'board': {'a2': 'K', 'd1': 'Q', 'h8': 'k'}, 'move': ['d1', 'd4']},
   'direct'),
  ('rook lands on king diagonal',
   {'board': {'b1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['b1', 'b2']}, 'none'),
  ('rook quiet', {'board': {'a1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['a1', 'b1']}, 'none'),
  ('black rook direct', {'board': {'a8': 'r', 'e1': 'K', 'h8': 'k'}, 'move': ['a8', 'a1']},
   'direct'),
  ('defender rook on own king line',
   {'board': {'a1': 'K', 'b1': 'N', 'e5': 'r', 'e8': 'k'}, 'move': ['b1', 'c3']}, 'none'),
  ('black discovered',
   {'board': {'a8': 'k', 'e1': 'K', 'e7': 'n', 'e8': 'r'}, 'move': ['e7', 'c6']}, 'discovered')],
 [('queen diagonal direct', {'board': {'a2': 'K', 'd1': 'Q', 'h8': 'k'}, 'move': ['d1', 'd4']},
   'direct'),
  ('rook lands on king diagonal',
   {'board': {'b1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['b1', 'b2']}, 'none'),
  ('black rook direct', {'board': {'a8': 'r', 'e1': 'K', 'h8': 'k'}, 'move': ['a8', 'a1']},
   'direct'),
  ('defender rook on own king line',
   {'board': {'a1': 'K', 'b1': 'N', 'e5': 'r', 'e8': 'k'}, 'move': ['b1', 'c3']}, 'none'),
  ('black discovered',
   {'board': {'a8': 'k', 'e1': 'K', 'e7': 'n', 'e8': 'r'}, 'move': ['e7', 'c6']}, 'discovered'),
  ('bishop direct', {'board': {'a1': 'K', 'e8': 'k', 'f1': 'B'}, 'move': ['f1', 'b5']}, 'direct'),
  ('pawn push check', {'board': {'a1': 'K', 'd5': 'P', 'e7': 'k'}, 'move': ['d5', 'd6']}, 'direct'),
  ('white piece near own line',
   {'board': {'a1': 'K', 'a2': 'r', 'c1': 'B', 'e3': 'P', 'h6': 'k'}, 'move': ['e3', 'e4']},
   'discovered')],
 [('promotion gives check', {'board': {'a1': 'K', 'b7': 'P', 'e8': 'k'}, 'move': ['b7', 'b8', 'q']},
   'direct'),
  ('knight promotion check',
   {'board': {'a1': 'K', 'e7': 'P', 'g7': 'k'}, 'move': ['e7', 'e8', 'n']}, 'direct'),
  ('simple direct', {'board': {'b1': 'N', 'd4': 'k', 'h1': 'K'}, 'move': ['b1', 'c2']}, 'direct'),
  ('queen diagonal direct', {'board': {'a2': 'K', 'd1': 'Q', 'h8': 'k'}, 'move': ['d1', 'd4']},
   'direct'),
  ('rook lands on king diagonal',
   {'board': {'b1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['b1', 'b2']}, 'none'),
  ('bishop direct', {'board': {'a1': 'K', 'e8': 'k', 'f1': 'B'}, 'move': ['f1', 'b5']}, 'direct'),
  ('pawn push check', {'board': {'a1': 'K', 'd5': 'P', 'e7': 'k'}, 'move': ['d5', 'd6']}, 'direct'),
  ('white piece near own line',
   {'board': {'a1': 'K', 'a2': 'r', 'c1': 'B', 'e3': 'P', 'h6': 'k'}, 'move': ['e3', 'e4']},
   'discovered')],
 [('promotion gives check', {'board': {'a1': 'K', 'b7': 'P', 'e8': 'k'}, 'move': ['b7', 'b8', 'q']},
   'direct'),
  ('knight promotion check',
   {'board': {'a1': 'K', 'e7': 'P', 'g7': 'k'}, 'move': ['e7', 'e8', 'n']}, 'direct'),
  ('simple direct', {'board': {'b1': 'N', 'd4': 'k', 'h1': 'K'}, 'move': ['b1', 'c2']}, 'direct'),
  ('discovered by bishop',
   {'board': {'a1': 'K', 'c3': 'B', 'd4': 'N', 'h8': 'k'}, 'move': ['d4', 'b5']}, 'discovered'),
  ('double check', {'board': {'a1': 'K', 'e1': 'R', 'e4': 'N', 'e8': 'k'}, 'move': ['e4', 'f6']},
   'double'),
  ('queen diagonal direct', {'board': {'a2': 'K', 'd1': 'Q', 'h8': 'k'}, 'move': ['d1', 'd4']},
   'direct'),
  ('rook lands on king diagonal',
   {'board': {'b1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['b1', 'b2']}, 'none'),
  ('rook quiet', {'board': {'a1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['a1', 'b1']}, 'none')]]
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)

source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    b=dict(x['board']); fr,to=x['move'][:2]; p=b.pop(fr)
    if len(x['move'])>2: p=x['move'][2].upper() if p.isupper() else x['move'][2].lower()
    b[to]=p
    white=p.isupper()
    ks=[s for s,v in b.items() if v==('k' if white else 'K')][0]
    def hits(src, tgt):
        v=b[src]; t=v.upper()
        f,r=ord(src[0])-97,int(src[1])-1
        tf,tr=ord(tgt[0])-97,int(tgt[1])-1
        df,dr=tf-f,tr-r
        if t=='P': return abs(df)==1 and dr==(1 if v.isupper() else -1)
        if t=='N': return (abs(df),abs(dr)) in ((1,2),(2,1))
        if t=='K': return max(abs(df),abs(dr))==1
        orth=(df==0)!=(dr==0); diag=abs(df)==abs(dr) and df!=0
        if not ((t in ('R','Q','B') and (orth or diag))): return False
        sf=(df>0)-(df<0); sr=(dr>0)-(dr<0)
        cf,cr=f+sf,r+sr
        while (cf,cr)!=(tf,tr):
            if chr(97+cf)+str(cr+1) in b: return False
            cf+=sf; cr+=sr
        return True
    direct=hits(to,ks)
    disc=any(hits(s,ks) for s,v in b.items() if s!=to and v.isupper()==white and v.upper()!='K')
    if direct and disc: return 'double'
    if direct: return 'direct'
    if disc: return 'discovered'
    return 'none'
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('promotion gives check', {'board': {'a1': 'K', 'b7': 'P', 'e8': 'k'}, 'move': ['b7', 'b8', 'q']},
   'direct'),
  ('knight promotion check',
   {'board': {'a1': 'K', 'e7': 'P', 'g7': 'k'}, 'move': ['e7', 'e8', 'n']}, 'direct'),
  ('simple direct', {'board': {'b1': 'N', 'd4': 'k', 'h1': 'K'}, 'move': ['b1', 'c2']}, 'direct'),
  ('discovered by bishop',
   {'board': {'a1': 'K', 'c3': 'B', 'd4': 'N', 'h8': 'k'}, 'move': ['d4', 'b5']}, 'discovered'),
  ('double check', {'board': {'a1': 'K', 'e1': 'R', 'e4': 'N', 'e8': 'k'}, 'move': ['e4', 'f6']},
   'double'),
  ('queen diagonal direct', {'board': {'a2': 'K', 'd1': 'Q', 'h8': 'k'}, 'move': ['d1', 'd4']},
   'direct'),
  ('rook lands on king diagonal',
   {'board': {'b1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['b1', 'b2']}, 'none'),
  ('rook quiet', {'board': {'a1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['a1', 'b1']}, 'none')],
 [('discovered by bishop',
   {'board': {'a1': 'K', 'c3': 'B', 'd4': 'N', 'h8': 'k'}, 'move': ['d4', 'b5']}, 'discovered'),
  ('double check', {'board': {'a1': 'K', 'e1': 'R', 'e4': 'N', 'e8': 'k'}, 'move': ['e4', 'f6']},
   'double'),
  ('queen diagonal direct', {'board': {'a2': 'K', 'd1': 'Q', 'h8': 'k'}, 'move': ['d1', 'd4']},
   'direct'),
  ('rook lands on king diagonal',
   {'board': {'b1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['b1', 'b2']}, 'none'),
  ('rook quiet', {'board': {'a1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['a1', 'b1']}, 'none'),
  ('black rook direct', {'board': {'a8': 'r', 'e1': 'K', 'h8': 'k'}, 'move': ['a8', 'a1']},
   'direct'),
  ('defender rook on own king line',
   {'board': {'a1': 'K', 'b1': 'N', 'e5': 'r', 'e8': 'k'}, 'move': ['b1', 'c3']}, 'none'),
  ('black discovered',
   {'board': {'a8': 'k', 'e1': 'K', 'e7': 'n', 'e8': 'r'}, 'move': ['e7', 'c6']}, 'discovered')],
 [('queen diagonal direct', {'board': {'a2': 'K', 'd1': 'Q', 'h8': 'k'}, 'move': ['d1', 'd4']},
   'direct'),
  ('rook lands on king diagonal',
   {'board': {'b1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['b1', 'b2']}, 'none'),
  ('black rook direct', {'board': {'a8': 'r', 'e1': 'K', 'h8': 'k'}, 'move': ['a8', 'a1']},
   'direct'),
  ('defender rook on own king line',
   {'board': {'a1': 'K', 'b1': 'N', 'e5': 'r', 'e8': 'k'}, 'move': ['b1', 'c3']}, 'none'),
  ('black discovered',
   {'board': {'a8': 'k', 'e1': 'K', 'e7': 'n', 'e8': 'r'}, 'move': ['e7', 'c6']}, 'discovered'),
  ('bishop direct', {'board': {'a1': 'K', 'e8': 'k', 'f1': 'B'}, 'move': ['f1', 'b5']}, 'direct'),
  ('pawn push check', {'board': {'a1': 'K', 'd5': 'P', 'e7': 'k'}, 'move': ['d5', 'd6']}, 'direct'),
  ('white piece near own line',
   {'board': {'a1': 'K', 'a2': 'r', 'c1': 'B', 'e3': 'P', 'h6': 'k'}, 'move': ['e3', 'e4']},
   'discovered')],
 [('promotion gives check', {'board': {'a1': 'K', 'b7': 'P', 'e8': 'k'}, 'move': ['b7', 'b8', 'q']},
   'direct'),
  ('knight promotion check',
   {'board': {'a1': 'K', 'e7': 'P', 'g7': 'k'}, 'move': ['e7', 'e8', 'n']}, 'direct'),
  ('simple direct', {'board': {'b1': 'N', 'd4': 'k', 'h1': 'K'}, 'move': ['b1', 'c2']}, 'direct'),
  ('queen diagonal direct', {'board': {'a2': 'K', 'd1': 'Q', 'h8': 'k'}, 'move': ['d1', 'd4']},
   'direct'),
  ('rook lands on king diagonal',
   {'board': {'b1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['b1', 'b2']}, 'none'),
  ('bishop direct', {'board': {'a1': 'K', 'e8': 'k', 'f1': 'B'}, 'move': ['f1', 'b5']}, 'direct'),
  ('pawn push check', {'board': {'a1': 'K', 'd5': 'P', 'e7': 'k'}, 'move': ['d5', 'd6']}, 'direct'),
  ('white piece near own line',
   {'board': {'a1': 'K', 'a2': 'r', 'c1': 'B', 'e3': 'P', 'h6': 'k'}, 'move': ['e3', 'e4']},
   'discovered')],
 [('promotion gives check', {'board': {'a1': 'K', 'b7': 'P', 'e8': 'k'}, 'move': ['b7', 'b8', 'q']},
   'direct'),
  ('knight promotion check',
   {'board': {'a1': 'K', 'e7': 'P', 'g7': 'k'}, 'move': ['e7', 'e8', 'n']}, 'direct'),
  ('simple direct', {'board': {'b1': 'N', 'd4': 'k', 'h1': 'K'}, 'move': ['b1', 'c2']}, 'direct'),
  ('discovered by bishop',
   {'board': {'a1': 'K', 'c3': 'B', 'd4': 'N', 'h8': 'k'}, 'move': ['d4', 'b5']}, 'discovered'),
  ('double check', {'board': {'a1': 'K', 'e1': 'R', 'e4': 'N', 'e8': 'k'}, 'move': ['e4', 'f6']},
   'double'),
  ('queen diagonal direct', {'board': {'a2': 'K', 'd1': 'Q', 'h8': 'k'}, 'move': ['d1', 'd4']},
   'direct'),
  ('rook lands on king diagonal',
   {'board': {'b1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['b1', 'b2']}, 'none'),
  ('rook quiet', {'board': {'a1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['a1', 'b1']}, 'none')]]
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)

prompt:
Qd1-d4 against a king on h8 is classified "none".

Input: {"board", "move": [from, to] or [from, to, promotion letter]}. Apply the move (promotion letter becomes a piece of the mover's colour) and classify the check it gives to the enemy king: "direct" (the moved piece attacks it), "discovered" (another of the mover's pieces now attacks it), "double" (both) or "none". Pawns attack diagonally forward, sliders need a clear path.

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    b=dict(x['board']); fr,to=x['move'][:2]; p=b.pop(fr)
    if len(x['move'])>2: p=x['move'][2].upper() if p.isupper() else x['move'][2].lower()
    b[to]=p
    white=p.isupper()
    ks=[s for s,v in b.items() if v==('k' if white else 'K')][0]
    def hits(src, tgt):
        v=b[src]; t=v.upper()
        f,r=ord(src[0])-97,int(src[1])-1
        tf,tr=ord(tgt[0])-97,int(tgt[1])-1
        df,dr=tf-f,tr-r
        if t=='P': return abs(df)==1 and dr==(1 if v.isupper() else -1)
        if t=='N': return (abs(df),abs(dr)) in ((1,2),(2,1))
        if t=='K': return max(abs(df),abs(dr))==1
        orth=(df==0)!=(dr==0); diag=abs(df)==abs(dr) and df!=0
        if not ((t in ('R','Q') and orth) or (t in ('B','Q') and diag)): return False
        sf=(df>0)-(df<0); sr=(dr>0)-(dr<0)
        cf,cr=f+sf,r+sr
        while (cf,cr)!=(tf,tr):
            if chr(97+cf)+str(cr+1) in b: return False
            cf+=sf; cr+=sr
        return True
    direct=hits(to,ks)
    disc=any(hits(s,ks) for s,v in b.items() if s!=to and v.upper()!='K')
    if direct and disc: return 'double'
    if direct: return 'direct'
    if disc: return 'discovered'
    return 'none'
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('promotion gives check', {'board': {'a1': 'K', 'b7': 'P', 'e8': 'k'}, 'move': ['b7', 'b8', 'q']},
   'direct'),
  ('knight promotion check',
   {'board': {'a1': 'K', 'e7': 'P', 'g7': 'k'}, 'move': ['e7', 'e8', 'n']}, 'direct'),
  ('simple direct', {'board': {'b1': 'N', 'd4': 'k', 'h1': 'K'}, 'move': ['b1', 'c2']}, 'direct'),
  ('discovered by bishop',
   {'board': {'a1': 'K', 'c3': 'B', 'd4': 'N', 'h8': 'k'}, 'move': ['d4', 'b5']}, 'discovered'),
  ('double check', {'board': {'a1': 'K', 'e1': 'R', 'e4': 'N', 'e8': 'k'}, 'move': ['e4', 'f6']},
   'double'),
  ('queen diagonal direct', {'board': {'a2': 'K', 'd1': 'Q', 'h8': 'k'}, 'move': ['d1', 'd4']},
   'direct'),
  ('defender rook on own king line',
   {'board': {'a1': 'K', 'b1': 'N', 'e5': 'r', 'e8': 'k'}, 'move': ['b1', 'c3']}, 'none'),
  ('black discovered',
   {'board': {'a8': 'k', 'e1': 'K', 'e7': 'n', 'e8': 'r'}, 'move': ['e7', 'c6']}, 'discovered')],
 [('discovered by bishop',
   {'board': {'a1': 'K', 'c3': 'B', 'd4': 'N', 'h8': 'k'}, 'move': ['d4', 'b5']}, 'discovered'),
  ('double check', {'board': {'a1': 'K', 'e1': 'R', 'e4': 'N', 'e8': 'k'}, 'move': ['e4', 'f6']},
   'double'),
  ('queen diagonal direct', {'board': {'a2': 'K', 'd1': 'Q', 'h8': 'k'}, 'move': ['d1', 'd4']},
   'direct'),
  ('rook lands on king diagonal',
   {'board': {'b1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['b1', 'b2']}, 'none'),
  ('rook quiet', {'board': {'a1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['a1', 'b1']}, 'none'),
  ('black rook direct', {'board': {'a8': 'r', 'e1': 'K', 'h8': 'k'}, 'move': ['a8', 'a1']},
   'direct'),
  ('defender rook on own king line',
   {'board': {'a1': 'K', 'b1': 'N', 'e5': 'r', 'e8': 'k'}, 'move': ['b1', 'c3']}, 'none'),
  ('black discovered',
   {'board': {'a8': 'k', 'e1': 'K', 'e7': 'n', 'e8': 'r'}, 'move': ['e7', 'c6']}, 'discovered')],
 [('rook lands on king diagonal',
   {'board': {'b1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['b1', 'b2']}, 'none'),
  ('rook quiet', {'board': {'a1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['a1', 'b1']}, 'none'),
  ('black rook direct', {'board': {'a8': 'r', 'e1': 'K', 'h8': 'k'}, 'move': ['a8', 'a1']},
   'direct'),
  ('defender rook on own king line',
   {'board': {'a1': 'K', 'b1': 'N', 'e5': 'r', 'e8': 'k'}, 'move': ['b1', 'c3']}, 'none'),
  ('black discovered',
   {'board': {'a8': 'k', 'e1': 'K', 'e7': 'n', 'e8': 'r'}, 'move': ['e7', 'c6']}, 'discovered'),
  ('bishop direct', {'board': {'a1': 'K', 'e8': 'k', 'f1': 'B'}, 'move': ['f1', 'b5']}, 'direct'),
  ('pawn push check', {'board': {'a1': 'K', 'd5': 'P', 'e7': 'k'}, 'move': ['d5', 'd6']}, 'direct'),
  ('white piece near own line',
   {'board': {'a1': 'K', 'a2': 'r', 'c1': 'B', 'e3': 'P', 'h6': 'k'}, 'move': ['e3', 'e4']},
   'discovered')],
 [('promotion gives check', {'board': {'a1': 'K', 'b7': 'P', 'e8': 'k'}, 'move': ['b7', 'b8', 'q']},
   'direct'),
  ('knight promotion check',
   {'board': {'a1': 'K', 'e7': 'P', 'g7': 'k'}, 'move': ['e7', 'e8', 'n']}, 'direct'),
  ('simple direct', {'board': {'b1': 'N', 'd4': 'k', 'h1': 'K'}, 'move': ['b1', 'c2']}, 'direct'),
  ('defender rook on own king line',
   {'board': {'a1': 'K', 'b1': 'N', 'e5': 'r', 'e8': 'k'}, 'move': ['b1', 'c3']}, 'none'),
  ('black discovered',
   {'board': {'a8': 'k', 'e1': 'K', 'e7': 'n', 'e8': 'r'}, 'move': ['e7', 'c6']}, 'discovered'),
  ('bishop direct', {'board': {'a1': 'K', 'e8': 'k', 'f1': 'B'}, 'move': ['f1', 'b5']}, 'direct'),
  ('pawn push check', {'board': {'a1': 'K', 'd5': 'P', 'e7': 'k'}, 'move': ['d5', 'd6']}, 'direct'),
  ('white piece near own line',
   {'board': {'a1': 'K', 'a2': 'r', 'c1': 'B', 'e3': 'P', 'h6': 'k'}, 'move': ['e3', 'e4']},
   'discovered')],
 [('promotion gives check', {'board': {'a1': 'K', 'b7': 'P', 'e8': 'k'}, 'move': ['b7', 'b8', 'q']},
   'direct'),
  ('knight promotion check',
   {'board': {'a1': 'K', 'e7': 'P', 'g7': 'k'}, 'move': ['e7', 'e8', 'n']}, 'direct'),
  ('simple direct', {'board': {'b1': 'N', 'd4': 'k', 'h1': 'K'}, 'move': ['b1', 'c2']}, 'direct'),
  ('discovered by bishop',
   {'board': {'a1': 'K', 'c3': 'B', 'd4': 'N', 'h8': 'k'}, 'move': ['d4', 'b5']}, 'discovered'),
  ('double check', {'board': {'a1': 'K', 'e1': 'R', 'e4': 'N', 'e8': 'k'}, 'move': ['e4', 'f6']},
   'double'),
  ('queen diagonal direct', {'board': {'a2': 'K', 'd1': 'Q', 'h8': 'k'}, 'move': ['d1', 'd4']},
   'direct'),
  ('defender rook on own king line',
   {'board': {'a1': 'K', 'b1': 'N', 'e5': 'r', 'e8': 'k'}, 'move': ['b1', 'c3']}, 'none'),
  ('black discovered',
   {'board': {'a8': 'k', 'e1': 'K', 'e7': 'n', 'e8': 'r'}, 'move': ['e7', 'c6']}, 'discovered')]]
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)

source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    b=dict(x['board']); fr,to=x['move'][:2]; p=b.pop(fr)
    if len(x['move'])>2: p=x['move'][2].upper() if p.isupper() else x['move'][2].lower()
    b[to]=p
    white=p.isupper()
    ks=[s for s,v in b.items() if v==('k' if white else 'K')][0]
    def hits(src, tgt):
        v=b[src]; t=v.upper()
        f,r=ord(src[0])-97,int(src[1])-1
        tf,tr=ord(tgt[0])-97,int(tgt[1])-1
        df,dr=tf-f,tr-r
        if t=='P': return abs(df)==1 and dr==(1 if v.isupper() else -1)
        if t=='N': return (abs(df),abs(dr)) in ((1,2),(2,1))
        if t=='K': return max(abs(df),abs(dr))==1
        orth=(df==0)!=(dr==0); diag=abs(df)==abs(dr) and df!=0
        if not ((t in ('R','Q') and orth) or (t in ('B','Q') and diag)): return False
        sf=(df>0)-(df<0); sr=(dr>0)-(dr<0)
        cf,cr=f+sf,r+sr
        while (cf,cr)!=(tf,tr):
            if chr(97+cf)+str(cr+1) in b: return False
            cf+=sf; cr+=sr
        return True
    direct=hits(to,ks)
    disc=any(hits(s,ks) for s,v in b.items() if s!=to and v.isupper() and v.upper()!='K')
    if direct and disc: return 'double'
    if direct: return 'direct'
    if disc: return 'discovered'
    return 'none'
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('promotion gives check', {'board': {'a1': 'K', 'b7': 'P', 'e8': 'k'}, 'move': ['b7', 'b8', 'q']},
   'direct'),
  ('knight promotion check',
   {'board': {'a1': 'K', 'e7': 'P', 'g7': 'k'}, 'move': ['e7', 'e8', 'n']}, 'direct'),
  ('simple direct', {'board': {'b1': 'N', 'd4': 'k', 'h1': 'K'}, 'move': ['b1', 'c2']}, 'direct'),
  ('discovered by bishop',
   {'board': {'a1': 'K', 'c3': 'B', 'd4': 'N', 'h8': 'k'}, 'move': ['d4', 'b5']}, 'discovered'),
  ('double check', {'board': {'a1': 'K', 'e1': 'R', 'e4': 'N', 'e8': 'k'}, 'move': ['e4', 'f6']},
   'double'),
  ('queen diagonal direct', {'board': {'a2': 'K', 'd1': 'Q', 'h8': 'k'}, 'move': ['d1', 'd4']},
   'direct'),
  ('defender rook on own king line',
   {'board': {'a1': 'K', 'b1': 'N', 'e5': 'r', 'e8': 'k'}, 'move': ['b1', 'c3']}, 'none'),
  ('black discovered',
   {'board': {'a8': 'k', 'e1': 'K', 'e7': 'n', 'e8': 'r'}, 'move': ['e7', 'c6']}, 'discovered')],
 [('discovered by bishop',
   {'board': {'a1': 'K', 'c3': 'B', 'd4': 'N', 'h8': 'k'}, 'move': ['d4', 'b5']}, 'discovered'),
  ('double check', {'board': {'a1': 'K', 'e1': 'R', 'e4': 'N', 'e8': 'k'}, 'move': ['e4', 'f6']},
   'double'),
  ('queen diagonal direct', {'board': {'a2': 'K', 'd1': 'Q', 'h8': 'k'}, 'move': ['d1', 'd4']},
   'direct'),
  ('rook lands on king diagonal',
   {'board': {'b1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['b1', 'b2']}, 'none'),
  ('rook quiet', {'board': {'a1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['a1', 'b1']}, 'none'),
  ('black rook direct', {'board': {'a8': 'r', 'e1': 'K', 'h8': 'k'}, 'move': ['a8', 'a1']},
   'direct'),
  ('defender rook on own king line',
   {'board': {'a1': 'K', 'b1': 'N', 'e5': 'r', 'e8': 'k'}, 'move': ['b1', 'c3']}, 'none'),
  ('black discovered',
   {'board': {'a8': 'k', 'e1': 'K', 'e7': 'n', 'e8': 'r'}, 'move': ['e7', 'c6']}, 'discovered')],
 [('rook lands on king diagonal',
   {'board': {'b1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['b1', 'b2']}, 'none'),
  ('rook quiet', {'board': {'a1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['a1', 'b1']}, 'none'),
  ('black rook direct', {'board': {'a8': 'r', 'e1': 'K', 'h8': 'k'}, 'move': ['a8', 'a1']},
   'direct'),
  ('defender rook on own king line',
   {'board': {'a1': 'K', 'b1': 'N', 'e5': 'r', 'e8': 'k'}, 'move': ['b1', 'c3']}, 'none'),
  ('black discovered',
   {'board': {'a8': 'k', 'e1': 'K', 'e7': 'n', 'e8': 'r'}, 'move': ['e7', 'c6']}, 'discovered'),
  ('bishop direct', {'board': {'a1': 'K', 'e8': 'k', 'f1': 'B'}, 'move': ['f1', 'b5']}, 'direct'),
  ('pawn push check', {'board': {'a1': 'K', 'd5': 'P', 'e7': 'k'}, 'move': ['d5', 'd6']}, 'direct'),
  ('white piece near own line',
   {'board': {'a1': 'K', 'a2': 'r', 'c1': 'B', 'e3': 'P', 'h6': 'k'}, 'move': ['e3', 'e4']},
   'discovered')],
 [('promotion gives check', {'board': {'a1': 'K', 'b7': 'P', 'e8': 'k'}, 'move': ['b7', 'b8', 'q']},
   'direct'),
  ('knight promotion check',
   {'board': {'a1': 'K', 'e7': 'P', 'g7': 'k'}, 'move': ['e7', 'e8', 'n']}, 'direct'),
  ('simple direct', {'board': {'b1': 'N', 'd4': 'k', 'h1': 'K'}, 'move': ['b1', 'c2']}, 'direct'),
  ('defender rook on own king line',
   {'board': {'a1': 'K', 'b1': 'N', 'e5': 'r', 'e8': 'k'}, 'move': ['b1', 'c3']}, 'none'),
  ('black discovered',
   {'board': {'a8': 'k', 'e1': 'K', 'e7': 'n', 'e8': 'r'}, 'move': ['e7', 'c6']}, 'discovered'),
  ('bishop direct', {'board': {'a1': 'K', 'e8': 'k', 'f1': 'B'}, 'move': ['f1', 'b5']}, 'direct'),
  ('pawn push check', {'board': {'a1': 'K', 'd5': 'P', 'e7': 'k'}, 'move': ['d5', 'd6']}, 'direct'),
  ('white piece near own line',
   {'board': {'a1': 'K', 'a2': 'r', 'c1': 'B', 'e3': 'P', 'h6': 'k'}, 'move': ['e3', 'e4']},
   'discovered')],
 [('promotion gives check', {'board': {'a1': 'K', 'b7': 'P', 'e8': 'k'}, 'move': ['b7', 'b8', 'q']},
   'direct'),
  ('knight promotion check',
   {'board': {'a1': 'K', 'e7': 'P', 'g7': 'k'}, 'move': ['e7', 'e8', 'n']}, 'direct'),
  ('simple direct', {'board': {'b1': 'N', 'd4': 'k', 'h1': 'K'}, 'move': ['b1', 'c2']}, 'direct'),
  ('discovered by bishop',
   {'board': {'a1': 'K', 'c3': 'B', 'd4': 'N', 'h8': 'k'}, 'move': ['d4', 'b5']}, 'discovered'),
  ('double check', {'board': {'a1': 'K', 'e1': 'R', 'e4': 'N', 'e8': 'k'}, 'move': ['e4', 'f6']},
   'double'),
  ('queen diagonal direct', {'board': {'a2': 'K', 'd1': 'Q', 'h8': 'k'}, 'move': ['d1', 'd4']},
   'direct'),
  ('defender rook on own king line',
   {'board': {'a1': 'K', 'b1': 'N', 'e5': 'r', 'e8': 'k'}, 'move': ['b1', 'c3']}, 'none'),
  ('black discovered',
   {'board': {'a8': 'k', 'e1': 'K', 'e7': 'n', 'e8': 'r'}, 'move': ['e7', 'c6']}, 'discovered')]]
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)

prompt:
After a quiet white knight move, a black rook standing on its own king's file is reported as a discovered check.

Input: {"board", "move": [from, to] or [from, to, promotion letter]}. Apply the move (promotion letter becomes a piece of the mover's colour) and classify the check it gives to the enemy king: "direct" (the moved piece attacks it), "discovered" (another of the mover's pieces now attacks it), "double" (both) or "none". Pawns attack diagonally forward, sliders need a clear path.

split: open-access


prompt:
Black's reply is rejected as an out-of-turn move.

Input: {"board", "turn": "w" or "b", "moves": [[from, to], ...]}. Replay the moves; return the index of the first move that starts from an empty square, moves a piece of the side not to move, or lands on a piece of its own colour; return -1 if all pass. Each move replaces any piece on the destination and passes the turn.

split: open-access


prompt:
A knight that moved from g1 can move from g1 again.

Input: {"board", "turn": "w" or "b", "moves": [[from, to], ...]}. Replay the moves; return the index of the first move that starts from an empty square, moves a piece of the side not to move, or lands on a piece of its own colour; return -1 if all pass. Each move replaces any piece on the destination and passes the turn.

split: open-access


prompt:
A queen may land on its own pawn.

Input: {"board", "turn": "w" or "b", "moves": [[from, to], ...]}. Replay the moves; return the index of the first move that starts from an empty square, moves a piece of the side not to move, or lands on a piece of its own colour; return -1 if all pass. Each move replaces any piece on the destination and passes the turn.

split: open-access


prompt:
White moving a black queen is accepted.

Input: {"board", "turn": "w" or "b", "moves": [[from, to], ...]}. Replay the moves; return the index of the first move that starts from an empty square, moves a piece of the side not to move, or lands on a piece of its own colour; return -1 if all pass. Each move replaces any piece on the destination and passes the turn.

split: open-access


prompt:
A move list beginning with black's move is rejected at index 0.

Input: {"board", "turn": "w" or "b", "moves": [[from, to], ...]}. Replay the moves; return the index of the first move that starts from an empty square, moves a piece of the side not to move, or lands on a piece of its own colour; return -1 if all pass. Each move replaces any piece on the destination and passes the turn.

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    board, komi = x
    n = len(board)
    m = len(board[0])
    b = sum(row.count('B') for row in board)
    w = sum(row.count('W') for row in board)
    seen = set()
    for r in range(n):
        for c in range(m):
            if board[r][c] != '.' or (r, c) in seen:
                continue
            stack = [(r, c)]
            seen.add((r, c))
            size = 0
            border = set()
            while stack:
                i, j = stack.pop()
                size += 1
                for di, dj in ((1, 0), (-1, 0), (0, 1), (0, -1)):
                    a, d = i + di, j + dj
                    if a < n and d < m:
                        v = board[a][d]
                        if v == '.':
                            if (a, d) not in seen:
                                seen.add((a, d))
                                stack.append((a, d))
                        else:
                            border.add(v)
            if border == {'B'}:
                b += size
            elif border == {'W'}:
                w += size
    diff = b * 10 - w * 10 - komi
    if diff > 0:
        res = 'B+%d.%d' % (diff // 10, diff % 10)
    elif diff < 0:
        res = 'W+%d.%d' % ((-diff) // 10, (-diff) % 10)
    else:
        res = 'Draw'
    return [b, w, res]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[['.B.', 'B.B', '.B.'], 65], [9, 0, 'B+2.5']], [[['WBWWB', 'BB.B.', 'WBWB.', 'WBWBB'], -5], [12, 7, 'B+5.5']], [[['.B.', '.WW', 'BBB', 'WW.'], 65], [4, 4, 'W+6.5']], [[['.WBB', 'BW..', '..B.'], 35], [4, 2, 'W+1.5']], [[['BW.B', '.WWW', 'B.BB', 'WBB.', 'BW.W'], -5], [8, 7, 'B+1.5']], [[['BWBB.', '.B..B', 'BW..B', 'W.BBW', '...BB'], 65], [13, 4, 'B+2.5']], [[['W..B.', 'BB.BB', 'B..B.', 'BBB..', 'B.BBB'], 60], [19, 1, 'B+12.0']], [[['.BBBW.', 'WBBBB.', '.WBB..', 'BBB...', 'BBW..B', '..BW.W'], 70], [18, 6, 'B+5.0']]], [[[['WB.B', 'B.B.', '.B..', 'B...'], -5], [15, 1, 'B+14.5']], [[['W..BBB', 'BWB.W.', '.WWWWW', 'W.WBWW'], -5], [6, 13, 'W+6.5']], [[['W..B', '...B', 'WWWW'], 0], [2, 5, 'W+3.0']], [[['W...', 'WBWB', 'WWBW', 'BBB.'], 5], [6, 6, 'W+0.5']], [[['WW..', 'WWW.', 'BWWW'], 65], [1, 11, 'W+16.5']], [[['WWB', 'W.W', 'B.W', 'B..', '..B'], 35], [4, 5, 'W+4.5']], [[['BB..', '...W', 'BBBW'], 65], [5, 2, 'W+3.5']], [[['W..', 'W.B', '.WB', 'WWW', 'B..'], -5], [3, 7, 'W+3.5']]], [[[['B.B.W', '.B.W.', 'B.BW.', 'BBW.W', '..W..'], 70], [10, 11, 'W+8.0']], [[['.BBBW.', 'WBBBB.', '.WBB..', 'BBB...', 'BBW..B', '..BW.W'], 70], [18, 6, 'B+5.0']], [[['WWW.W', '..BWW', 'B.BWB', 'W.B..', '.W.WB', 'WW.W.'], 5], [6, 15, 'W+9.5']], [[['.W.', 'BBW', '..B', 'BWW'], 65], [4, 5, 'W+7.5']], [[['.W..', 'WWBB', 'WWWW'], 75], [2, 8, 'W+13.5']], [[['.BBW.', 'WBWBW', '.WWW.', '.WB.B', 'BBW.W'], 35], [8, 11, 'W+6.5']], [[['.W...', '.BBB.', 'WWBBW', '.BB.B', 'WB..W', 'B..BB'], 60], [12, 6, 'Draw']], [[['.W.', '.WW', '.W.', 'BWB'], 70], [2, 6, 'W+11.0']]], [[[['WWW.W', '..BWW', 'B.BWB', 'W.B..', '.W.WB', 'WW.W.'], 5], [6, 15, 'W+9.5']], [[['.W.', '.WW', '.W.', 'BWB'], 70], [2, 6, 'W+11.0']], [[['.WB', 'W.B', 'WB.', 'WB.', 'B..', 'B.B'], 5], [12, 5, 'B+6.5']], [[['WBB', 'BWW', '.BB', 'W..'], 75], [5, 4, 'W+6.5']], [[['..WWB', 'B.B..', '.W.W.', '..BB.', '....B', '...BB'], 60], [8, 4, 'W+2.0']], [[['BBBB.B', '....B.', '.....W', 'BBW..B'], 70], [10, 2, 'B+1.0']], [[['.B.B.', '.BW.W', '....B', 'B..BW', '.BB..', 'W.W..'], -5], [8, 5, 'B+3.5']], [[['...W.W', '.WB.W.', 'W..W..', 'BWW.WW', '.WWW.W', 'BW....'], 0], [3, 25, 'W+22.0']]], [[[['.B.', 'B.B', '.B.'], 65], [9, 0, 'B+2.5']], [[['BBBB.B', '....B.', '.....W', 'BBW..B'], 70], [10, 2, 'B+1.0']], [[['WWW', '.WW', '.WW', 'WWW', 'WWW', 'W.W'], 65], [0, 18, 'W+24.5']], [[['W..', 'W.B', '.WB', 'WWW', 'B..'], -5], [3, 7, 'W+3.5']], [[['WWW', '..B', 'WBW'], 75], [2, 5, 'W+10.5']], [[['.WWW.', 'WW.BB', '.WB..', 'B.W.W', '.WW..', 'W.WWW'], 60], [4, 16, 'W+18.0']], [[['..B', '..W', 'BWB', 'B.B', 'B.W'], 70], [6, 3, 'W+4.0']], [[['.WBB..', 'WWWB.B', 'BWWW.W', 'WW.BB.', 'BW.W.W'], -5], [8, 14, 'W+5.5']]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("area 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)

source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    board, komi = x
    n = len(board)
    m = len(board[0])
    b = sum(row.count('B') for row in board)
    w = sum(row.count('W') for row in board)
    seen = set()
    for r in range(n):
        for c in range(m):
            if board[r][c] != '.' or (r, c) in seen:
                continue
            stack = [(r, c)]
            seen.add((r, c))
            size = 0
            border = set()
            while stack:
                i, j = stack.pop()
                size += 1
                for di, dj in ((1, 0), (-1, 0), (0, 1), (0, -1)):
                    a, d = i + di, j + dj
                    if 0 <= a < n and d < m:
                        v = board[a][d]
                        if v == '.':
                            if (a, d) not in seen:
                                seen.add((a, d))
                                stack.append((a, d))
                        else:
                            border.add(v)
            if border == {'B'}:
                b += size
            elif border == {'W'}:
                w += size
    diff = b * 10 - w * 10 - komi
    if diff > 0:
        res = 'B+%d.%d' % (diff // 10, diff % 10)
    elif diff < 0:
        res = 'W+%d.%d' % ((-diff) // 10, (-diff) % 10)
    else:
        res = 'Draw'
    return [b, w, res]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[['.B.', 'B.B', '.B.'], 65], [9, 0, 'B+2.5']], [[['WBWWB', 'BB.B.', 'WBWB.', 'WBWBB'], -5], [12, 7, 'B+5.5']], [[['.B.', '.WW', 'BBB', 'WW.'], 65], [4, 4, 'W+6.5']], [[['.WBB', 'BW..', '..B.'], 35], [4, 2, 'W+1.5']], [[['BW.B', '.WWW', 'B.BB', 'WBB.', 'BW.W'], -5], [8, 7, 'B+1.5']], [[['BWBB.', '.B..B', 'BW..B', 'W.BBW', '...BB'], 65], [13, 4, 'B+2.5']], [[['W..B.', 'BB.BB', 'B..B.', 'BBB..', 'B.BBB'], 60], [19, 1, 'B+12.0']], [[['.BBBW.', 'WBBBB.', '.WBB..', 'BBB...', 'BBW..B', '..BW.W'], 70], [18, 6, 'B+5.0']]], [[[['WB.B', 'B.B.', '.B..', 'B...'], -5], [15, 1, 'B+14.5']], [[['W..BBB', 'BWB.W.', '.WWWWW', 'W.WBWW'], -5], [6, 13, 'W+6.5']], [[['W..B', '...B', 'WWWW'], 0], [2, 5, 'W+3.0']], [[['W...', 'WBWB', 'WWBW', 'BBB.'], 5], [6, 6, 'W+0.5']], [[['WW..', 'WWW.', 'BWWW'], 65], [1, 11, 'W+16.5']], [[['WWB', 'W.W', 'B.W', 'B..', '..B'], 35], [4, 5, 'W+4.5']], [[['BB..', '...W', 'BBBW'], 65], [5, 2, 'W+3.5']], [[['W..', 'W.B', '.WB', 'WWW', 'B..'], -5], [3, 7, 'W+3.5']]], [[[['B.B.W', '.B.W.', 'B.BW.', 'BBW.W', '..W..'], 70], [10, 11, 'W+8.0']], [[['.BBBW.', 'WBBBB.', '.WBB..', 'BBB...', 'BBW..B', '..BW.W'], 70], [18, 6, 'B+5.0']], [[['WWW.W', '..BWW', 'B.BWB', 'W.B..', '.W.WB', 'WW.W.'], 5], [6, 15, 'W+9.5']], [[['.W.', 'BBW', '..B', 'BWW'], 65], [4, 5, 'W+7.5']], [[['.W..', 'WWBB', 'WWWW'], 75], [2, 8, 'W+13.5']], [[['.BBW.', 'WBWBW', '.WWW.', '.WB.B', 'BBW.W'], 35], [8, 11, 'W+6.5']], [[['.W...', '.BBB.', 'WWBBW', '.BB.B', 'WB..W', 'B..BB'], 60], [12, 6, 'Draw']], [[['.W.', '.WW', '.W.', 'BWB'], 70], [2, 6, 'W+11.0']]], [[[['WWW.W', '..BWW', 'B.BWB', 'W.B..', '.W.WB', 'WW.W.'], 5], [6, 15, 'W+9.5']], [[['.W.', '.WW', '.W.', 'BWB'], 70], [2, 6, 'W+11.0']], [[['.WB', 'W.B', 'WB.', 'WB.', 'B..', 'B.B'], 5], [12, 5, 'B+6.5']], [[['WBB', 'BWW', '.BB', 'W..'], 75], [5, 4, 'W+6.5']], [[['..WWB', 'B.B..', '.W.W.', '..BB.', '....B', '...BB'], 60], [8, 4, 'W+2.0']], [[['BBBB.B', '....B.', '.....W', 'BBW..B'], 70], [10, 2, 'B+1.0']], [[['.B.B.', '.BW.W', '....B', 'B..BW', '.BB..', 'W.W..'], -5], [8, 5, 'B+3.5']], [[['...W.W', '.WB.W.', 'W..W..', 'BWW.WW', '.WWW.W', 'BW....'], 0], [3, 25, 'W+22.0']]], [[[['.B.', 'B.B', '.B.'], 65], [9, 0, 'B+2.5']], [[['BBBB.B', '....B.', '.....W', 'BBW..B'], 70], [10, 2, 'B+1.0']], [[['WWW', '.WW', '.WW', 'WWW', 'WWW', 'W.W'], 65], [0, 18, 'W+24.5']], [[['W..', 'W.B', '.WB', 'WWW', 'B..'], -5], [3, 7, 'W+3.5']], [[['WWW', '..B', 'WBW'], 75], [2, 5, 'W+10.5']], [[['.WWW.', 'WW.BB', '.WB..', 'B.W.W', '.WW..', 'W.WWW'], 60], [4, 16, 'W+18.0']], [[['..B', '..W', 'BWB', 'B.B', 'B.W'], 70], [6, 3, 'W+4.0']], [[['.WBB..', 'WWWB.B', 'BWWW.W', 'WW.BB.', 'BW.W.W'], -5], [8, 14, 'W+5.5']]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("area 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)

prompt:
Empty regions on the first row or column pick up border colours from the opposite edge, so territory becomes dame or changes owner.

Input [board, komi_tenths]. Area = own stones + empty regions whose orthogonal border touches only that colour. Return [black_area, white_area, result] where result is "B+x.y" / "W+x.y" after subtracting komi from black, or "Draw".

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    board, komi = x
    n = len(board)
    m = len(board[0])
    b = sum(row.count('B') for row in board)
    w = sum(row.count('W') for row in board)
    seen = set()
    for r in range(n):
        for c in range(m):
            if board[r][c] != '.' or (r, c) in seen:
                continue
            stack = [(r, c)]
            seen.add((r, c))
            size = 0
            border = set()
            while stack:
                i, j = stack.pop()
                size += 1
                for di, dj in ((1, 0), (-1, 0), (0, 1), (0, -1)):
                    a, d = i + di, j + dj
                    if 0 <= a < n and 0 <= d < m:
                        v = board[a][d]
                        if v == '.':
                            if (a, d) not in seen:
                                seen.add((a, d))
                                stack.append((a, d))
                        else:
                            border.add(v)
            if 'B' in border:
                b += size
            elif 'W' in border:
                w += size
    diff = b * 10 - w * 10 - komi
    if diff > 0:
        res = 'B+%d.%d' % (diff // 10, diff % 10)
    elif diff < 0:
        res = 'W+%d.%d' % ((-diff) // 10, (-diff) % 10)
    else:
        res = 'Draw'
    return [b, w, res]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[['...', '...', '...'], 5], [0, 0, 'W+0.5']], [[['B..W', 'B..W', 'B..W', 'B..W'], 75], [4, 4, 'W+7.5']], [[['BBBB', 'B..B', 'B..B', 'BBBB'], 5], [16, 0, 'B+15.5']], [[['WWW', 'W.W', 'WWW'], 65], [0, 9, 'W+15.5']], [[['B.W', '...', 'W.B'], 75], [2, 2, 'W+7.5']], [[['.B...', 'B....', '.....', '....W', '...W.'], 35], [3, 3, 'W+3.5']], [[['BW.', 'BW.', 'BW.'], 60], [3, 6, 'W+9.0']], [[['.....', '.BBB.', '.B.B.', '.BBB.', '.....'], 70], [25, 0, 'B+18.0']]], [[[['...', '...', '...'], 5], [0, 0, 'W+0.5']], [[['.W.B.', 'W.WB.', '.WB..', 'WB...', 'B....'], 0], [16, 8, 'B+8.0']], [[['..W', '.W.', 'W..'], 0], [0, 9, 'W+9.0']], [[['B....B', '......', '..WW..', '..WW..', '......', 'B....B'], 5], [4, 4, 'W+0.5']], [[['.BBW.', 'B.BBB', '...W.', '.B.WB'], 65], [9, 3, 'W+0.5']], [[['BB.W.', 'BB.WW', 'W..WW', '.W...', '.B...'], 75], [5, 8, 'W+10.5']], [[['B..', '..W', '...', '.WW'], 35], [1, 3, 'W+5.5']], [[['...B..', '.B..B.', '..W...', 'B..B..'], 60], [5, 1, 'W+2.0']]], [[[['...', '...', '...'], 5], [0, 0, 'W+0.5']], [[['B....B', '......', '..WW..', '..WW..', '......', 'B....B'], 5], [4, 4, 'W+0.5']], [[['WBWWB', 'BB.B.', 'WBWB.', 'WBWBB'], -5], [12, 7, 'B+5.5']], [[['...', '...', '.B.', '.WB', '...', 'B..'], 0], [3, 1, 'B+2.0']], [[['.....', '.W...', 'WW...'], 5], [0, 15, 'W+15.5']], [[['.B.', '.WW', 'BBB', 'WW.'], 65], [4, 4, 'W+6.5']], [[['.B.BB', 'WB...', '.....'], 75], [4, 1, 'W+4.5']], [[['.WBB', 'BW..', '..B.'], 35], [4, 2, 'W+1.5']]], [[[['...', '...', '...'], 5], [0, 0, 'W+0.5']], [[['B..', '..W', '...', '.WW'], 35], [1, 3, 'W+5.5']], [[['B..', '.B.', '...', '...', 'B..', 'BB.'], 70], [18, 0, 'B+11.0']], [[['BW.B', '.WWW', 'B.BB', 'WBB.', 'BW.W'], -5], [8, 7, 'B+1.5']], [[['......', '..W...', 'WW.WW.', '......', 'WBW...'], 0], [1, 7, 'W+6.0']], [[['W..W', '.B..', 'B.W.', '.W..', '....'], 5], [2, 4, 'W+2.5']], [[['BWBB.', '.B..B', 'BW..B', 'W.BBW', '...BB'], 65], [13, 4, 'B+2.5']], [[['...W..', '..WBW.', 'W...WW', '.WW..W'], 75], [1, 13, 'W+19.5']]], [[[['...', '...', '...'], 5], [0, 0, 'W+0.5']], [[['WBWWB', 'BB.B.', 'WBWB.', 'WBWBB'], -5], [12, 7, 'B+5.5']], [[['W..B.', 'BB.BB', 'B..B.', 'BBB..', 'B.BBB'], 60], [19, 1, 'B+12.0']], [[['.BBBW.', 'WBBBB.', '.WBB..', 'BBB...', 'BBW..B', '..BW.W'], 70], [18, 6, 'B+5.0']], [[['W..BBB', 'BWB.W.', '.WWWWW', 'W.WBWW'], -5], [6, 13, 'W+6.5']], [[['W..B', '...B', 'WWWW'], 0], [2, 5, 'W+3.0']], [[['W...', 'WBWB', 'WWBW', 'BBB.'], 5], [6, 6, 'W+0.5']], [[['WW..', 'WWW.', 'BWWW'], 65], [1, 11, 'W+16.5']]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("area 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)

source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    board, komi = x
    n = len(board)
    m = len(board[0])
    b = sum(row.count('B') for row in board)
    w = sum(row.count('W') for row in board)
    seen = set()
    for r in range(n):
        for c in range(m):
            if board[r][c] != '.' or (r, c) in seen:
                continue
            stack = [(r, c)]
            seen.add((r, c))
            size = 0
            border = set()
            while stack:
                i, j = stack.pop()
                size += 1
                for di, dj in ((1, 0), (-1, 0), (0, 1), (0, -1)):
                    a, d = i + di, j + dj
                    if 0 <= a < n and 0 <= d < m:
                        v = board[a][d]
                        if v == '.':
                            if (a, d) not in seen:
                                seen.add((a, d))
                                stack.append((a, d))
                        else:
                            border.add(v)
            if border <= {'B'}:
                b += size
            elif border <= {'W'}:
                w += size
    diff = b * 10 - w * 10 - komi
    if diff > 0:
        res = 'B+%d.%d' % (diff // 10, diff % 10)
    elif diff < 0:
        res = 'W+%d.%d' % ((-diff) // 10, (-diff) % 10)
    else:
        res = 'Draw'
    return [b, w, res]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[['...', '...', '...'], 5], [0, 0, 'W+0.5']], [[['B..W', 'B..W', 'B..W', 'B..W'], 75], [4, 4, 'W+7.5']], [[['BBBB', 'B..B', 'B..B', 'BBBB'], 5], [16, 0, 'B+15.5']], [[['WWW', 'W.W', 'WWW'], 65], [0, 9, 'W+15.5']], [[['B.W', '...', 'W.B'], 75], [2, 2, 'W+7.5']], [[['.B...', 'B....', '.....', '....W', '...W.'], 35], [3, 3, 'W+3.5']], [[['BW.', 'BW.', 'BW.'], 60], [3, 6, 'W+9.0']], [[['.....', '.BBB.', '.B.B.', '.BBB.', '.....'], 70], [25, 0, 'B+18.0']]], [[[['...', '...', '...'], 5], [0, 0, 'W+0.5']], [[['.W.B.', 'W.WB.', '.WB..', 'WB...', 'B....'], 0], [16, 8, 'B+8.0']], [[['..W', '.W.', 'W..'], 0], [0, 9, 'W+9.0']], [[['B....B', '......', '..WW..', '..WW..', '......', 'B....B'], 5], [4, 4, 'W+0.5']], [[['.BBW.', 'B.BBB', '...W.', '.B.WB'], 65], [9, 3, 'W+0.5']], [[['BB.W.', 'BB.WW', 'W..WW', '.W...', '.B...'], 75], [5, 8, 'W+10.5']], [[['B..', '..W', '...', '.WW'], 35], [1, 3, 'W+5.5']], [[['...B..', '.B..B.', '..W...', 'B..B..'], 60], [5, 1, 'W+2.0']]], [[[['...', '...', '...'], 5], [0, 0, 'W+0.5']], [[['B....B', '......', '..WW..', '..WW..', '......', 'B....B'], 5], [4, 4, 'W+0.5']], [[['WBWWB', 'BB.B.', 'WBWB.', 'WBWBB'], -5], [12, 7, 'B+5.5']], [[['...', '...', '.B.', '.WB', '...', 'B..'], 0], [3, 1, 'B+2.0']], [[['.....', '.W...', 'WW...'], 5], [0, 15, 'W+15.5']], [[['.B.', '.WW', 'BBB', 'WW.'], 65], [4, 4, 'W+6.5']], [[['.B.BB', 'WB...', '.....'], 75], [4, 1, 'W+4.5']], [[['.WBB', 'BW..', '..B.'], 35], [4, 2, 'W+1.5']]], [[[['...', '...', '...'], 5], [0, 0, 'W+0.5']], [[['B..', '..W', '...', '.WW'], 35], [1, 3, 'W+5.5']], [[['B..', '.B.', '...', '...', 'B..', 'BB.'], 70], [18, 0, 'B+11.0']], [[['BW.B', '.WWW', 'B.BB', 'WBB.', 'BW.W'], -5], [8, 7, 'B+1.5']], [[['......', '..W...', 'WW.WW.', '......', 'WBW...'], 0], [1, 7, 'W+6.0']], [[['W..W', '.B..', 'B.W.', '.W..', '....'], 5], [2, 4, 'W+2.5']], [[['BWBB.', '.B..B', 'BW..B', 'W.BBW', '...BB'], 65], [13, 4, 'B+2.5']], [[['...W..', '..WBW.', 'W...WW', '.WW..W'], 75], [1, 13, 'W+19.5']]], [[[['...', '...', '...'], 5], [0, 0, 'W+0.5']], [[['WBWWB', 'BB.B.', 'WBWB.', 'WBWBB'], -5], [12, 7, 'B+5.5']], [[['W..B.', 'BB.BB', 'B..B.', 'BBB..', 'B.BBB'], 60], [19, 1, 'B+12.0']], [[['.BBBW.', 'WBBBB.', '.WBB..', 'BBB...', 'BBW..B', '..BW.W'], 70], [18, 6, 'B+5.0']], [[['W..BBB', 'BWB.W.', '.WWWWW', 'W.WBWW'], -5], [6, 13, 'W+6.5']], [[['W..B', '...B', 'WWWW'], 0], [2, 5, 'W+3.0']], [[['W...', 'WBWB', 'WWBW', 'BBB.'], 5], [6, 6, 'W+0.5']], [[['WW..', 'WWW.', 'BWWW'], 65], [1, 11, 'W+16.5']]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("area 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)

prompt:
Neutral points between the two armies are added to black area and the reported margin is inflated.

Input [board, komi_tenths]. Area = own stones + empty regions whose orthogonal border touches only that colour. Return [black_area, white_area, result] where result is "B+x.y" / "W+x.y" after subtracting komi from black, or "Draw".

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    board, komi = x
    n = len(board)
    m = len(board[0])
    b = sum(row.count('B') for row in board)
    w = sum(row.count('W') for row in board)
    seen = set()
    for r in range(n):
        for c in range(m):
            if board[r][c] != '.' or (r, c) in seen:
                continue
            stack = [(r, c)]
            seen.add((r, c))
            size = 0
            border = set()
            while stack:
                i, j = stack.pop()
                size += 1
                for di, dj in ((1, 0), (-1, 0), (0, 1), (0, -1)):
                    a, d = i + di, j + dj
                    if 0 <= a < n and 0 <= d < m:
                        v = board[a][d]
                        if v == '.':
                            if (a, d) not in seen:
                                seen.add((a, d))
                                stack.append((a, d))
                        else:
                            border.add(v)
            if border == {'B'}:
                b += size
            elif border == {'W'}:
                w += size
    diff = b * 10 - w * 10 + komi
    if diff > 0:
        res = 'B+%d.%d' % (diff // 10, diff % 10)
    elif diff < 0:
        res = 'W+%d.%d' % ((-diff) // 10, (-diff) % 10)
    else:
        res = 'Draw'
    return [b, w, res]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[['...', '...', '...'], 5], [0, 0, 'W+0.5']], [[['.W.B.', 'W.WB.', '.WB..', 'WB...', 'B....'], 0], [16, 8, 'B+8.0']], [[['BBBB', 'B..B', 'B..B', 'BBBB'], 5], [16, 0, 'B+15.5']], [[['WWW', 'W.W', 'WWW'], 65], [0, 9, 'W+15.5']], [[['B.W', '...', 'W.B'], 75], [2, 2, 'W+7.5']], [[['.B...', 'B....', '.....', '....W', '...W.'], 35], [3, 3, 'W+3.5']], [[['BW.', 'BW.', 'BW.'], 60], [3, 6, 'W+9.0']], [[['.....', '.BBB.', '.B.B.', '.BBB.', '.....'], 70], [25, 0, 'B+18.0']]], [[[['.BW.', '.BW.', '.BW.', '.BW.'], 35], [8, 8, 'W+3.5']], [[['WB.B', 'B.B.', '.B..', 'B...'], -5], [15, 1, 'B+14.5']], [[['..W', '.W.', 'W..'], 0], [0, 9, 'W+9.0']], [[['B....B', '......', '..WW..', '..WW..', '......', 'B....B'], 5], [4, 4, 'W+0.5']], [[['.BBW.', 'B.BBB', '...W.', '.B.WB'], 65], [9, 3, 'W+0.5']], [[['BB.W.', 'BB.WW', 'W..WW', '.W...', '.B...'], 75], [5, 8, 'W+10.5']], [[['B..', '..W', '...', '.WW'], 35], [1, 3, 'W+5.5']], [[['...B..', '.B..B.', '..W...', 'B..B..'], 60], [5, 1, 'W+2.0']]], [[[['W....', '.....', '.....', '.....', '....B'], -5], [1, 1, 'B+0.5']], [[['..B', '.WB', 'BW.', '...', '.B.', 'BBB'], 70], [7, 2, 'W+2.0']], [[['WBWWB', 'BB.B.', 'WBWB.', 'WBWBB'], -5], [12, 7, 'B+5.5']], [[['...', '...', '.B.', '.WB', '...', 'B..'], 0], [3, 1, 'B+2.0']], [[['.....', '.W...', 'WW...'], 5], [0, 15, 'W+15.5']], [[['.B.', '.WW', 'BBB', 'WW.'], 65], [4, 4, 'W+6.5']], [[['.B.BB', 'WB...', '.....'], 75], [4, 1, 'W+4.5']], [[['.WBB', 'BW..', '..B.'], 35], [4, 2, 'W+1.5']]], [[[['B.W', '...', 'W.B'], 75], [2, 2, 'W+7.5']], [[['B.BW.', 'W.B..', 'W..B.', 'B.B.B'], 60], [8, 3, 'W+1.0']], [[['B..', '.B.', '...', '...', 'B..', 'BB.'], 70], [18, 0, 'B+11.0']], [[['BW.B', '.WWW', 'B.BB', 'WBB.', 'BW.W'], -5], [8, 7, 'B+1.5']], [[['......', '..W...', 'WW.WW.', '......', 'WBW...'], 0], [1, 7, 'W+6.0']], [[['W..W', '.B..', 'B.W.', '.W..', '....'], 5], [2, 4, 'W+2.5']], [[['BWBB.', '.B..B', 'BW..B', 'W.BBW', '...BB'], 65], [13, 4, 'B+2.5']], [[['...W..', '..WBW.', 'W...WW', '.WW..W'], 75], [1, 13, 'W+19.5']]], [[[['.....', '.BBB.', '.B.B.', '.BBB.', '.....'], 70], [25, 0, 'B+18.0']], [[['....W', 'BBWWB', 'B..W.', 'W..W.', 'W.W..', '.....'], 35], [4, 8, 'W+7.5']], [[['W..B.', 'BB.BB', 'B..B.', 'BBB..', 'B.BBB'], 60], [19, 1, 'B+12.0']], [[['.BBBW.', 'WBBBB.', '.WBB..', 'BBB...', 'BBW..B', '..BW.W'], 70], [18, 6, 'B+5.0']], [[['W..BBB', 'BWB.W.', '.WWWWW', 'W.WBWW'], -5], [6, 13, 'W+6.5']], [[['W..B', '...B', 'WWWW'], 0], [2, 5, 'W+3.0']], [[['W...', 'WBWB', 'WWBW', 'BBB.'], 5], [6, 6, 'W+0.5']], [[['WW..', 'WWW.', 'BWWW'], 65], [1, 11, 'W+16.5']]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("area 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)

source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    board, komi = x
    n = len(board)
    m = len(board[0])
    b = sum(row.count('B') for row in board)
    w = sum(row.count('W') for row in board)
    seen = set()
    for r in range(n):
        for c in range(m):
            if board[r][c] != '.' or (r, c) in seen:
                continue
            stack = [(r, c)]
            seen.add((r, c))
            size = 0
            border = set()
            while stack:
                i, j = stack.pop()
                size += 1
                for di, dj in ((1, 0), (-1, 0), (0, 1), (0, -1)):
                    a, d = i + di, j + dj
                    if 0 <= a < n and 0 <= d < m:
                        v = board[a][d]
                        if v == '.':
                            if (a, d) not in seen:
                                seen.add((a, d))
                                stack.append((a, d))
                        else:
                            border.add(v)
            if border == {'B'}:
                b += size
            elif border == {'W'}:
                w += size
    diff = (b - w - komi // 10) * 10
    if diff > 0:
        res = 'B+%d.%d' % (diff // 10, diff % 10)
    elif diff < 0:
        res = 'W+%d.%d' % ((-diff) // 10, (-diff) % 10)
    else:
        res = 'Draw'
    return [b, w, res]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[['...', '...', '...'], 5], [0, 0, 'W+0.5']], [[['.W.B.', 'W.WB.', '.WB..', 'WB...', 'B....'], 0], [16, 8, 'B+8.0']], [[['BBBB', 'B..B', 'B..B', 'BBBB'], 5], [16, 0, 'B+15.5']], [[['WWW', 'W.W', 'WWW'], 65], [0, 9, 'W+15.5']], [[['B.W', '...', 'W.B'], 75], [2, 2, 'W+7.5']], [[['.B...', 'B....', '.....', '....W', '...W.'], 35], [3, 3, 'W+3.5']], [[['BW.', 'BW.', 'BW.'], 60], [3, 6, 'W+9.0']], [[['.....', '.BBB.', '.B.B.', '.BBB.', '.....'], 70], [25, 0, 'B+18.0']]], [[[['.BW.', '.BW.', '.BW.', '.BW.'], 35], [8, 8, 'W+3.5']], [[['WB.B', 'B.B.', '.B..', 'B...'], -5], [15, 1, 'B+14.5']], [[['..W', '.W.', 'W..'], 0], [0, 9, 'W+9.0']], [[['B....B', '......', '..WW..', '..WW..', '......', 'B....B'], 5], [4, 4, 'W+0.5']], [[['.BBW.', 'B.BBB', '...W.', '.B.WB'], 65], [9, 3, 'W+0.5']], [[['BB.W.', 'BB.WW', 'W..WW', '.W...', '.B...'], 75], [5, 8, 'W+10.5']], [[['B..', '..W', '...', '.WW'], 35], [1, 3, 'W+5.5']], [[['...B..', '.B..B.', '..W...', 'B..B..'], 60], [5, 1, 'W+2.0']]], [[[['W....', '.....', '.....', '.....', '....B'], -5], [1, 1, 'B+0.5']], [[['..B', '.WB', 'BW.', '...', '.B.', 'BBB'], 70], [7, 2, 'W+2.0']], [[['WBWWB', 'BB.B.', 'WBWB.', 'WBWBB'], -5], [12, 7, 'B+5.5']], [[['...', '...', '.B.', '.WB', '...', 'B..'], 0], [3, 1, 'B+2.0']], [[['.....', '.W...', 'WW...'], 5], [0, 15, 'W+15.5']], [[['.B.', '.WW', 'BBB', 'WW.'], 65], [4, 4, 'W+6.5']], [[['.B.BB', 'WB...', '.....'], 75], [4, 1, 'W+4.5']], [[['.WBB', 'BW..', '..B.'], 35], [4, 2, 'W+1.5']]], [[[['B.W', '...', 'W.B'], 75], [2, 2, 'W+7.5']], [[['B.BW.', 'W.B..', 'W..B.', 'B.B.B'], 60], [8, 3, 'W+1.0']], [[['B..', '.B.', '...', '...', 'B..', 'BB.'], 70], [18, 0, 'B+11.0']], [[['BW.B', '.WWW', 'B.BB', 'WBB.', 'BW.W'], -5], [8, 7, 'B+1.5']], [[['......', '..W...', 'WW.WW.', '......', 'WBW...'], 0], [1, 7, 'W+6.0']], [[['W..W', '.B..', 'B.W.', '.W..', '....'], 5], [2, 4, 'W+2.5']], [[['BWBB.', '.B..B', 'BW..B', 'W.BBW', '...BB'], 65], [13, 4, 'B+2.5']], [[['...W..', '..WBW.', 'W...WW', '.WW..W'], 75], [1, 13, 'W+19.5']]], [[[['.....', '.BBB.', '.B.B.', '.BBB.', '.....'], 70], [25, 0, 'B+18.0']], [[['....W', 'BBWWB', 'B..W.', 'W..W.', 'W.W..', '.....'], 35], [4, 8, 'W+7.5']], [[['W..B.', 'BB.BB', 'B..B.', 'BBB..', 'B.BBB'], 60], [19, 1, 'B+12.0']], [[['.BBBW.', 'WBBBB.', '.WBB..', 'BBB...', 'BBW..B', '..BW.W'], 70], [18, 6, 'B+5.0']], [[['W..BBB', 'BWB.W.', '.WWWWW', 'W.WBWW'], -5], [6, 13, 'W+6.5']], [[['W..B', '...B', 'WWWW'], 0], [2, 5, 'W+3.0']], [[['W...', 'WBWB', 'WWBW', 'BBB.'], 5], [6, 6, 'W+0.5']], [[['WW..', 'WWW.', 'BWWW'], 65], [1, 11, 'W+16.5']]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("area 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)

prompt:
Close games flip winner; the half-point margin moves the wrong way.

Input [board, komi_tenths]. Area = own stones + empty regions whose orthogonal border touches only that colour. Return [black_area, white_area, result] where result is "B+x.y" / "W+x.y" after subtracting komi from black, or "Draw".

split: open-access