FAILURE MAP
← Case archive

FA-82911 / Go territory scoring / Open access

Ko is declared although the capturing stone has several liberties · case 01

Snapback-style single captures with open points around are flagged as ko.

Verified by executionVariant 1 · 8 checks per implementationDownload source bundle ↓JSON ↗

ROOT CAUSE

The liberty count test on the capturing stone is missing.

VERIFIED REPAIR

Require exactly one liberty on the capturing stone.

Unsuccessful approach: Allowing up to two liberties still flags positions where recapture cannot repeat the board.

Case contract

Input [board_after_move, row, col, captured_points]. A ko ban point exists only when exactly one stone was captured, the played stone has no friendly orthogonal neighbour, and it has exactly one liberty. Return the captured point or None.

Why this case matters

Go servers and scoring tools compute this value automatically; a wrong answer changes a game result.

1 / The failure

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    board, r, c, captured = x
    n = len(board)
    m = len(board[0])
    color = board[r][c]
    same = 0
    libs = []
    for p, q in ((r + 1, c), (r - 1, c), (r, c + 1), (r, c - 1)):
        if 0 <= p < n and 0 <= q < m:
            if board[p][q] == color:
                same += 1
            elif board[p][q] == '.':
                libs.append([p, q])
    if len(captured) != 1:
        return None
    if same:
        return None
    return captured[0]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[['.W.B.', 'W.WB.', 'BWB..', '.B...', 'B....'], 2, 0, [[3, 0]]], [3, 0]], [[['.W.B.', 'W.WB.', '.WB..', 'WB...', '.W...'], 4, 1, [[4, 0]]], None], [[['BBBB', 'B..B', 'B.BB', 'BBBB'], 2, 2, []], None], [[['...', '.B.', '...'], 1, 1, [[0, 0], [0, 1], [0, 2], [1, 0], [1, 2], [2, 0], [2, 1], [2, 2]]], None], [[['B.W', '...', 'WWB'], 2, 1, []], None], [[['.B...', 'B....', '..W..', '....W', '...W.'], 2, 2, []], None], [[['.B...', 'B....', '.....', '...BW', '...W.'], 3, 3, []], None], [[['.W..W', 'WBW.W', 'B.B..'], 0, 1, [[0, 0]]], None]], [[[['.B...', 'B....', '.....', '...WW', '...W.'], 3, 3, []], None], [[['.....', '.BBB.', '.B.BB', '.BBB.', '.....'], 2, 4, []], None], [[['.....', '.BBB.', '.B.B.', 'WBBB.', '.....'], 3, 0, []], None], [[['B....B', '......', '..WWB.', '..WW..', '......', 'B....B'], 2, 4, []], None], [[['B....B', '......', '..WW..', '.WWW..', '......', 'B....B'], 3, 1, []], None], [[['B.B', '.B.', 'BWB', 'WBW', 'BB.'], 0, 2, [[1, 2], [0, 1]]], None], [[['BB.', 'WWW', 'W.W', '.W.'], 3, 1, [[2, 1]]], None], [[['W.WBW', 'BW..B', 'BB.WB', 'W.BWB'], 0, 2, [[0, 1]]], None]], [[[['BW.', '.BW', 'BWB', 'WB.', 'BBB'], 4, 2, [[3, 2]]], None], [[['BW.', '.BW', 'BWB', 'W.W', '..W'], 4, 2, [[3, 1], [4, 0], [4, 1]]], None], [[['..BWW', '....W', 'W..B.'], 2, 0, []], None], [[['W.W.B', '.WW..', '.W.BB'], 0, 0, [[1, 0], [2, 0], [0, 1]]], None], [[['..W..', 'B..WW', '...BW', 'W..B.', '..W.W'], 0, 2, [[0, 3], [0, 4]]], None], [[['.W..', 'W..W', '.B.W'], 0, 1, [[0, 0]]], None], [[['W.W..', 'WB..B', 'B.BWW'], 2, 2, [[2, 1]]], None], [[['WWWBW', 'BWBB.', '.BB.B', '..BWB', 'WB.B.'], 4, 3, [[4, 4]]], None]], [[[['BW..', 'W.W.', 'BWW.', 'B.BW', 'B..W'], 1, 2, [[1, 1]]], None], [[['BW..', 'WB.B', 'BWW.', 'B.BW', 'B..W'], 1, 3, []], None], [[['.....', '..W..', 'W.WB.', 'BW.W.'], 2, 3, []], None], [[['..W', 'WWW', 'WBW', '...'], 0, 2, [[0, 0], [0, 1]]], None], [[['BB.', 'WWW', 'W.W', '.W.'], 3, 1, [[2, 1]]], None], [[['.BB', 'B.B', 'BWB', 'W.W'], 2, 1, [[3, 1]]], None], [[['..B.B', '...WW', 'W...B', '.WB.B'], 3, 1, [[3, 0]]], None], [[['.B.WW', 'B..W.', 'W.W..', '.W...'], 1, 0, [[0, 0]]], None]], [[[['W.WWB', '.WB.B', 'BW.BW', '.B.BW', '...WW'], 0, 2, [[0, 1]]], None], [[['.B.WB', 'BWB.B', 'BW.BW', '.B.BW', '...WW'], 1, 0, [[0, 0]]], None], [[['WB.W.', '.WBW.', 'BW.BW', '.B.BW', '...WW'], 1, 3, [[0, 4], [1, 4]]], None], [[['WB.WB', '.WB.B', 'BW.B.', '.B.B.', '..B..'], 4, 2, [[2, 4], [3, 4], [4, 3], [4, 4]]], None], [[['BB.', 'BBB', 'BB.', '..B', 'B.B'], 2, 1, [[3, 0], [3, 1], [4, 1]]], None], [[['BB.', 'BBB', 'B.W', 'WW.', 'BW.'], 2, 2, [[3, 2], [4, 2]]], None], [[['W.W..', 'WB..B', 'B.BWW'], 2, 2, [[2, 1]]], None], [[['.W..W', 'WBW.W', 'B.B..'], 0, 1, [[0, 0]]], None]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("ko point case %d" % i, solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
ko point case 0[3, 0][3, 0]Passed
ko point case 1[4, 0]NoneFailed
ko point case 2NoneNonePassed
ko point case 3NoneNonePassed
ko point case 4NoneNonePassed
ko point case 5NoneNonePassed
ko point case 6NoneNonePassed
ko point case 7[0, 0]NoneFailed

SHA-256 / b6e13df816bafd2f986fc83f62e15a65a6881eb69458e94f805d6bc0e020ed21

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    board, r, c, captured = x
    n = len(board)
    m = len(board[0])
    color = board[r][c]
    same = 0
    libs = []
    for p, q in ((r + 1, c), (r - 1, c), (r, c + 1), (r, c - 1)):
        if 0 <= p < n and 0 <= q < m:
            if board[p][q] == color:
                same += 1
            elif board[p][q] == '.':
                libs.append([p, q])
    if len(captured) != 1:
        return None
    if same:
        return None
    if len(libs) > 2:
        return None
    return captured[0]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[['.W.B.', 'W.WB.', 'BWB..', '.B...', 'B....'], 2, 0, [[3, 0]]], [3, 0]], [[['.W.B.', 'W.WB.', '.WB..', 'WB...', '.W...'], 4, 1, [[4, 0]]], None], [[['BBBB', 'B..B', 'B.BB', 'BBBB'], 2, 2, []], None], [[['...', '.B.', '...'], 1, 1, [[0, 0], [0, 1], [0, 2], [1, 0], [1, 2], [2, 0], [2, 1], [2, 2]]], None], [[['B.W', '...', 'WWB'], 2, 1, []], None], [[['.B...', 'B....', '..W..', '....W', '...W.'], 2, 2, []], None], [[['.B...', 'B....', '.....', '...BW', '...W.'], 3, 3, []], None], [[['.W..W', 'WBW.W', 'B.B..'], 0, 1, [[0, 0]]], None]], [[[['.B...', 'B....', '.....', '...WW', '...W.'], 3, 3, []], None], [[['.....', '.BBB.', '.B.BB', '.BBB.', '.....'], 2, 4, []], None], [[['.....', '.BBB.', '.B.B.', 'WBBB.', '.....'], 3, 0, []], None], [[['B....B', '......', '..WWB.', '..WW..', '......', 'B....B'], 2, 4, []], None], [[['B....B', '......', '..WW..', '.WWW..', '......', 'B....B'], 3, 1, []], None], [[['B.B', '.B.', 'BWB', 'WBW', 'BB.'], 0, 2, [[1, 2], [0, 1]]], None], [[['BB.', 'WWW', 'W.W', '.W.'], 3, 1, [[2, 1]]], None], [[['W.WBW', 'BW..B', 'BB.WB', 'W.BWB'], 0, 2, [[0, 1]]], None]], [[[['BW.', '.BW', 'BWB', 'WB.', 'BBB'], 4, 2, [[3, 2]]], None], [[['BW.', '.BW', 'BWB', 'W.W', '..W'], 4, 2, [[3, 1], [4, 0], [4, 1]]], None], [[['..BWW', '....W', 'W..B.'], 2, 0, []], None], [[['W.W.B', '.WW..', '.W.BB'], 0, 0, [[1, 0], [2, 0], [0, 1]]], None], [[['..W..', 'B..WW', '...BW', 'W..B.', '..W.W'], 0, 2, [[0, 3], [0, 4]]], None], [[['.W..', 'W..W', '.B.W'], 0, 1, [[0, 0]]], None], [[['W.W..', 'WB..B', 'B.BWW'], 2, 2, [[2, 1]]], None], [[['WWWBW', 'BWBB.', '.BB.B', '..BWB', 'WB.B.'], 4, 3, [[4, 4]]], None]], [[[['BW..', 'W.W.', 'BWW.', 'B.BW', 'B..W'], 1, 2, [[1, 1]]], None], [[['BW..', 'WB.B', 'BWW.', 'B.BW', 'B..W'], 1, 3, []], None], [[['.....', '..W..', 'W.WB.', 'BW.W.'], 2, 3, []], None], [[['..W', 'WWW', 'WBW', '...'], 0, 2, [[0, 0], [0, 1]]], None], [[['BB.', 'WWW', 'W.W', '.W.'], 3, 1, [[2, 1]]], None], [[['.BB', 'B.B', 'BWB', 'W.W'], 2, 1, [[3, 1]]], None], [[['..B.B', '...WW', 'W...B', '.WB.B'], 3, 1, [[3, 0]]], None], [[['.B.WW', 'B..W.', 'W.W..', '.W...'], 1, 0, [[0, 0]]], None]], [[[['W.WWB', '.WB.B', 'BW.BW', '.B.BW', '...WW'], 0, 2, [[0, 1]]], None], [[['.B.WB', 'BWB.B', 'BW.BW', '.B.BW', '...WW'], 1, 0, [[0, 0]]], None], [[['WB.W.', '.WBW.', 'BW.BW', '.B.BW', '...WW'], 1, 3, [[0, 4], [1, 4]]], None], [[['WB.WB', '.WB.B', 'BW.B.', '.B.B.', '..B..'], 4, 2, [[2, 4], [3, 4], [4, 3], [4, 4]]], None], [[['BB.', 'BBB', 'BB.', '..B', 'B.B'], 2, 1, [[3, 0], [3, 1], [4, 1]]], None], [[['BB.', 'BBB', 'B.W', 'WW.', 'BW.'], 2, 2, [[3, 2], [4, 2]]], None], [[['W.W..', 'WB..B', 'B.BWW'], 2, 2, [[2, 1]]], None], [[['.W..W', 'WBW.W', 'B.B..'], 0, 1, [[0, 0]]], None]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("ko point case %d" % i, solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
ko point case 0[3, 0][3, 0]Passed
ko point case 1[4, 0]NoneFailed
ko point case 2NoneNonePassed
ko point case 3NoneNonePassed
ko point case 4NoneNonePassed
ko point case 5NoneNonePassed
ko point case 6NoneNonePassed
ko point case 7[0, 0]NoneFailed

SHA-256 / 99e21e6925102603df52eaa2ffef851011e16046cedf2924192c7528ecdd6d16

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    board, r, c, captured = x
    n = len(board)
    m = len(board[0])
    color = board[r][c]
    same = 0
    libs = []
    for p, q in ((r + 1, c), (r - 1, c), (r, c + 1), (r, c - 1)):
        if 0 <= p < n and 0 <= q < m:
            if board[p][q] == color:
                same += 1
            elif board[p][q] == '.':
                libs.append([p, q])
    if len(captured) != 1:
        return None
    if same:
        return None
    if len(libs) != 1:
        return None
    return captured[0]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[['.W.B.', 'W.WB.', 'BWB..', '.B...', 'B....'], 2, 0, [[3, 0]]], [3, 0]], [[['.W.B.', 'W.WB.', '.WB..', 'WB...', '.W...'], 4, 1, [[4, 0]]], None], [[['BBBB', 'B..B', 'B.BB', 'BBBB'], 2, 2, []], None], [[['...', '.B.', '...'], 1, 1, [[0, 0], [0, 1], [0, 2], [1, 0], [1, 2], [2, 0], [2, 1], [2, 2]]], None], [[['B.W', '...', 'WWB'], 2, 1, []], None], [[['.B...', 'B....', '..W..', '....W', '...W.'], 2, 2, []], None], [[['.B...', 'B....', '.....', '...BW', '...W.'], 3, 3, []], None], [[['.W..W', 'WBW.W', 'B.B..'], 0, 1, [[0, 0]]], None]], [[[['.B...', 'B....', '.....', '...WW', '...W.'], 3, 3, []], None], [[['.....', '.BBB.', '.B.BB', '.BBB.', '.....'], 2, 4, []], None], [[['.....', '.BBB.', '.B.B.', 'WBBB.', '.....'], 3, 0, []], None], [[['B....B', '......', '..WWB.', '..WW..', '......', 'B....B'], 2, 4, []], None], [[['B....B', '......', '..WW..', '.WWW..', '......', 'B....B'], 3, 1, []], None], [[['B.B', '.B.', 'BWB', 'WBW', 'BB.'], 0, 2, [[1, 2], [0, 1]]], None], [[['BB.', 'WWW', 'W.W', '.W.'], 3, 1, [[2, 1]]], None], [[['W.WBW', 'BW..B', 'BB.WB', 'W.BWB'], 0, 2, [[0, 1]]], None]], [[[['BW.', '.BW', 'BWB', 'WB.', 'BBB'], 4, 2, [[3, 2]]], None], [[['BW.', '.BW', 'BWB', 'W.W', '..W'], 4, 2, [[3, 1], [4, 0], [4, 1]]], None], [[['..BWW', '....W', 'W..B.'], 2, 0, []], None], [[['W.W.B', '.WW..', '.W.BB'], 0, 0, [[1, 0], [2, 0], [0, 1]]], None], [[['..W..', 'B..WW', '...BW', 'W..B.', '..W.W'], 0, 2, [[0, 3], [0, 4]]], None], [[['.W..', 'W..W', '.B.W'], 0, 1, [[0, 0]]], None], [[['W.W..', 'WB..B', 'B.BWW'], 2, 2, [[2, 1]]], None], [[['WWWBW', 'BWBB.', '.BB.B', '..BWB', 'WB.B.'], 4, 3, [[4, 4]]], None]], [[[['BW..', 'W.W.', 'BWW.', 'B.BW', 'B..W'], 1, 2, [[1, 1]]], None], [[['BW..', 'WB.B', 'BWW.', 'B.BW', 'B..W'], 1, 3, []], None], [[['.....', '..W..', 'W.WB.', 'BW.W.'], 2, 3, []], None], [[['..W', 'WWW', 'WBW', '...'], 0, 2, [[0, 0], [0, 1]]], None], [[['BB.', 'WWW', 'W.W', '.W.'], 3, 1, [[2, 1]]], None], [[['.BB', 'B.B', 'BWB', 'W.W'], 2, 1, [[3, 1]]], None], [[['..B.B', '...WW', 'W...B', '.WB.B'], 3, 1, [[3, 0]]], None], [[['.B.WW', 'B..W.', 'W.W..', '.W...'], 1, 0, [[0, 0]]], None]], [[[['W.WWB', '.WB.B', 'BW.BW', '.B.BW', '...WW'], 0, 2, [[0, 1]]], None], [[['.B.WB', 'BWB.B', 'BW.BW', '.B.BW', '...WW'], 1, 0, [[0, 0]]], None], [[['WB.W.', '.WBW.', 'BW.BW', '.B.BW', '...WW'], 1, 3, [[0, 4], [1, 4]]], None], [[['WB.WB', '.WB.B', 'BW.B.', '.B.B.', '..B..'], 4, 2, [[2, 4], [3, 4], [4, 3], [4, 4]]], None], [[['BB.', 'BBB', 'BB.', '..B', 'B.B'], 2, 1, [[3, 0], [3, 1], [4, 1]]], None], [[['BB.', 'BBB', 'B.W', 'WW.', 'BW.'], 2, 2, [[3, 2], [4, 2]]], None], [[['W.W..', 'WB..B', 'B.BWW'], 2, 2, [[2, 1]]], None], [[['.W..W', 'WBW.W', 'B.B..'], 0, 1, [[0, 0]]], None]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("ko point case %d" % i, solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
ko point case 0[3, 0][3, 0]Passed
ko point case 1NoneNonePassed
ko point case 2NoneNonePassed
ko point case 3NoneNonePassed
ko point case 4NoneNonePassed
ko point case 5NoneNonePassed
ko point case 6NoneNonePassed
ko point case 7NoneNonePassed

SHA-256 / 8aec54464e066ab0943475a8fc35b973f2f8d882ab93869359ab979fc7dabc4a

Verification & scope

Small rectangular toy boards given as strings of B, W and dot; a bounded teaching model of one scoring or bookkeeping rule, not a complete rules engine or server implementation. This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.

Observations recorded using Python 3.12.14 at 2026-09-29T14:50:16.575492+00:00.

Case digest / 8fc5ca74b7300922260eb8b7c3d21c85b59737372b9b14219b25e7957476d018