FAILURE MAP
← Case archive

FA-83196 / Go territory scoring / Open access

Dead stones are rendered as unknown points that neutralise territory · case 01

A dead invader turns the surrounding territory into dame.

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

ROOT CAUSE

Dead points are replaced with "?" rather than removed.

VERIFIED REPAIR

Replace dead stones with empty points before region analysis.

Unsuccessful approach: Removing them for analysis but rendering from the original board shows dead stones as alive.

Case contract

Input [board, dead_points]. Remove dead stones, then render each point: live stones as B/W, territory (region bordered by one colour) as lower-case b/w, other empty points as "?". Return rows.

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 = x
    n = len(board)
    m = len(board[0])
    dd = {tuple(p) for p in dead}
    g = [[('?' if (r, c) in dd else board[r][c]) for c in range(m)] for r in range(n)]
    out = [[g[r][c] for c in range(m)] for r in range(n)]
    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))
            region = [(r, c)]
            k = 0
            cols = set()
            while k < len(region):
                i, j = region[k]
                k += 1
                for p, q in ((i - 1, j), (i, j - 1), (i + 1, j), (i, j + 1)):
                    if 0 <= p < n and 0 <= q < m:
                        if g[p][q] == '.':
                            if (p, q) not in seen:
                                seen.add((p, q))
                                region.append((p, q))
                        else:
                            cols.add(g[p][q])
            mark = cols.pop().lower() if len(cols) == 1 else '?'
            for i, j in region:
                out[i][j] = mark
    return [''.join(row) for row in out]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[['.BW.', '.BW.', '.BW.', '.BWB', '.BW.', '.BWB'], [[1, 1]]], ['?BW?', '??W?', '?BW?', '?BWB', '?BW?', '?BWB']], [[['...WBW.', '....BW.', '....BW.', '.W..BW.'], []], ['???WBWw', '????BWw', '????BWw', '?W??BWw']], [[['.BWB.', '.BW..', '.BW..', '.BWB.'], [[2, 2], [0, 2]]], ['bB?B?', 'bBW??', 'bB???', 'bBWB?']], [[['WBW...', '.BW...', '.BW..B', '.BW...', '.BW...'], [[0, 2]]], ['WB????', '?BW???', '?BW??B', '?BW???', '?BW???']], [[['.BW.B..', 'WBW....', '.BW....', '.BW....', '.BW....'], [[2, 2]]], ['?BW?B??', 'WBW????', '?B?????', '?BW????', '?BW????']], [[['....BW', '....BW', '....BW', '....BW', '....BW', '....BW'], [[2, 5], [2, 4]]], ['????BW', '????BW', '??????', '????BW', '????BW', '????BW']], [[['..BW', '..BW', '..BW', '..BW', '..BW', '..BW', '..BW'], [[3, 2]]], ['??BW', '??BW', '??BW', '???W', '??BW', '??BW', '??BW']], [[['.B.', 'B.B', '.B.'], [[1, 2], [2, 1]]], ['bBb', 'Bbb', 'bbb']]], [[[['W.BW.', '..BW.', '.WBW.', '.WBW.', '..BW.', '..BW.', '..BW.'], []], ['W?BWw', '??BWw', '?WBWw', '?WBWw', '??BWw', '??BWw', '??BWw']], [[['.W.W.BW', '.....BW', '.W...BW', '...W.BW', '.....BW'], [[2, 1]]], ['?W?W?BW', '?????BW', '?????BW', '???W?BW', '?????BW']], [[['.BWB', '.BW.', 'WBW.', '.BW.', '.BW.', 'WBW.'], [[4, 1]]], ['?BWB', '?BW?', 'WBW?', '?BW?', '??W?', 'WBW?']], [[['.BW.', '.BW.', 'WBW.', '.BW.', '.BW.'], [[0, 1], [3, 1]]], ['??Ww', '?BWw', 'WBWw', '??Ww', '?BWw']], [[['.W..BW', '....BW', 'W...BW', '....BW'], [[1, 4]]], ['?W??BW', '?????W', 'W???BW', '????BW']], [[['..BW', '..BW', 'W.BW', '..BW', '..BW'], [[4, 2], [3, 2]]], ['??BW', '??BW', 'W?BW', '???W', '???W']], [[['.BW...', '.BW...', '.BW...', 'WBW..B', '.BW..B', '.BW..B'], []], ['?BW???', '?BW???', '?BW???', 'WBW??B', '?BW??B', '?BW??B']], [[['BBBB', 'B..B', 'B..B', 'BBBB'], [[0, 2]]], ['BBbB', 'BbbB', 'BbbB', 'BBBB']]], [[[['.BW..', 'WBW..', 'WBWB.', '.BW..', '.BW..'], []], ['?BW??', 'WBW??', 'WBWB?', '?BW??', '?BW??']], [[['...BW', '...BW', '...BW', '...BW', 'W..BW', '.W.BW', '...BW'], [[2, 4], [3, 3]]], ['???BW', '???BW', '???B?', '????W', 'W??BW', '?W?BW', '???BW']], [[['...BW', '..WBW', '...BW', '...BW', '...BW'], []], ['???BW', '??WBW', '???BW', '???BW', '???BW']], [[['...BW', '...BW', '...BW', 'W..BW'], []], ['???BW', '???BW', '???BW', 'W??BW']], [[['..BW.', '..BW.', '..BWB', '..BW.', '..BW.', '..BW.', '..BW.'], [[2, 2], [3, 3]]], ['??BW?', '??BW?', '???WB', '??B??', '??BW?', '??BW?', '??BW?']], [[['.BW..', '.BW.B', '.BWB.', '.BW..', '.BW.B', '.BW..', 'WBW..'], [[4, 1]]], ['?BW??', '?BW?B', '?BWB?', '?BW??', '??W?B', '?BW??', 'WBW??']], [[['..BW', 'W.BW', '..BW', '..BW', '..BW', 'W.BW'], [[0, 2], [5, 3]]], ['???W', 'W?BW', '??BW', '??BW', '??BW', 'W?B?']], [[['..W', '.W.', 'W..'], [[0, 2], [2, 0]]], ['www', 'wWw', 'www']]], [[[['...BW.', '...BW.', '...BW.', '...BW.', '...BW.', '...BW.'], [[2, 4]]], ['bbbBW?', 'bbbBW?', 'bbbB??', 'bbbBW?', 'bbbBW?', 'bbbBW?']], [[['...BW', '...BW', 'W..BW', 'W.WBW', '...BW', '...BW'], []], ['???BW', '???BW', 'W??BW', 'W?WBW', '???BW', '???BW']], [[['....', '....', '....', '....'], []], ['????', '????', '????', '????']], [[['...', '...', '...'], []], ['???', '???', '???']], [[['.B.', 'B.B', '.B.'], [[1, 2], [2, 1]]], ['bBb', 'Bbb', 'bbb']], [[['B..W', 'B..W', 'B..W', 'B..W'], [[2, 3]]], ['B??W', 'B??W', 'B???', 'B??W']], [[['.BW.', '.BW.', '.BW.', '.BW.'], [[0, 2]]], ['bB??', 'bBW?', 'bBW?', 'bBW?']], [[['..B.', '....', '....', '....', 'B...'], [[0, 2]]], ['bbbb', 'bbbb', 'bbbb', 'bbbb', 'Bbbb']]], [[[['.B.', 'B.B', '.B.'], [[1, 2], [2, 1]]], ['bBb', 'Bbb', 'bbb']], [[['B.B.W', '.B.W.', 'B.BW.', 'BBW.W', '..W..'], []], ['BbB?W', 'bB?Ww', 'BbBWw', 'BBWwW', '??Www']], [[['W....', '.....', '.....', '.....', '....B'], [[4, 4]]], ['Wwwww', 'wwwww', 'wwwww', 'wwwww', 'wwwww']], [[['.W.B.', 'W.WB.', '.WB..', 'WB...', 'B....'], [[3, 1], [3, 0]]], ['wW?B?', 'WwWB?', '?WB??', '?????', 'B????']], [[['BBBB', 'B..B', 'B..B', 'BBBB'], [[0, 2]]], ['BBbB', 'BbbB', 'BbbB', 'BBBB']], [[['WWW', 'W.W', 'WWW'], []], ['WWW', 'WwW', 'WWW']], [[['B.W', '...', 'W.B'], [[2, 2], [0, 0]]], ['wwW', 'www', 'Www']], [[['.B...', 'B....', '.....', '....W', '...W.'], [[1, 0]]], ['?B???', '?????', '?????', '????W', '???Ww']]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("ownership map 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
ownership map case 0['?BW?', '??W?', '?BW?', '?BWB', '?BW?', '?BWB']['?BW?', '??W?', '?BW?', '?BWB', '?BW?', '?BWB']Passed
ownership map case 1['???WBWw', '????BWw', '????BWw', '?W??BWw']['???WBWw', '????BWw', '????BWw', '?W??BWw']Passed
ownership map case 2['bB?B?', 'bBW??', 'bB???', 'bBWB?']['bB?B?', 'bBW??', 'bB???', 'bBWB?']Passed
ownership map case 3['WB????', '?BW???', '?BW??B', '?BW???', '?BW???']['WB????', '?BW???', '?BW??B', '?BW???', '?BW???']Passed
ownership map case 4['?BW?B??', 'WBW????', '?B?????', '?BW????', '?BW????']['?BW?B??', 'WBW????', '?B?????', '?BW????', '?BW????']Passed
ownership map case 5['????BW', '????BW', '??????', '????BW', '????BW', '????BW']['????BW', '????BW', '??????', '????BW', '????BW', '????BW']Passed
ownership map case 6['??BW', '??BW', '??BW', '???W', '??BW', '??BW', '??BW']['??BW', '??BW', '??BW', '???W', '??BW', '??BW', '??BW']Passed
ownership map case 7['bB?', 'B??', '???']['bBb', 'Bbb', 'bbb']Failed

SHA-256 / e560fe25eb772b170ea3b769b85c2797dc353d170e6fd35f678454b6f6caa751

2 / The unsuccessful fix

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

N = 1
observations = []
def solve(x):
    board, dead = x
    n = len(board)
    m = len(board[0])
    dd = {tuple(p) for p in dead}
    g = [[('.' if (r, c) in dd else board[r][c]) for c in range(m)] for r in range(n)]
    out = [[board[r][c] for c in range(m)] for r in range(n)]
    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))
            region = [(r, c)]
            k = 0
            cols = set()
            while k < len(region):
                i, j = region[k]
                k += 1
                for p, q in ((i - 1, j), (i, j - 1), (i + 1, j), (i, j + 1)):
                    if 0 <= p < n and 0 <= q < m:
                        if g[p][q] == '.':
                            if (p, q) not in seen:
                                seen.add((p, q))
                                region.append((p, q))
                        else:
                            cols.add(g[p][q])
            mark = cols.pop().lower() if len(cols) == 1 else '?'
            for i, j in region:
                if board[i][j] == '.':
                    out[i][j] = mark
    return [''.join(row) for row in out]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[['.BW.', '.BW.', '.BW.', '.BWB', '.BW.', '.BWB'], [[1, 1]]], ['?BW?', '??W?', '?BW?', '?BWB', '?BW?', '?BWB']], [[['...WBW.', '....BW.', '....BW.', '.W..BW.'], []], ['???WBWw', '????BWw', '????BWw', '?W??BWw']], [[['.BWB.', '.BW..', '.BW..', '.BWB.'], [[2, 2], [0, 2]]], ['bB?B?', 'bBW??', 'bB???', 'bBWB?']], [[['WBW...', '.BW...', '.BW..B', '.BW...', '.BW...'], [[0, 2]]], ['WB????', '?BW???', '?BW??B', '?BW???', '?BW???']], [[['.BW.B..', 'WBW....', '.BW....', '.BW....', '.BW....'], [[2, 2]]], ['?BW?B??', 'WBW????', '?B?????', '?BW????', '?BW????']], [[['....BW', '....BW', '....BW', '....BW', '....BW', '....BW'], [[2, 5], [2, 4]]], ['????BW', '????BW', '??????', '????BW', '????BW', '????BW']], [[['..BW', '..BW', '..BW', '..BW', '..BW', '..BW', '..BW'], [[3, 2]]], ['??BW', '??BW', '??BW', '???W', '??BW', '??BW', '??BW']], [[['.B.', 'B.B', '.B.'], [[1, 2], [2, 1]]], ['bBb', 'Bbb', 'bbb']]], [[[['W.BW.', '..BW.', '.WBW.', '.WBW.', '..BW.', '..BW.', '..BW.'], []], ['W?BWw', '??BWw', '?WBWw', '?WBWw', '??BWw', '??BWw', '??BWw']], [[['.W.W.BW', '.....BW', '.W...BW', '...W.BW', '.....BW'], [[2, 1]]], ['?W?W?BW', '?????BW', '?????BW', '???W?BW', '?????BW']], [[['.BWB', '.BW.', 'WBW.', '.BW.', '.BW.', 'WBW.'], [[4, 1]]], ['?BWB', '?BW?', 'WBW?', '?BW?', '??W?', 'WBW?']], [[['.BW.', '.BW.', 'WBW.', '.BW.', '.BW.'], [[0, 1], [3, 1]]], ['??Ww', '?BWw', 'WBWw', '??Ww', '?BWw']], [[['.W..BW', '....BW', 'W...BW', '....BW'], [[1, 4]]], ['?W??BW', '?????W', 'W???BW', '????BW']], [[['..BW', '..BW', 'W.BW', '..BW', '..BW'], [[4, 2], [3, 2]]], ['??BW', '??BW', 'W?BW', '???W', '???W']], [[['.BW...', '.BW...', '.BW...', 'WBW..B', '.BW..B', '.BW..B'], []], ['?BW???', '?BW???', '?BW???', 'WBW??B', '?BW??B', '?BW??B']], [[['BBBB', 'B..B', 'B..B', 'BBBB'], [[0, 2]]], ['BBbB', 'BbbB', 'BbbB', 'BBBB']]], [[[['.BW..', 'WBW..', 'WBWB.', '.BW..', '.BW..'], []], ['?BW??', 'WBW??', 'WBWB?', '?BW??', '?BW??']], [[['...BW', '...BW', '...BW', '...BW', 'W..BW', '.W.BW', '...BW'], [[2, 4], [3, 3]]], ['???BW', '???BW', '???B?', '????W', 'W??BW', '?W?BW', '???BW']], [[['...BW', '..WBW', '...BW', '...BW', '...BW'], []], ['???BW', '??WBW', '???BW', '???BW', '???BW']], [[['...BW', '...BW', '...BW', 'W..BW'], []], ['???BW', '???BW', '???BW', 'W??BW']], [[['..BW.', '..BW.', '..BWB', '..BW.', '..BW.', '..BW.', '..BW.'], [[2, 2], [3, 3]]], ['??BW?', '??BW?', '???WB', '??B??', '??BW?', '??BW?', '??BW?']], [[['.BW..', '.BW.B', '.BWB.', '.BW..', '.BW.B', '.BW..', 'WBW..'], [[4, 1]]], ['?BW??', '?BW?B', '?BWB?', '?BW??', '??W?B', '?BW??', 'WBW??']], [[['..BW', 'W.BW', '..BW', '..BW', '..BW', 'W.BW'], [[0, 2], [5, 3]]], ['???W', 'W?BW', '??BW', '??BW', '??BW', 'W?B?']], [[['..W', '.W.', 'W..'], [[0, 2], [2, 0]]], ['www', 'wWw', 'www']]], [[[['...BW.', '...BW.', '...BW.', '...BW.', '...BW.', '...BW.'], [[2, 4]]], ['bbbBW?', 'bbbBW?', 'bbbB??', 'bbbBW?', 'bbbBW?', 'bbbBW?']], [[['...BW', '...BW', 'W..BW', 'W.WBW', '...BW', '...BW'], []], ['???BW', '???BW', 'W??BW', 'W?WBW', '???BW', '???BW']], [[['....', '....', '....', '....'], []], ['????', '????', '????', '????']], [[['...', '...', '...'], []], ['???', '???', '???']], [[['.B.', 'B.B', '.B.'], [[1, 2], [2, 1]]], ['bBb', 'Bbb', 'bbb']], [[['B..W', 'B..W', 'B..W', 'B..W'], [[2, 3]]], ['B??W', 'B??W', 'B???', 'B??W']], [[['.BW.', '.BW.', '.BW.', '.BW.'], [[0, 2]]], ['bB??', 'bBW?', 'bBW?', 'bBW?']], [[['..B.', '....', '....', '....', 'B...'], [[0, 2]]], ['bbbb', 'bbbb', 'bbbb', 'bbbb', 'Bbbb']]], [[[['.B.', 'B.B', '.B.'], [[1, 2], [2, 1]]], ['bBb', 'Bbb', 'bbb']], [[['B.B.W', '.B.W.', 'B.BW.', 'BBW.W', '..W..'], []], ['BbB?W', 'bB?Ww', 'BbBWw', 'BBWwW', '??Www']], [[['W....', '.....', '.....', '.....', '....B'], [[4, 4]]], ['Wwwww', 'wwwww', 'wwwww', 'wwwww', 'wwwww']], [[['.W.B.', 'W.WB.', '.WB..', 'WB...', 'B....'], [[3, 1], [3, 0]]], ['wW?B?', 'WwWB?', '?WB??', '?????', 'B????']], [[['BBBB', 'B..B', 'B..B', 'BBBB'], [[0, 2]]], ['BBbB', 'BbbB', 'BbbB', 'BBBB']], [[['WWW', 'W.W', 'WWW'], []], ['WWW', 'WwW', 'WWW']], [[['B.W', '...', 'W.B'], [[2, 2], [0, 0]]], ['wwW', 'www', 'Www']], [[['.B...', 'B....', '.....', '....W', '...W.'], [[1, 0]]], ['?B???', '?????', '?????', '????W', '???Ww']]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("ownership map 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
ownership map case 0['?BW?', '?BW?', '?BW?', '?BWB', '?BW?', '?BWB']['?BW?', '??W?', '?BW?', '?BWB', '?BW?', '?BWB']Failed
ownership map case 1['???WBWw', '????BWw', '????BWw', '?W??BWw']['???WBWw', '????BWw', '????BWw', '?W??BWw']Passed
ownership map case 2['bBWB?', 'bBW??', 'bBW??', 'bBWB?']['bB?B?', 'bBW??', 'bB???', 'bBWB?']Failed
ownership map case 3['WBW???', '?BW???', '?BW??B', '?BW???', '?BW???']['WB????', '?BW???', '?BW??B', '?BW???', '?BW???']Failed
ownership map case 4['?BW?B??', 'WBW????', '?BW????', '?BW????', '?BW????']['?BW?B??', 'WBW????', '?B?????', '?BW????', '?BW????']Failed
ownership map case 5['????BW', '????BW', '????BW', '????BW', '????BW', '????BW']['????BW', '????BW', '??????', '????BW', '????BW', '????BW']Failed
ownership map case 6['??BW', '??BW', '??BW', '??BW', '??BW', '??BW', '??BW']['??BW', '??BW', '??BW', '???W', '??BW', '??BW', '??BW']Failed
ownership map case 7['bBb', 'BbB', 'bBb']['bBb', 'Bbb', 'bbb']Failed

SHA-256 / 6dd54964082c6a449d7b1d2c98cbbbacbb100ae7fab5f5470064b67abc386b12

3 / The verified repair

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

N = 1
observations = []
def solve(x):
    board, dead = x
    n = len(board)
    m = len(board[0])
    dd = {tuple(p) for p in dead}
    g = [[('.' if (r, c) in dd else board[r][c]) for c in range(m)] for r in range(n)]
    out = [[g[r][c] for c in range(m)] for r in range(n)]
    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))
            region = [(r, c)]
            k = 0
            cols = set()
            while k < len(region):
                i, j = region[k]
                k += 1
                for p, q in ((i - 1, j), (i, j - 1), (i + 1, j), (i, j + 1)):
                    if 0 <= p < n and 0 <= q < m:
                        if g[p][q] == '.':
                            if (p, q) not in seen:
                                seen.add((p, q))
                                region.append((p, q))
                        else:
                            cols.add(g[p][q])
            mark = cols.pop().lower() if len(cols) == 1 else '?'
            for i, j in region:
                out[i][j] = mark
    return [''.join(row) for row in out]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[['.BW.', '.BW.', '.BW.', '.BWB', '.BW.', '.BWB'], [[1, 1]]], ['?BW?', '??W?', '?BW?', '?BWB', '?BW?', '?BWB']], [[['...WBW.', '....BW.', '....BW.', '.W..BW.'], []], ['???WBWw', '????BWw', '????BWw', '?W??BWw']], [[['.BWB.', '.BW..', '.BW..', '.BWB.'], [[2, 2], [0, 2]]], ['bB?B?', 'bBW??', 'bB???', 'bBWB?']], [[['WBW...', '.BW...', '.BW..B', '.BW...', '.BW...'], [[0, 2]]], ['WB????', '?BW???', '?BW??B', '?BW???', '?BW???']], [[['.BW.B..', 'WBW....', '.BW....', '.BW....', '.BW....'], [[2, 2]]], ['?BW?B??', 'WBW????', '?B?????', '?BW????', '?BW????']], [[['....BW', '....BW', '....BW', '....BW', '....BW', '....BW'], [[2, 5], [2, 4]]], ['????BW', '????BW', '??????', '????BW', '????BW', '????BW']], [[['..BW', '..BW', '..BW', '..BW', '..BW', '..BW', '..BW'], [[3, 2]]], ['??BW', '??BW', '??BW', '???W', '??BW', '??BW', '??BW']], [[['.B.', 'B.B', '.B.'], [[1, 2], [2, 1]]], ['bBb', 'Bbb', 'bbb']]], [[[['W.BW.', '..BW.', '.WBW.', '.WBW.', '..BW.', '..BW.', '..BW.'], []], ['W?BWw', '??BWw', '?WBWw', '?WBWw', '??BWw', '??BWw', '??BWw']], [[['.W.W.BW', '.....BW', '.W...BW', '...W.BW', '.....BW'], [[2, 1]]], ['?W?W?BW', '?????BW', '?????BW', '???W?BW', '?????BW']], [[['.BWB', '.BW.', 'WBW.', '.BW.', '.BW.', 'WBW.'], [[4, 1]]], ['?BWB', '?BW?', 'WBW?', '?BW?', '??W?', 'WBW?']], [[['.BW.', '.BW.', 'WBW.', '.BW.', '.BW.'], [[0, 1], [3, 1]]], ['??Ww', '?BWw', 'WBWw', '??Ww', '?BWw']], [[['.W..BW', '....BW', 'W...BW', '....BW'], [[1, 4]]], ['?W??BW', '?????W', 'W???BW', '????BW']], [[['..BW', '..BW', 'W.BW', '..BW', '..BW'], [[4, 2], [3, 2]]], ['??BW', '??BW', 'W?BW', '???W', '???W']], [[['.BW...', '.BW...', '.BW...', 'WBW..B', '.BW..B', '.BW..B'], []], ['?BW???', '?BW???', '?BW???', 'WBW??B', '?BW??B', '?BW??B']], [[['BBBB', 'B..B', 'B..B', 'BBBB'], [[0, 2]]], ['BBbB', 'BbbB', 'BbbB', 'BBBB']]], [[[['.BW..', 'WBW..', 'WBWB.', '.BW..', '.BW..'], []], ['?BW??', 'WBW??', 'WBWB?', '?BW??', '?BW??']], [[['...BW', '...BW', '...BW', '...BW', 'W..BW', '.W.BW', '...BW'], [[2, 4], [3, 3]]], ['???BW', '???BW', '???B?', '????W', 'W??BW', '?W?BW', '???BW']], [[['...BW', '..WBW', '...BW', '...BW', '...BW'], []], ['???BW', '??WBW', '???BW', '???BW', '???BW']], [[['...BW', '...BW', '...BW', 'W..BW'], []], ['???BW', '???BW', '???BW', 'W??BW']], [[['..BW.', '..BW.', '..BWB', '..BW.', '..BW.', '..BW.', '..BW.'], [[2, 2], [3, 3]]], ['??BW?', '??BW?', '???WB', '??B??', '??BW?', '??BW?', '??BW?']], [[['.BW..', '.BW.B', '.BWB.', '.BW..', '.BW.B', '.BW..', 'WBW..'], [[4, 1]]], ['?BW??', '?BW?B', '?BWB?', '?BW??', '??W?B', '?BW??', 'WBW??']], [[['..BW', 'W.BW', '..BW', '..BW', '..BW', 'W.BW'], [[0, 2], [5, 3]]], ['???W', 'W?BW', '??BW', '??BW', '??BW', 'W?B?']], [[['..W', '.W.', 'W..'], [[0, 2], [2, 0]]], ['www', 'wWw', 'www']]], [[[['...BW.', '...BW.', '...BW.', '...BW.', '...BW.', '...BW.'], [[2, 4]]], ['bbbBW?', 'bbbBW?', 'bbbB??', 'bbbBW?', 'bbbBW?', 'bbbBW?']], [[['...BW', '...BW', 'W..BW', 'W.WBW', '...BW', '...BW'], []], ['???BW', '???BW', 'W??BW', 'W?WBW', '???BW', '???BW']], [[['....', '....', '....', '....'], []], ['????', '????', '????', '????']], [[['...', '...', '...'], []], ['???', '???', '???']], [[['.B.', 'B.B', '.B.'], [[1, 2], [2, 1]]], ['bBb', 'Bbb', 'bbb']], [[['B..W', 'B..W', 'B..W', 'B..W'], [[2, 3]]], ['B??W', 'B??W', 'B???', 'B??W']], [[['.BW.', '.BW.', '.BW.', '.BW.'], [[0, 2]]], ['bB??', 'bBW?', 'bBW?', 'bBW?']], [[['..B.', '....', '....', '....', 'B...'], [[0, 2]]], ['bbbb', 'bbbb', 'bbbb', 'bbbb', 'Bbbb']]], [[[['.B.', 'B.B', '.B.'], [[1, 2], [2, 1]]], ['bBb', 'Bbb', 'bbb']], [[['B.B.W', '.B.W.', 'B.BW.', 'BBW.W', '..W..'], []], ['BbB?W', 'bB?Ww', 'BbBWw', 'BBWwW', '??Www']], [[['W....', '.....', '.....', '.....', '....B'], [[4, 4]]], ['Wwwww', 'wwwww', 'wwwww', 'wwwww', 'wwwww']], [[['.W.B.', 'W.WB.', '.WB..', 'WB...', 'B....'], [[3, 1], [3, 0]]], ['wW?B?', 'WwWB?', '?WB??', '?????', 'B????']], [[['BBBB', 'B..B', 'B..B', 'BBBB'], [[0, 2]]], ['BBbB', 'BbbB', 'BbbB', 'BBBB']], [[['WWW', 'W.W', 'WWW'], []], ['WWW', 'WwW', 'WWW']], [[['B.W', '...', 'W.B'], [[2, 2], [0, 0]]], ['wwW', 'www', 'Www']], [[['.B...', 'B....', '.....', '....W', '...W.'], [[1, 0]]], ['?B???', '?????', '?????', '????W', '???Ww']]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("ownership map 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
ownership map case 0['?BW?', '??W?', '?BW?', '?BWB', '?BW?', '?BWB']['?BW?', '??W?', '?BW?', '?BWB', '?BW?', '?BWB']Passed
ownership map case 1['???WBWw', '????BWw', '????BWw', '?W??BWw']['???WBWw', '????BWw', '????BWw', '?W??BWw']Passed
ownership map case 2['bB?B?', 'bBW??', 'bB???', 'bBWB?']['bB?B?', 'bBW??', 'bB???', 'bBWB?']Passed
ownership map case 3['WB????', '?BW???', '?BW??B', '?BW???', '?BW???']['WB????', '?BW???', '?BW??B', '?BW???', '?BW???']Passed
ownership map case 4['?BW?B??', 'WBW????', '?B?????', '?BW????', '?BW????']['?BW?B??', 'WBW????', '?B?????', '?BW????', '?BW????']Passed
ownership map case 5['????BW', '????BW', '??????', '????BW', '????BW', '????BW']['????BW', '????BW', '??????', '????BW', '????BW', '????BW']Passed
ownership map case 6['??BW', '??BW', '??BW', '???W', '??BW', '??BW', '??BW']['??BW', '??BW', '??BW', '???W', '??BW', '??BW', '??BW']Passed
ownership map case 7['bBb', 'Bbb', 'bbb']['bBb', 'Bbb', 'bbb']Passed

SHA-256 / c4b29bb2ce8a0395dd36923d2bcb2ce895c7c89f86b832f7ffde38cf0d3aec97

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:19.371791+00:00.

Case digest / 336e8533b709de23d0f7f921f7b7d30ef72c2b3ed5e34edd2262841c629029dd