FA-82906 / Go territory scoring / Open access
Ko ban is set when the capturing stone joins a friendly chain · case 01
A single-stone capture by a connected stone forbids an immediate recapture that is actually legal.
ROOT CAUSE
The rule that the capturing stone must stand alone is not checked.
VERIFIED REPAIR
Return None whenever the played stone has any friendly orthogonal neighbour.
Unsuccessful approach: Rejecting only stones with two or more friendly neighbours still bans recapture after a one-neighbour connection.
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 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], [[['BW.', '.BW', 'BWB', 'WB.', 'BBB'], 4, 2, [[3, 2]]], None], [[['..BW.', '...WW', 'W...B', 'B.B.B'], 0, 3, [[0, 4]]], 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], [[['WWW', '.WW', 'W.B', '..W'], 0, 0, [[1, 0]]], None], [[['B...B', '.BWWB', 'WBBB.', '...WB'], 1, 4, [[2, 4]]], 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], [[['....', '.BWW', 'WW.W', 'WWW.'], 2, 1, [[2, 2]]], None], [[['.B..', 'WBBB', 'BBBW', '.BBW', 'BBBB'], 2, 0, [[3, 0]]], 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.WB', 'BWB.B', 'BW.BW', '.B.BW', '...WW'], 1, 0, [[0, 0]]], None], [[['WWBW', 'WB..', '.WWW', 'BW.W'], 3, 1, [[3, 2]]], 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], [[['WWBW', 'WB..', '.WWW', 'BW.W'], 3, 1, [[3, 2]]], None], [[['BBB.B', 'B.BW.', 'BBB.W'], 1, 0, [[1, 1]]], 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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| ko point case 0 | [3, 0] | [3, 0] | Passed |
| ko point case 1 | None | None | Passed |
| ko point case 2 | None | None | Passed |
| ko point case 3 | None | None | Passed |
| ko point case 4 | None | None | Passed |
| ko point case 5 | None | None | Passed |
| ko point case 6 | [3, 2] | None | Failed |
| ko point case 7 | [0, 4] | None | Failed |
SHA-256 / 7b2abf73c3e4af4aed19d6eb2017fea7f05009053339471139486f46d9e5cbe3
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 > 1:
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], [[['BW.', '.BW', 'BWB', 'WB.', 'BBB'], 4, 2, [[3, 2]]], None], [[['..BW.', '...WW', 'W...B', 'B.B.B'], 0, 3, [[0, 4]]], 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], [[['WWW', '.WW', 'W.B', '..W'], 0, 0, [[1, 0]]], None], [[['B...B', '.BWWB', 'WBBB.', '...WB'], 1, 4, [[2, 4]]], 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], [[['....', '.BWW', 'WW.W', 'WWW.'], 2, 1, [[2, 2]]], None], [[['.B..', 'WBBB', 'BBBW', '.BBW', 'BBBB'], 2, 0, [[3, 0]]], 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.WB', 'BWB.B', 'BW.BW', '.B.BW', '...WW'], 1, 0, [[0, 0]]], None], [[['WWBW', 'WB..', '.WWW', 'BW.W'], 3, 1, [[3, 2]]], 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], [[['WWBW', 'WB..', '.WWW', 'BW.W'], 3, 1, [[3, 2]]], None], [[['BBB.B', 'B.BW.', 'BBB.W'], 1, 0, [[1, 1]]], 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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| ko point case 0 | [3, 0] | [3, 0] | Passed |
| ko point case 1 | None | None | Passed |
| ko point case 2 | None | None | Passed |
| ko point case 3 | None | None | Passed |
| ko point case 4 | None | None | Passed |
| ko point case 5 | None | None | Passed |
| ko point case 6 | [3, 2] | None | Failed |
| ko point case 7 | [0, 4] | None | Failed |
SHA-256 / b7eb7e2d65ae3adabde57a56b746a5057244103de7626cfdbe63351b370e3bc4
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], [[['BW.', '.BW', 'BWB', 'WB.', 'BBB'], 4, 2, [[3, 2]]], None], [[['..BW.', '...WW', 'W...B', 'B.B.B'], 0, 3, [[0, 4]]], 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], [[['WWW', '.WW', 'W.B', '..W'], 0, 0, [[1, 0]]], None], [[['B...B', '.BWWB', 'WBBB.', '...WB'], 1, 4, [[2, 4]]], 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], [[['....', '.BWW', 'WW.W', 'WWW.'], 2, 1, [[2, 2]]], None], [[['.B..', 'WBBB', 'BBBW', '.BBW', 'BBBB'], 2, 0, [[3, 0]]], 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.WB', 'BWB.B', 'BW.BW', '.B.BW', '...WW'], 1, 0, [[0, 0]]], None], [[['WWBW', 'WB..', '.WWW', 'BW.W'], 3, 1, [[3, 2]]], 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], [[['WWBW', 'WB..', '.WWW', 'BW.W'], 3, 1, [[3, 2]]], None], [[['BBB.B', 'B.BW.', 'BBB.W'], 1, 0, [[1, 1]]], 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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| ko point case 0 | [3, 0] | [3, 0] | Passed |
| ko point case 1 | None | None | Passed |
| ko point case 2 | None | None | Passed |
| ko point case 3 | None | None | Passed |
| ko point case 4 | None | None | Passed |
| ko point case 5 | None | None | Passed |
| ko point case 6 | None | None | Passed |
| ko point case 7 | None | None | Passed |
SHA-256 / f3ba1d5fca608405a0b6b96ead577e0adf748384aeb9546cfc35274b6b85d18b
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.576996+00:00.
Case digest / 726df7eeb9ef80f22c0bebe86e90f48306d6b29f2c863159bcf4d400313fcd75