FA-83336 / Go territory scoring / Open access
Dead stones are also credited as prisoners under area scoring · case 01
Removing a dead stone gives the capturer an extra point on top of the recovered area.
ROOT CAUSE
Territory-scoring prisoner credit is mixed into the area total.
THE FAILURE
Territory-scoring prisoner credit is mixed into the area total.
Unsuccessful approach: Subtracting dead stones from their owner as well still double counts the swing.
Case contract
Input [board, dead_points, komi_tenths]. Remove dead stones (no prisoners in area scoring), then area = remaining stones + regions bordered by one colour. Return [black, white, margin_tenths].
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, dead, komi = x
dd = {tuple(p) for p in dead}
bonus = {'B': 0, 'W': 0}
for r, c in dd:
if board[r][c] != '.':
bonus['W' if board[r][c] == 'B' else 'B'] += 1
g = [[('.' if (r, c) in dd else ch) for c, ch in enumerate(row)] for r, row in enumerate(board)]
n = len(g)
m = len(g[0])
area = {'B': 0, 'W': 0}
for row in g:
for ch in row:
if ch != '.':
area[ch] += 1
seen = set()
for r in range(n):
for c in range(m):
if g[r][c] != '.' or (r, c) in seen:
continue
seen.add((r, c))
todo = [(r, c)]
cnt = 0
edge = set()
while todo:
i, j = todo.pop()
cnt += 1
for p, q in ((i, j + 1), (i, j - 1), (i + 1, j), (i - 1, j)):
if 0 <= p < n and 0 <= q < m:
if g[p][q] == '.':
if (p, q) not in seen:
seen.add((p, q))
todo.append((p, q))
else:
edge.add(g[p][q])
if len(edge) == 1:
area[edge.pop()] += cnt
area['B'] += bonus['B']
area['W'] += bonus['W']
return [area['B'], area['W'], (area['B'] - area['W']) * 10 - komi]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[['.BW..', 'WBW..', 'WBW..', '.BW.B', 'WBW..', 'WBW.B'], [[2, 1]], 0], [7, 10, -30]], [[['.BW...', '.BW...', '.BW...', 'WBW...', 'WBW...'], [[4, 2]], 0], [5, 6, -10]], [[['...W.BW', '.....BW', 'W....BW', '.....BW', '..W..BW'], [[1, 6], [2, 6]], 0], [5, 6, -10]], [[['.BWB', '.BW.', '.BWB', '.BW.', '.BWB'], [], 0], [13, 5, 80]], [[['.W.BW..', '...BW..', '...BWB.', '...BW..'], [[1, 4], [3, 4]], 0], [5, 3, 20]], [[['.BWBB.', '.BW...', '.BW..B', '.BW...', '.BW...', '.BW..B', '.BW.B.'], [[3, 1]], 5], [12, 7, 45]], [[['..W..BW', '.....BW', '..W..BW', '.....BW', '.W...BW', '...W.BW'], [], 0], [6, 10, -40]], [[['.BW..', '.BW..', '.BWB.', '.BWB.', 'WBW..'], [[4, 2]], 75], [7, 5, -55]]], [[[['.BW....', '.BWB...', '.BW.B..', 'WBW.B..', '.BW.B..', '.BW....'], [[5, 2]], 0], [10, 6, 40]], [[['..BWB', '..BW.', '..BWB', 'W.BW.', '..BW.'], [[4, 2], [3, 3]], 75], [6, 5, -65]], [[['.BW.', '.BW.', '.BW.', '.BW.', 'WBW.', '.BW.', 'WBW.'], [[2, 2], [6, 2]], 75], [7, 7, -75]], [[['..BW', '..BW', 'W.BW', '..BW'], [[0, 2], [2, 3]], 75], [3, 4, -85]], [[['.W.BW.', '...BW.', '...BW.', '...BW.', '.W.BW.', '...BW.'], [[4, 3], [0, 4]], 0], [5, 7, -20]], [[['W..BW.', '...BW.', '...BWB', '...BW.'], [[3, 4], [0, 3]], 75], [4, 4, -75]], [[['.WBW...', '..BW...', '..BW...', 'W.BW...', '..BW...'], [[0, 3], [4, 2]], 75], [4, 6, -95]], [[['..BW', 'W.BW', '..BW', 'W.BW', '..BW'], [], 75], [5, 7, -95]]], [[[['...W.BW', '.....BW', 'W....BW', '.....BW', '..W..BW'], [[1, 6], [2, 6]], 0], [5, 6, -10]], [[['..BW...', '..BW...', '..BW...', '..BW...', '..BWB..', '.WBW...'], [[5, 3]], 5], [7, 6, 5]], [[['...BW', '.W.BW', 'W..BW', '..WBW'], [[3, 4], [0, 4]], 5], [4, 5, -15]], [[['..BW..B', '..BW...', '..BW...', '..BW...'], [], 75], [13, 4, 15]], [[['..BW', '..BW', '.WBW', '..BW', '..BW', '..BW'], [[1, 2]], 5], [5, 7, -25]], [[['W.BW.', '..BW.', 'W.BW.', '..BW.', '..BW.', '..BW.', '.WBW.'], [[6, 1]], 5], [7, 16, -95]], [[['..BW.', '..BW.', '..BW.', '..BW.', '..BW.', '..BW.'], [], 5], [18, 12, 55]], [[['..BW.', '.WBW.', '..BW.', '.WBW.'], [[2, 2], [3, 2]], 5], [2, 10, -85]]], [[[['.BW..', '.BW..', '.BWB.', '.BWB.', 'WBW..'], [[4, 2]], 75], [7, 5, -55]], [[['.WBWB', '..BW.', '..BW.', '..BW.', '..BW.'], [], 0], [6, 6, 0]], [[['...BW.B', '...BWBB', '...BWBB', '...BW..', '...BW..'], [[3, 3], [0, 4]], 5], [9, 4, 45]], [[['.W..BW.', '..W.BW.', '....BW.', '..W.BW.', '...WBW.', '....BW.', '...WBW.'], [[2, 4], [3, 5]], 75], [6, 11, -125]], [[['...BW', '..WBW', '...BW', '..WBW', '...BW'], [[2, 3]], 75], [4, 7, -105]], [[['.WBW', '..BW', '..BW', '..BW', '..BW', '..BW'], [[2, 2], [4, 2]], 5], [4, 7, -35]], [[['WBW..', '.BW..', '.BW..', '.BWBB'], [[1, 2]], 0], [6, 4, 20]], [[['...WBW.', '....BW.', '....BW.', 'W...BW.', '....BW.', '..W.BW.'], [[1, 4]], 5], [5, 15, -105]]], [[[['..BW', '..BW', 'W.BW', '..BW'], [[0, 2], [2, 3]], 75], [3, 4, -85]], [[['...WBW.', '....BW.', '....BW.', 'W...BW.', '....BW.', '..W.BW.'], [[1, 4]], 5], [5, 15, -105]], [[['...BW', 'W..BW', '..WBW', '...BW', '..WBW', '...BW'], [[5, 3]], 0], [5, 9, -40]], [[['..BW.', '..BW.', '..BW.', '..BW.', 'W.BW.', '..BW.', '..BW.'], [], 5], [7, 15, -85]], [[['.BWB', '.BW.', '.BW.', '.BW.'], [], 0], [9, 4, 50]], [[['....', '....', '....', '....'], [], 75], [0, 0, -75]], [[['...', '...', '...'], [], 5], [0, 0, -5]], [[['.B.', 'B.B', '.B.'], [[2, 1], [1, 2]], 0], [9, 0, 90]]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
check("area with dead 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 |
|---|---|---|---|
| area with dead case 0 | [7, 11, -40] | [7, 10, -30] | Failed |
| area with dead case 1 | [6, 6, 0] | [5, 6, -10] | Failed |
| area with dead case 2 | [7, 6, 10] | [5, 6, -10] | Failed |
| area with dead case 3 | [13, 5, 80] | [13, 5, 80] | Passed |
| area with dead case 4 | [7, 3, 40] | [5, 3, 20] | Failed |
| area with dead case 5 | [12, 8, 35] | [12, 7, 45] | Failed |
| area with dead case 6 | [6, 10, -40] | [6, 10, -40] | Passed |
| area with dead case 7 | [8, 5, -45] | [7, 5, -55] | Failed |
SHA-256 / 17ed8ea7a723c2cb5418530bafe37fb7fcfa298f2240ba31d7ecfeae463ba8f8
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
board, dead, komi = x
dd = {tuple(p) for p in dead}
g = [[('.' if (r, c) in dd else ch) for c, ch in enumerate(row)] for r, row in enumerate(board)]
n = len(g)
m = len(g[0])
area = {'B': 0, 'W': 0}
for row in g:
for ch in row:
if ch != '.':
area[ch] += 1
seen = set()
for r in range(n):
for c in range(m):
if g[r][c] != '.' or (r, c) in seen:
continue
seen.add((r, c))
todo = [(r, c)]
cnt = 0
edge = set()
while todo:
i, j = todo.pop()
cnt += 1
for p, q in ((i, j + 1), (i, j - 1), (i + 1, j), (i - 1, j)):
if 0 <= p < n and 0 <= q < m:
if g[p][q] == '.':
if (p, q) not in seen:
seen.add((p, q))
todo.append((p, q))
else:
edge.add(g[p][q])
if len(edge) == 1:
area[edge.pop()] += cnt
for r, c in dd:
if board[r][c] != '.':
area[board[r][c]] -= 1
return [area['B'], area['W'], (area['B'] - area['W']) * 10 - komi]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[['.BW..', 'WBW..', 'WBW..', '.BW.B', 'WBW..', 'WBW.B'], [[2, 1]], 0], [7, 10, -30]], [[['.BW...', '.BW...', '.BW...', 'WBW...', 'WBW...'], [[4, 2]], 0], [5, 6, -10]], [[['...W.BW', '.....BW', 'W....BW', '.....BW', '..W..BW'], [[1, 6], [2, 6]], 0], [5, 6, -10]], [[['.BWB', '.BW.', '.BWB', '.BW.', '.BWB'], [], 0], [13, 5, 80]], [[['.W.BW..', '...BW..', '...BWB.', '...BW..'], [[1, 4], [3, 4]], 0], [5, 3, 20]], [[['.BWBB.', '.BW...', '.BW..B', '.BW...', '.BW...', '.BW..B', '.BW.B.'], [[3, 1]], 5], [12, 7, 45]], [[['..W..BW', '.....BW', '..W..BW', '.....BW', '.W...BW', '...W.BW'], [], 0], [6, 10, -40]], [[['.BW..', '.BW..', '.BWB.', '.BWB.', 'WBW..'], [[4, 2]], 75], [7, 5, -55]]], [[[['.BW....', '.BWB...', '.BW.B..', 'WBW.B..', '.BW.B..', '.BW....'], [[5, 2]], 0], [10, 6, 40]], [[['..BWB', '..BW.', '..BWB', 'W.BW.', '..BW.'], [[4, 2], [3, 3]], 75], [6, 5, -65]], [[['.BW.', '.BW.', '.BW.', '.BW.', 'WBW.', '.BW.', 'WBW.'], [[2, 2], [6, 2]], 75], [7, 7, -75]], [[['..BW', '..BW', 'W.BW', '..BW'], [[0, 2], [2, 3]], 75], [3, 4, -85]], [[['.W.BW.', '...BW.', '...BW.', '...BW.', '.W.BW.', '...BW.'], [[4, 3], [0, 4]], 0], [5, 7, -20]], [[['W..BW.', '...BW.', '...BWB', '...BW.'], [[3, 4], [0, 3]], 75], [4, 4, -75]], [[['.WBW...', '..BW...', '..BW...', 'W.BW...', '..BW...'], [[0, 3], [4, 2]], 75], [4, 6, -95]], [[['..BW', 'W.BW', '..BW', 'W.BW', '..BW'], [], 75], [5, 7, -95]]], [[[['...W.BW', '.....BW', 'W....BW', '.....BW', '..W..BW'], [[1, 6], [2, 6]], 0], [5, 6, -10]], [[['..BW...', '..BW...', '..BW...', '..BW...', '..BWB..', '.WBW...'], [[5, 3]], 5], [7, 6, 5]], [[['...BW', '.W.BW', 'W..BW', '..WBW'], [[3, 4], [0, 4]], 5], [4, 5, -15]], [[['..BW..B', '..BW...', '..BW...', '..BW...'], [], 75], [13, 4, 15]], [[['..BW', '..BW', '.WBW', '..BW', '..BW', '..BW'], [[1, 2]], 5], [5, 7, -25]], [[['W.BW.', '..BW.', 'W.BW.', '..BW.', '..BW.', '..BW.', '.WBW.'], [[6, 1]], 5], [7, 16, -95]], [[['..BW.', '..BW.', '..BW.', '..BW.', '..BW.', '..BW.'], [], 5], [18, 12, 55]], [[['..BW.', '.WBW.', '..BW.', '.WBW.'], [[2, 2], [3, 2]], 5], [2, 10, -85]]], [[[['.BW..', '.BW..', '.BWB.', '.BWB.', 'WBW..'], [[4, 2]], 75], [7, 5, -55]], [[['.WBWB', '..BW.', '..BW.', '..BW.', '..BW.'], [], 0], [6, 6, 0]], [[['...BW.B', '...BWBB', '...BWBB', '...BW..', '...BW..'], [[3, 3], [0, 4]], 5], [9, 4, 45]], [[['.W..BW.', '..W.BW.', '....BW.', '..W.BW.', '...WBW.', '....BW.', '...WBW.'], [[2, 4], [3, 5]], 75], [6, 11, -125]], [[['...BW', '..WBW', '...BW', '..WBW', '...BW'], [[2, 3]], 75], [4, 7, -105]], [[['.WBW', '..BW', '..BW', '..BW', '..BW', '..BW'], [[2, 2], [4, 2]], 5], [4, 7, -35]], [[['WBW..', '.BW..', '.BW..', '.BWBB'], [[1, 2]], 0], [6, 4, 20]], [[['...WBW.', '....BW.', '....BW.', 'W...BW.', '....BW.', '..W.BW.'], [[1, 4]], 5], [5, 15, -105]]], [[[['..BW', '..BW', 'W.BW', '..BW'], [[0, 2], [2, 3]], 75], [3, 4, -85]], [[['...WBW.', '....BW.', '....BW.', 'W...BW.', '....BW.', '..W.BW.'], [[1, 4]], 5], [5, 15, -105]], [[['...BW', 'W..BW', '..WBW', '...BW', '..WBW', '...BW'], [[5, 3]], 0], [5, 9, -40]], [[['..BW.', '..BW.', '..BW.', '..BW.', 'W.BW.', '..BW.', '..BW.'], [], 5], [7, 15, -85]], [[['.BWB', '.BW.', '.BW.', '.BW.'], [], 0], [9, 4, 50]], [[['....', '....', '....', '....'], [], 75], [0, 0, -75]], [[['...', '...', '...'], [], 5], [0, 0, -5]], [[['.B.', 'B.B', '.B.'], [[2, 1], [1, 2]], 0], [9, 0, 90]]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
check("area with dead 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 |
|---|---|---|---|
| area with dead case 0 | [6, 10, -40] | [7, 10, -30] | Failed |
| area with dead case 1 | [5, 5, 0] | [5, 6, -10] | Failed |
| area with dead case 2 | [5, 4, 10] | [5, 6, -10] | Failed |
| area with dead case 3 | [13, 5, 80] | [13, 5, 80] | Passed |
| area with dead case 4 | [5, 1, 40] | [5, 3, 20] | Failed |
| area with dead case 5 | [11, 7, 35] | [12, 7, 45] | Failed |
| area with dead case 6 | [6, 10, -40] | [6, 10, -40] | Passed |
| area with dead case 7 | [7, 4, -45] | [7, 5, -55] | Failed |
SHA-256 / 1869c234364d7135bf9296a7a65ec450d87e31bc1d4b82d29df2f1d0bff3eae2
HELD IN THE MEMBER ARCHIVE
The verified repair and its recorded checks are member-only.
This mechanism has 8 recorded checks per implementation. The open-access tier publishes the failure and the unsuccessful fix; the repaired source that passes every check, and the observations that prove it, are available to members.
Every case sharing this mechanism uses the same contract and the same repair, so this one record is held back for all of them.
Member access is invitation-based. Sign in with your invited account to inspect the repair.
Sign in to the archive ↗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:20.666935+00:00.
Case digest / 21a85f92675f99ac0e85fab488f5c4dfafc1a09d7be31f828bc784a8fab3e15c