FA-82901 / Go territory scoring / Open access
Opponent stones are treated as liberties · case 01
Surrounded chains are never captured and some suicides are accepted.
ROOT CAUSE
The liberty test accepts any point not of the chain colour instead of only empty points.
VERIFIED REPAIR
Only empty orthogonal neighbours are liberties.
Unsuccessful approach: Counting the just-played point as a liberty for every chain still prevents the capture it causes.
Case contract
Input [board, colour, row, col]. Occupied point -> ["illegal", "occupied"]. Otherwise place the stone, remove every adjacent opponent chain left without liberties, then reject the move as ["illegal", "suicide"] only if the placed chain still has no liberty. Return [new_board, captured_stone_count].
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, color, r, c = x
g = [list(row) for row in board]
n = len(g)
m = len(g[0])
if g[r][c] != '.':
return ['illegal', 'occupied']
opp = 'W' if color == 'B' else 'B'
g[r][c] = color
def group(i, j):
col = g[i][j]
stones = {(i, j)}
libs = set()
stack = [(i, j)]
while stack:
a, b = stack.pop()
for p, q in ((a, b + 1), (a + 1, b), (a, b - 1), (a - 1, b)):
if 0 <= p < n and 0 <= q < m:
if g[p][q] != col:
libs.add((p, q))
elif g[p][q] == col and (p, q) not in stones:
stones.add((p, q))
stack.append((p, q))
return stones, libs
captured = 0
for p, q in ((r + 1, c), (r - 1, c), (r, c + 1), (r, c - 1)):
if 0 <= p < n and 0 <= q < m and g[p][q] == opp:
stones, libs = group(p, q)
if not libs:
for s, t in stones:
g[s][t] = '.'
captured += len(stones)
stones, libs = group(r, c)
if not libs:
return ['illegal', 'suicide']
return [[''.join(row) for row in g], captured]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[['...', '...', '...'], 'W', 2, 0], [['...', '...', 'W..'], 0]], [[['.B.', 'B.B', '.B.'], 'W', 2, 2], ['illegal', 'suicide']], [[['.B.', 'B.B', '.B.'], 'W', 2, 0], ['illegal', 'suicide']], [[['.B.', 'B.B', '.B.'], 'B', 0, 0], [['BB.', 'B.B', '.B.'], 0]], [[['.B.', 'B.B', '.B.'], 'B', 0, 2], [['.BB', 'B.B', '.B.'], 0]], [[['.B.', 'B.B', '.B.'], 'B', 0, 1], ['illegal', 'occupied']], [[['B..W', 'B..W', 'B..W', 'B..W'], 'W', 2, 2], [['B..W', 'B..W', 'B.WW', 'B..W'], 0]], [[['WBW.', '..W.', 'WB.W', '..BW'], 'B', 1, 0], [['.BW.', 'B.W.', 'WB.W', '..BW'], 1]]], [[[['B..W', 'B..W', 'B..W', 'B..W'], 'B', 1, 1], [['B..W', 'BB.W', 'B..W', 'B..W'], 0]], [[['B..W', 'B..W', 'B..W', 'B..W'], 'W', 0, 2], [['B.WW', 'B..W', 'B..W', 'B..W'], 0]], [[['B..W', 'B..W', 'B..W', 'B..W'], 'B', 0, 1], [['BB.W', 'B..W', 'B..W', 'B..W'], 0]], [[['B..W', 'B..W', 'B..W', 'B..W'], 'B', 2, 0], ['illegal', 'occupied']], [[['.BW.', '.BW.', '.BW.', '.BW.'], 'W', 2, 3], [['.BW.', '.BW.', '.BWW', '.BW.'], 0]], [[['.BW.', '.BW.', '.BW.', '.BW.'], 'W', 0, 0], [['WBW.', '.BW.', '.BW.', '.BW.'], 0]], [[['B.B.W', '.B.W.', 'B.BW.', 'BBW.W', '..W..'], 'W', 0, 1], ['illegal', 'suicide']], [[['.WB.', 'B.WB', 'W.BW'], 'B', 1, 1], [['.WB.', 'BB.B', 'W.BW'], 1]]], [[[['.BW.', '.BW.', '.BW.', '.BW.'], 'B', 2, 0], [['.BW.', '.BW.', 'BBW.', '.BW.'], 0]], [[['.BW.', '.BW.', '.BW.', '.BW.'], 'B', 0, 2], ['illegal', 'occupied']], [[['..B..', '..B..', 'BBBBB', 'WWWWW', '..W..'], 'B', 0, 0], [['B.B..', '..B..', 'BBBBB', 'WWWWW', '..W..'], 0]], [[['..B..', '..B..', 'BBBBB', 'WWWWW', '..W..'], 'B', 1, 1], [['..B..', '.BB..', 'BBBBB', 'WWWWW', '..W..'], 0]], [[['..B..', '..B..', 'BBBBB', 'WWWWW', '..W..'], 'B', 4, 0], [['..B..', '..B..', 'BBBBB', 'WWWWW', 'B.W..'], 0]], [[['..B..', '..B..', 'BBBBB', 'WWWWW', '..W..'], 'B', 0, 1], [['.BB..', '..B..', 'BBBBB', 'WWWWW', '..W..'], 0]], [[['...', '.BW', '..B', '.BW', 'BB.'], 'W', 4, 2], ['illegal', 'suicide']], [[['B.BW', 'WWBB', 'BB.W', '.BBB'], 'W', 0, 1], [['.WBW', 'WWBB', 'BB.W', '.BBB'], 1]]], [[[['B.B.W', '.B.W.', 'B.BW.', 'BBW.W', '..W..'], 'W', 2, 1], ['illegal', 'suicide']], [[['B.B.W', '.B.W.', 'B.BW.', 'BBW.W', '..W..'], 'W', 0, 1], ['illegal', 'suicide']], [[['B.B.W', '.B.W.', 'B.BW.', 'BBW.W', '..W..'], 'B', 4, 3], [['B.B.W', '.B.W.', 'B.BW.', 'BBW.W', '..WB.'], 0]], [[['B.B.W', '.B.W.', 'B.BW.', 'BBW.W', '..W..'], 'B', 2, 4], [['B.B.W', '.B.W.', 'B.BWB', 'BBW.W', '..W..'], 0]], [[['B.B.W', '.B.W.', 'B.BW.', 'BBW.W', '..W..'], 'B', 3, 2], ['illegal', 'occupied']], [[['W....', '.....', '.....', '.....', '....B'], 'W', 4, 1], [['W....', '.....', '.....', '.....', '.W..B'], 0]], [[['WB.BB', 'B.B.W', 'B.WBB', 'BWBW.'], 'W', 1, 3], ['illegal', 'suicide']], [[['.BW', 'BW.', 'W..'], 'B', 2, 1], [['.BW', 'BW.', '.B.'], 1]]], [[[['W....', '.....', '.....', '.....', '....B'], 'W', 3, 0], [['W....', '.....', '.....', 'W....', '....B'], 0]], [[['W....', '.....', '.....', '.....', '....B'], 'W', 4, 0], [['W....', '.....', '.....', '.....', 'W...B'], 0]], [[['W....', '.....', '.....', '.....', '....B'], 'B', 4, 4], ['illegal', 'occupied']], [[['.W.B.', 'W.WB.', '.WB..', 'WB...', 'B....'], 'W', 0, 2], [['.WWB.', 'W.WB.', '.WB..', 'WB...', 'B....'], 0]], [[['.W.B.', 'W.WB.', '.WB..', 'WB...', 'B....'], 'W', 0, 0], [['WW.B.', 'W.WB.', '.WB..', 'WB...', 'B....'], 0]], [[['.W.B.', 'W.WB.', '.WB..', 'WB...', 'B....'], 'B', 2, 4], [['.W.B.', 'W.WB.', '.WB.B', 'WB...', 'B....'], 0]], [[['.B...', 'WWWBW', 'WW..B', '.W.WW', '..B..'], 'W', 2, 3], [['.B...', 'WWWBW', 'WW.W.', '.W.WW', '..B..'], 1]], [[['.W.', 'WBW', 'BWB'], 'B', 0, 2], [['.WB', 'WB.', 'BWB'], 1]]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
check("move result 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 |
|---|---|---|---|
| move result case 0 | [['...', '...', 'W..'], 0] | [['...', '...', 'W..'], 0] | Passed |
| move result case 1 | [['.B.', 'B.B', '.BW'], 0] | ['illegal', 'suicide'] | Failed |
| move result case 2 | [['.B.', 'B.B', 'WB.'], 0] | ['illegal', 'suicide'] | Failed |
| move result case 3 | [['BB.', 'B.B', '.B.'], 0] | [['BB.', 'B.B', '.B.'], 0] | Passed |
| move result case 4 | [['.BB', 'B.B', '.B.'], 0] | [['.BB', 'B.B', '.B.'], 0] | Passed |
| move result case 5 | ['illegal', 'occupied'] | ['illegal', 'occupied'] | Passed |
| move result case 6 | [['B..W', 'B..W', 'B.WW', 'B..W'], 0] | [['B..W', 'B..W', 'B.WW', 'B..W'], 0] | Passed |
| move result case 7 | [['WBW.', 'B.W.', 'WB.W', '..BW'], 0] | [['.BW.', 'B.W.', 'WB.W', '..BW'], 1] | Failed |
SHA-256 / 3d05ababccb3aacb017041852cc5f5d180b713df6be4ce8b97d967bb083a457e
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
board, color, r, c = x
g = [list(row) for row in board]
n = len(g)
m = len(g[0])
if g[r][c] != '.':
return ['illegal', 'occupied']
opp = 'W' if color == 'B' else 'B'
g[r][c] = color
def group(i, j):
col = g[i][j]
stones = {(i, j)}
libs = set()
stack = [(i, j)]
while stack:
a, b = stack.pop()
for p, q in ((a, b + 1), (a + 1, b), (a, b - 1), (a - 1, b)):
if 0 <= p < n and 0 <= q < m:
if g[p][q] == '.' or (p, q) == (r, c):
libs.add((p, q))
elif g[p][q] == col and (p, q) not in stones:
stones.add((p, q))
stack.append((p, q))
return stones, libs
captured = 0
for p, q in ((r + 1, c), (r - 1, c), (r, c + 1), (r, c - 1)):
if 0 <= p < n and 0 <= q < m and g[p][q] == opp:
stones, libs = group(p, q)
if not libs:
for s, t in stones:
g[s][t] = '.'
captured += len(stones)
stones, libs = group(r, c)
if not libs:
return ['illegal', 'suicide']
return [[''.join(row) for row in g], captured]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[['...', '...', '...'], 'W', 2, 0], [['...', '...', 'W..'], 0]], [[['.B.', 'B.B', '.B.'], 'W', 2, 2], ['illegal', 'suicide']], [[['.B.', 'B.B', '.B.'], 'W', 2, 0], ['illegal', 'suicide']], [[['.B.', 'B.B', '.B.'], 'B', 0, 0], [['BB.', 'B.B', '.B.'], 0]], [[['.B.', 'B.B', '.B.'], 'B', 0, 2], [['.BB', 'B.B', '.B.'], 0]], [[['.B.', 'B.B', '.B.'], 'B', 0, 1], ['illegal', 'occupied']], [[['B..W', 'B..W', 'B..W', 'B..W'], 'W', 2, 2], [['B..W', 'B..W', 'B.WW', 'B..W'], 0]], [[['WBW.', '..W.', 'WB.W', '..BW'], 'B', 1, 0], [['.BW.', 'B.W.', 'WB.W', '..BW'], 1]]], [[[['B..W', 'B..W', 'B..W', 'B..W'], 'B', 1, 1], [['B..W', 'BB.W', 'B..W', 'B..W'], 0]], [[['B..W', 'B..W', 'B..W', 'B..W'], 'W', 0, 2], [['B.WW', 'B..W', 'B..W', 'B..W'], 0]], [[['B..W', 'B..W', 'B..W', 'B..W'], 'B', 0, 1], [['BB.W', 'B..W', 'B..W', 'B..W'], 0]], [[['B..W', 'B..W', 'B..W', 'B..W'], 'B', 2, 0], ['illegal', 'occupied']], [[['.BW.', '.BW.', '.BW.', '.BW.'], 'W', 2, 3], [['.BW.', '.BW.', '.BWW', '.BW.'], 0]], [[['.BW.', '.BW.', '.BW.', '.BW.'], 'W', 0, 0], [['WBW.', '.BW.', '.BW.', '.BW.'], 0]], [[['B.B.W', '.B.W.', 'B.BW.', 'BBW.W', '..W..'], 'W', 0, 1], ['illegal', 'suicide']], [[['.WB.', 'B.WB', 'W.BW'], 'B', 1, 1], [['.WB.', 'BB.B', 'W.BW'], 1]]], [[[['.BW.', '.BW.', '.BW.', '.BW.'], 'B', 2, 0], [['.BW.', '.BW.', 'BBW.', '.BW.'], 0]], [[['.BW.', '.BW.', '.BW.', '.BW.'], 'B', 0, 2], ['illegal', 'occupied']], [[['..B..', '..B..', 'BBBBB', 'WWWWW', '..W..'], 'B', 0, 0], [['B.B..', '..B..', 'BBBBB', 'WWWWW', '..W..'], 0]], [[['..B..', '..B..', 'BBBBB', 'WWWWW', '..W..'], 'B', 1, 1], [['..B..', '.BB..', 'BBBBB', 'WWWWW', '..W..'], 0]], [[['..B..', '..B..', 'BBBBB', 'WWWWW', '..W..'], 'B', 4, 0], [['..B..', '..B..', 'BBBBB', 'WWWWW', 'B.W..'], 0]], [[['..B..', '..B..', 'BBBBB', 'WWWWW', '..W..'], 'B', 0, 1], [['.BB..', '..B..', 'BBBBB', 'WWWWW', '..W..'], 0]], [[['...', '.BW', '..B', '.BW', 'BB.'], 'W', 4, 2], ['illegal', 'suicide']], [[['B.BW', 'WWBB', 'BB.W', '.BBB'], 'W', 0, 1], [['.WBW', 'WWBB', 'BB.W', '.BBB'], 1]]], [[[['B.B.W', '.B.W.', 'B.BW.', 'BBW.W', '..W..'], 'W', 2, 1], ['illegal', 'suicide']], [[['B.B.W', '.B.W.', 'B.BW.', 'BBW.W', '..W..'], 'W', 0, 1], ['illegal', 'suicide']], [[['B.B.W', '.B.W.', 'B.BW.', 'BBW.W', '..W..'], 'B', 4, 3], [['B.B.W', '.B.W.', 'B.BW.', 'BBW.W', '..WB.'], 0]], [[['B.B.W', '.B.W.', 'B.BW.', 'BBW.W', '..W..'], 'B', 2, 4], [['B.B.W', '.B.W.', 'B.BWB', 'BBW.W', '..W..'], 0]], [[['B.B.W', '.B.W.', 'B.BW.', 'BBW.W', '..W..'], 'B', 3, 2], ['illegal', 'occupied']], [[['W....', '.....', '.....', '.....', '....B'], 'W', 4, 1], [['W....', '.....', '.....', '.....', '.W..B'], 0]], [[['WB.BB', 'B.B.W', 'B.WBB', 'BWBW.'], 'W', 1, 3], ['illegal', 'suicide']], [[['.BW', 'BW.', 'W..'], 'B', 2, 1], [['.BW', 'BW.', '.B.'], 1]]], [[[['W....', '.....', '.....', '.....', '....B'], 'W', 3, 0], [['W....', '.....', '.....', 'W....', '....B'], 0]], [[['W....', '.....', '.....', '.....', '....B'], 'W', 4, 0], [['W....', '.....', '.....', '.....', 'W...B'], 0]], [[['W....', '.....', '.....', '.....', '....B'], 'B', 4, 4], ['illegal', 'occupied']], [[['.W.B.', 'W.WB.', '.WB..', 'WB...', 'B....'], 'W', 0, 2], [['.WWB.', 'W.WB.', '.WB..', 'WB...', 'B....'], 0]], [[['.W.B.', 'W.WB.', '.WB..', 'WB...', 'B....'], 'W', 0, 0], [['WW.B.', 'W.WB.', '.WB..', 'WB...', 'B....'], 0]], [[['.W.B.', 'W.WB.', '.WB..', 'WB...', 'B....'], 'B', 2, 4], [['.W.B.', 'W.WB.', '.WB.B', 'WB...', 'B....'], 0]], [[['.B...', 'WWWBW', 'WW..B', '.W.WW', '..B..'], 'W', 2, 3], [['.B...', 'WWWBW', 'WW.W.', '.W.WW', '..B..'], 1]], [[['.W.', 'WBW', 'BWB'], 'B', 0, 2], [['.WB', 'WB.', 'BWB'], 1]]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
check("move result 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 |
|---|---|---|---|
| move result case 0 | [['...', '...', 'W..'], 0] | [['...', '...', 'W..'], 0] | Passed |
| move result case 1 | ['illegal', 'suicide'] | ['illegal', 'suicide'] | Passed |
| move result case 2 | ['illegal', 'suicide'] | ['illegal', 'suicide'] | Passed |
| move result case 3 | [['BB.', 'B.B', '.B.'], 0] | [['BB.', 'B.B', '.B.'], 0] | Passed |
| move result case 4 | [['.BB', 'B.B', '.B.'], 0] | [['.BB', 'B.B', '.B.'], 0] | Passed |
| move result case 5 | ['illegal', 'occupied'] | ['illegal', 'occupied'] | Passed |
| move result case 6 | [['B..W', 'B..W', 'B.WW', 'B..W'], 0] | [['B..W', 'B..W', 'B.WW', 'B..W'], 0] | Passed |
| move result case 7 | [['WBW.', 'B.W.', 'WB.W', '..BW'], 0] | [['.BW.', 'B.W.', 'WB.W', '..BW'], 1] | Failed |
SHA-256 / ae64f2869e212afd7716a7051e8db4ebec2501df93749a77420b1309077ea30d
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
board, color, r, c = x
g = [list(row) for row in board]
n = len(g)
m = len(g[0])
if g[r][c] != '.':
return ['illegal', 'occupied']
opp = 'W' if color == 'B' else 'B'
g[r][c] = color
def group(i, j):
col = g[i][j]
stones = {(i, j)}
libs = set()
stack = [(i, j)]
while stack:
a, b = stack.pop()
for p, q in ((a, b + 1), (a + 1, b), (a, b - 1), (a - 1, b)):
if 0 <= p < n and 0 <= q < m:
if g[p][q] == '.':
libs.add((p, q))
elif g[p][q] == col and (p, q) not in stones:
stones.add((p, q))
stack.append((p, q))
return stones, libs
captured = 0
for p, q in ((r + 1, c), (r - 1, c), (r, c + 1), (r, c - 1)):
if 0 <= p < n and 0 <= q < m and g[p][q] == opp:
stones, libs = group(p, q)
if not libs:
for s, t in stones:
g[s][t] = '.'
captured += len(stones)
stones, libs = group(r, c)
if not libs:
return ['illegal', 'suicide']
return [[''.join(row) for row in g], captured]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[['...', '...', '...'], 'W', 2, 0], [['...', '...', 'W..'], 0]], [[['.B.', 'B.B', '.B.'], 'W', 2, 2], ['illegal', 'suicide']], [[['.B.', 'B.B', '.B.'], 'W', 2, 0], ['illegal', 'suicide']], [[['.B.', 'B.B', '.B.'], 'B', 0, 0], [['BB.', 'B.B', '.B.'], 0]], [[['.B.', 'B.B', '.B.'], 'B', 0, 2], [['.BB', 'B.B', '.B.'], 0]], [[['.B.', 'B.B', '.B.'], 'B', 0, 1], ['illegal', 'occupied']], [[['B..W', 'B..W', 'B..W', 'B..W'], 'W', 2, 2], [['B..W', 'B..W', 'B.WW', 'B..W'], 0]], [[['WBW.', '..W.', 'WB.W', '..BW'], 'B', 1, 0], [['.BW.', 'B.W.', 'WB.W', '..BW'], 1]]], [[[['B..W', 'B..W', 'B..W', 'B..W'], 'B', 1, 1], [['B..W', 'BB.W', 'B..W', 'B..W'], 0]], [[['B..W', 'B..W', 'B..W', 'B..W'], 'W', 0, 2], [['B.WW', 'B..W', 'B..W', 'B..W'], 0]], [[['B..W', 'B..W', 'B..W', 'B..W'], 'B', 0, 1], [['BB.W', 'B..W', 'B..W', 'B..W'], 0]], [[['B..W', 'B..W', 'B..W', 'B..W'], 'B', 2, 0], ['illegal', 'occupied']], [[['.BW.', '.BW.', '.BW.', '.BW.'], 'W', 2, 3], [['.BW.', '.BW.', '.BWW', '.BW.'], 0]], [[['.BW.', '.BW.', '.BW.', '.BW.'], 'W', 0, 0], [['WBW.', '.BW.', '.BW.', '.BW.'], 0]], [[['B.B.W', '.B.W.', 'B.BW.', 'BBW.W', '..W..'], 'W', 0, 1], ['illegal', 'suicide']], [[['.WB.', 'B.WB', 'W.BW'], 'B', 1, 1], [['.WB.', 'BB.B', 'W.BW'], 1]]], [[[['.BW.', '.BW.', '.BW.', '.BW.'], 'B', 2, 0], [['.BW.', '.BW.', 'BBW.', '.BW.'], 0]], [[['.BW.', '.BW.', '.BW.', '.BW.'], 'B', 0, 2], ['illegal', 'occupied']], [[['..B..', '..B..', 'BBBBB', 'WWWWW', '..W..'], 'B', 0, 0], [['B.B..', '..B..', 'BBBBB', 'WWWWW', '..W..'], 0]], [[['..B..', '..B..', 'BBBBB', 'WWWWW', '..W..'], 'B', 1, 1], [['..B..', '.BB..', 'BBBBB', 'WWWWW', '..W..'], 0]], [[['..B..', '..B..', 'BBBBB', 'WWWWW', '..W..'], 'B', 4, 0], [['..B..', '..B..', 'BBBBB', 'WWWWW', 'B.W..'], 0]], [[['..B..', '..B..', 'BBBBB', 'WWWWW', '..W..'], 'B', 0, 1], [['.BB..', '..B..', 'BBBBB', 'WWWWW', '..W..'], 0]], [[['...', '.BW', '..B', '.BW', 'BB.'], 'W', 4, 2], ['illegal', 'suicide']], [[['B.BW', 'WWBB', 'BB.W', '.BBB'], 'W', 0, 1], [['.WBW', 'WWBB', 'BB.W', '.BBB'], 1]]], [[[['B.B.W', '.B.W.', 'B.BW.', 'BBW.W', '..W..'], 'W', 2, 1], ['illegal', 'suicide']], [[['B.B.W', '.B.W.', 'B.BW.', 'BBW.W', '..W..'], 'W', 0, 1], ['illegal', 'suicide']], [[['B.B.W', '.B.W.', 'B.BW.', 'BBW.W', '..W..'], 'B', 4, 3], [['B.B.W', '.B.W.', 'B.BW.', 'BBW.W', '..WB.'], 0]], [[['B.B.W', '.B.W.', 'B.BW.', 'BBW.W', '..W..'], 'B', 2, 4], [['B.B.W', '.B.W.', 'B.BWB', 'BBW.W', '..W..'], 0]], [[['B.B.W', '.B.W.', 'B.BW.', 'BBW.W', '..W..'], 'B', 3, 2], ['illegal', 'occupied']], [[['W....', '.....', '.....', '.....', '....B'], 'W', 4, 1], [['W....', '.....', '.....', '.....', '.W..B'], 0]], [[['WB.BB', 'B.B.W', 'B.WBB', 'BWBW.'], 'W', 1, 3], ['illegal', 'suicide']], [[['.BW', 'BW.', 'W..'], 'B', 2, 1], [['.BW', 'BW.', '.B.'], 1]]], [[[['W....', '.....', '.....', '.....', '....B'], 'W', 3, 0], [['W....', '.....', '.....', 'W....', '....B'], 0]], [[['W....', '.....', '.....', '.....', '....B'], 'W', 4, 0], [['W....', '.....', '.....', '.....', 'W...B'], 0]], [[['W....', '.....', '.....', '.....', '....B'], 'B', 4, 4], ['illegal', 'occupied']], [[['.W.B.', 'W.WB.', '.WB..', 'WB...', 'B....'], 'W', 0, 2], [['.WWB.', 'W.WB.', '.WB..', 'WB...', 'B....'], 0]], [[['.W.B.', 'W.WB.', '.WB..', 'WB...', 'B....'], 'W', 0, 0], [['WW.B.', 'W.WB.', '.WB..', 'WB...', 'B....'], 0]], [[['.W.B.', 'W.WB.', '.WB..', 'WB...', 'B....'], 'B', 2, 4], [['.W.B.', 'W.WB.', '.WB.B', 'WB...', 'B....'], 0]], [[['.B...', 'WWWBW', 'WW..B', '.W.WW', '..B..'], 'W', 2, 3], [['.B...', 'WWWBW', 'WW.W.', '.W.WW', '..B..'], 1]], [[['.W.', 'WBW', 'BWB'], 'B', 0, 2], [['.WB', 'WB.', 'BWB'], 1]]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
check("move result 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 |
|---|---|---|---|
| move result case 0 | [['...', '...', 'W..'], 0] | [['...', '...', 'W..'], 0] | Passed |
| move result case 1 | ['illegal', 'suicide'] | ['illegal', 'suicide'] | Passed |
| move result case 2 | ['illegal', 'suicide'] | ['illegal', 'suicide'] | Passed |
| move result case 3 | [['BB.', 'B.B', '.B.'], 0] | [['BB.', 'B.B', '.B.'], 0] | Passed |
| move result case 4 | [['.BB', 'B.B', '.B.'], 0] | [['.BB', 'B.B', '.B.'], 0] | Passed |
| move result case 5 | ['illegal', 'occupied'] | ['illegal', 'occupied'] | Passed |
| move result case 6 | [['B..W', 'B..W', 'B.WW', 'B..W'], 0] | [['B..W', 'B..W', 'B.WW', 'B..W'], 0] | Passed |
| move result case 7 | [['.BW.', 'B.W.', 'WB.W', '..BW'], 1] | [['.BW.', 'B.W.', 'WB.W', '..BW'], 1] | Passed |
SHA-256 / 98a5cdeb3098873642d054c2f94ff7daa42dc3efb4bbc050ebfb9a3d71acf11b
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.575539+00:00.
Case digest / 92b42e039758d7c39c537993b07e7ac9f1ddf82a3ab366b9114b354606f6f5c5