broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    size, moves = x
    g = [['.'] * size for _ in range(size)]
    pris = {'B': 0, 'W': 0}
    def chain(i, j):
        col = g[i][j]
        seen = {(i, j)}
        todo = [(i, j)]
        libs = 0
        while todo:
            a, b = todo.pop()
            for p, q in ((a - 1, b), (a, b + 1), (a + 1, b), (a, b - 1)):
                if 0 <= p < size and 0 <= q < size:
                    if g[p][q] == '.':
                        libs += 1
                    elif g[p][q] == col and (p, q) not in seen:
                        seen.add((p, q))
                        todo.append((p, q))
        return seen, libs
    for idx, mv in enumerate(moves):
        if mv[1] == 'pass':
            continue
        col, r, c = mv
        if g[r][c] != '.':
            return ['illegal', idx]
        g[r][c] = col
        opp = 'B' if col == 'W' else 'W'
        for p, q in ((r - 1, c), (r, c + 1), (r + 1, c), (r, c - 1)):
            if 0 <= p < size and 0 <= q < size and g[p][q] == opp:
                dead, libs = chain(p, q)
                if libs == 0:
                    for s, t in dead:
                        g[s][t] = '.'
                    pris[opp] += len(dead)
        own, libs = chain(r, c)
        if libs == 0:
            return ['illegal', idx]
    return [pris['B'], pris['W'], [''.join(row) for row in g]]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[4, [['B', 3, 0], ['W', 2, 3], ['B', 'pass']]], [0, 0, ['....', '....', '...W', 'B...']]], [[4, [['B', 2, 0], ['W', 3, 1], ['B', 2, 0], ['W', 0, 1], ['B', 2, 0], ['W', 1, 3], ['B', 'pass'], ['W', 0, 1], ['B', 2, 3], ['W', 1, 2], ['B', 1, 1], ['W', 1, 0]]], ['illegal', 2]], [[3, [['B', 1, 1], ['W', 0, 1], ['B', 1, 1], ['W', 1, 1], ['B', 'pass'], ['W', 1, 1], ['B', 2, 0], ['W', 2, 2], ['B', 2, 0], ['W', 1, 1], ['B', 2, 2], ['W', 0, 0], ['B', 'pass'], ['W', 0, 2], ['B', 2, 1]]], ['illegal', 2]], [[3, [['B', 0, 1], ['W', 1, 0], ['B', 2, 1], ['W', 1, 0], ['B', 'pass'], ['W', 0, 0], ['B', 1, 1], ['W', 1, 1], ['B', 1, 1], ['W', 1, 2], ['B', 2, 0], ['W', 1, 1], ['B', 2, 2], ['W', 2, 1], ['B', 0, 0]]], ['illegal', 3]], [[4, [['B', 3, 0], ['W', 2, 1], ['B', 3, 1], ['W', 3, 0], ['B', 0, 0], ['W', 1, 0], ['B', 'pass']]], ['illegal', 3]], [[4, [['B', 0, 3], ['W', 0, 2], ['B', 2, 0], ['W', 1, 3], ['B', 2, 3], ['W', 'pass'], ['B', 0, 1], ['W', 1, 0], ['B', 0, 2], ['W', 1, 0], ['B', 2, 1], ['W', 3, 0]]], ['illegal', 8]], [[3, [['B', 'pass'], ['W', 1, 2], ['B', 0, 0], ['W', 1, 1], ['B', 0, 2], ['W', 0, 1], ['B', 'pass'], ['W', 'pass']]], [0, 1, ['BW.', '.WW', '...']]], [[3, [['B', 1, 0], ['W', 0, 0], ['B', 1, 1], ['W', 0, 1], ['B', 0, 2]]], [2, 0, ['..B', 'BB.', '...']]]], [[[3, [['B', 0, 1], ['W', 2, 0], ['B', 1, 1], ['W', 1, 2], ['B', 0, 0], ['W', 2, 1], ['B', 2, 1], ['W', 'pass'], ['B', 0, 2], ['W', 1, 1], ['B', 1, 2], ['W', 0, 0], ['B', 'pass']]], ['illegal', 6]], [[4, [['B', 2, 0], ['W', 0, 2], ['B', 1, 1], ['W', 3, 0], ['B', 3, 2]]], [0, 0, ['..W.', '.B..', 'B...', 'W.B.']]], [[3, [['B', 2, 1], ['W', 2, 1], ['B', 1, 2], ['W', 2, 2], ['B', 0, 2], ['W', 0, 0], ['B', 1, 1], ['W', 0, 1], ['B', 0, 2]]], ['illegal', 1]], [[4, [['B', 0, 1], ['W', 'pass'], ['B', 1, 3], ['W', 2, 3], ['B', 0, 2], ['W', 2, 0], ['B', 2, 0], ['W', 1, 1], ['B', 'pass'], ['W', 1, 2], ['B', 1, 0], ['W', 3, 2]]], ['illegal', 6]], [[3, [['B', 1, 0], ['W', 2, 2], ['B', 'pass'], ['W', 1, 0], ['B', 1, 2]]], ['illegal', 3]], [[4, [['B', 1, 0], ['W', 2, 0], ['B', 1, 3], ['W', 0, 0], ['B', 1, 1], ['W', 2, 2], ['B', 3, 1], ['W', 1, 2], ['B', 0, 0], ['W', 0, 2], ['B', 1, 0], ['W', 0, 0]]], ['illegal', 8]], [[4, [['B', 1, 0], ['W', 0, 0], ['B', 1, 1], ['W', 0, 1], ['B', 1, 2], ['W', 0, 2], ['B', 0, 3]]], [3, 0, ['...B', 'BBB.', '....', '....']]], [[3, [['W', 1, 0], ['B', 0, 0], ['W', 1, 1], ['B', 0, 1], ['W', 0, 2], ['B', 2, 2]]], [0, 2, ['..W', 'WW.', '..B']]]], [[[3, [['B', 2, 0], ['W', 1, 1], ['B', 'pass'], ['W', 2, 1], ['B', 0, 1], ['W', 1, 1]]], ['illegal', 5]], [[4, [['B', 3, 1], ['W', 1, 3], ['B', 2, 3], ['W', 2, 0], ['B', 0, 1], ['W', 1, 3], ['B', 'pass'], ['W', 0, 0], ['B', 3, 0], ['W', 'pass'], ['B', 'pass'], ['W', 1, 1], ['B', 0, 2], ['W', 'pass'], ['B', 0, 0]]], ['illegal', 5]], [[4, [['B', 1, 1], ['W', 0, 2], ['B', 2, 3], ['W', 'pass'], ['B', 1, 1], ['W', 0, 2], ['B', 0, 3], ['W', 2, 0], ['B', 2, 2], ['W', 3, 0], ['B', 3, 0]]], ['illegal', 4]], [[3, [['B', 0, 0], ['W', 2, 2], ['B', 2, 1], ['W', 2, 2], ['B', 1, 2], ['W', 2, 2], ['B', 1, 0]]], ['illegal', 3]], [[3, [['B', 1, 2], ['W', 2, 0], ['B', 1, 0], ['W', 0, 1], ['B', 2, 2], ['W', 2, 2], ['B', 1, 2], ['W', 2, 0], ['B', 'pass'], ['W', 2, 0], ['B', 2, 1], ['W', 2, 0], ['B', 0, 2], ['W', 0, 1], ['B', 2, 2]]], ['illegal', 5]], [[3, [['B', 'pass'], ['W', 1, 2], ['B', 0, 0], ['W', 1, 1], ['B', 0, 2], ['W', 0, 1], ['B', 'pass'], ['W', 'pass']]], [0, 1, ['BW.', '.WW', '...']]], [[4, [['B', 1, 0], ['W', 0, 0], ['B', 1, 1], ['W', 0, 1], ['B', 1, 2], ['W', 0, 2], ['B', 0, 3]]], [3, 0, ['...B', 'BBB.', '....', '....']]], [[3, [['W', 0, 1], ['B', 0, 0], ['W', 1, 0], ['B', 'pass'], ['W', 2, 2]]], [0, 1, ['.W.', 'W..', '..W']]]], [[[4, [['B', 'pass'], ['W', 1, 0], ['B', 2, 3], ['W', 3, 2], ['B', 1, 3]]], [0, 0, ['....', 'W..B', '...B', '..W.']]], [[4, [['B', 0, 3], ['W', 'pass'], ['B', 3, 1], ['W', 3, 3], ['B', 3, 1], ['W', 0, 3], ['B', 1, 3], ['W', 'pass'], ['B', 3, 2], ['W', 'pass'], ['B', 3, 1], ['W', 0, 2], ['B', 3, 0]]], ['illegal', 4]], [[3, [['B', 1, 1], ['W', 2, 1], ['B', 2, 0], ['W', 0, 2], ['B', 0, 2], ['W', 0, 0], ['B', 2, 2], ['W', 2, 0], ['B', 2, 2], ['W', 0, 2], ['B', 2, 2], ['W', 2, 0]]], ['illegal', 4]], [[3, [['B', 1, 0], ['W', 0, 1], ['B', 0, 1], ['W', 0, 2], ['B', 2, 0], ['W', 1, 0], ['B', 0, 0], ['W', 2, 1], ['B', 2, 2], ['W', 2, 0], ['B', 1, 1], ['W', 0, 2], ['B', 1, 1], ['W', 0, 2]]], ['illegal', 2]], [[4, [['B', 0, 3], ['W', 3, 3], ['B', 1, 2], ['W', 0, 1], ['B', 3, 0]]], [0, 0, ['.W.B', '..B.', '....', 'B..W']]], [[4, [['B', 3, 0], ['W', 0, 3], ['B', 0, 2]]], [0, 0, ['..BW', '....', '....', 'B...']]], [[3, [['B', 1, 0], ['W', 0, 0], ['B', 1, 1], ['W', 0, 1], ['B', 0, 2]]], [2, 0, ['..B', 'BB.', '...']]], [[3, [['B', 1, 0], ['W', 0, 0], ['B', 1, 1], ['W', 0, 1], ['B', 0, 2]]], [2, 0, ['..B', 'BB.', '...']]]], [[[3, [['B', 2, 2], ['W', 1, 1], ['B', 1, 0], ['W', 2, 1], ['B', 0, 2]]], [0, 0, ['..B', 'BW.', '.WB']]], [[3, [['B', 0, 2], ['W', 0, 1], ['B', 1, 1], ['W', 2, 2], ['B', 0, 2], ['W', 'pass'], ['B', 1, 1], ['W', 'pass'], ['B', 0, 2], ['W', 2, 1], ['B', 'pass'], ['W', 0, 0], ['B', 'pass']]], ['illegal', 4]], [[3, [['B', 1, 1], ['W', 1, 2], ['B', 0, 2]]], [0, 0, ['..B', '.BW', '...']]], [[3, [['B', 2, 1], ['W', 'pass'], ['B', 'pass'], ['W', 0, 0], ['B', 1, 1], ['W', 0, 2], ['B', 0, 2], ['W', 2, 2], ['B', 0, 1]]], ['illegal', 6]], [[3, [['B', 2, 0], ['W', 0, 1], ['B', 1, 0], ['W', 1, 1], ['B', 2, 0], ['W', 1, 0], ['B', 0, 0], ['W', 'pass']]], ['illegal', 4]], [[4, [['B', 2, 3], ['W', 0, 2], ['B', 1, 3], ['W', 'pass'], ['B', 1, 0], ['W', 2, 1], ['B', 3, 0], ['W', 1, 1]]], [0, 0, ['..W.', 'BW.B', '.W.B', 'B...']]], [[3, [['W', 1, 0], ['B', 0, 0], ['W', 1, 1], ['B', 0, 1], ['W', 0, 2], ['B', 2, 2]]], [0, 2, ['..W', 'WW.', '..B']]], [[3, [['B', 0, 1], ['W', 0, 0], ['B', 1, 0]]], [1, 0, ['.B.', 'B..', '...']]]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("replay 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)

source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    size, moves = x
    g = [['.'] * size for _ in range(size)]
    pris = {'B': 0, 'W': 0}
    def chain(i, j):
        col = g[i][j]
        seen = {(i, j)}
        todo = [(i, j)]
        libs = 0
        while todo:
            a, b = todo.pop()
            for p, q in ((a - 1, b), (a, b + 1), (a + 1, b), (a, b - 1)):
                if 0 <= p < size and 0 <= q < size:
                    if g[p][q] == '.':
                        libs += 1
                    elif g[p][q] == col and (p, q) not in seen:
                        seen.add((p, q))
                        todo.append((p, q))
        return seen, libs
    for idx, mv in enumerate(moves):
        if mv[1] == 'pass':
            continue
        col, r, c = mv
        if g[r][c] != '.':
            return ['illegal', idx]
        g[r][c] = col
        opp = 'B' if col == 'W' else 'W'
        for p, q in ((r - 1, c), (r, c + 1), (r + 1, c), (r, c - 1)):
            if 0 <= p < size and 0 <= q < size and g[p][q] == opp:
                dead, libs = chain(p, q)
                if libs == 0:
                    for s, t in dead:
                        g[s][t] = '.'
                    pris[col] += 1
        own, libs = chain(r, c)
        if libs == 0:
            return ['illegal', idx]
    return [pris['B'], pris['W'], [''.join(row) for row in g]]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[4, [['B', 3, 0], ['W', 2, 3], ['B', 'pass']]], [0, 0, ['....', '....', '...W', 'B...']]], [[4, [['B', 2, 0], ['W', 3, 1], ['B', 2, 0], ['W', 0, 1], ['B', 2, 0], ['W', 1, 3], ['B', 'pass'], ['W', 0, 1], ['B', 2, 3], ['W', 1, 2], ['B', 1, 1], ['W', 1, 0]]], ['illegal', 2]], [[3, [['B', 1, 1], ['W', 0, 1], ['B', 1, 1], ['W', 1, 1], ['B', 'pass'], ['W', 1, 1], ['B', 2, 0], ['W', 2, 2], ['B', 2, 0], ['W', 1, 1], ['B', 2, 2], ['W', 0, 0], ['B', 'pass'], ['W', 0, 2], ['B', 2, 1]]], ['illegal', 2]], [[3, [['B', 0, 1], ['W', 1, 0], ['B', 2, 1], ['W', 1, 0], ['B', 'pass'], ['W', 0, 0], ['B', 1, 1], ['W', 1, 1], ['B', 1, 1], ['W', 1, 2], ['B', 2, 0], ['W', 1, 1], ['B', 2, 2], ['W', 2, 1], ['B', 0, 0]]], ['illegal', 3]], [[4, [['B', 3, 0], ['W', 2, 1], ['B', 3, 1], ['W', 3, 0], ['B', 0, 0], ['W', 1, 0], ['B', 'pass']]], ['illegal', 3]], [[4, [['B', 0, 3], ['W', 0, 2], ['B', 2, 0], ['W', 1, 3], ['B', 2, 3], ['W', 'pass'], ['B', 0, 1], ['W', 1, 0], ['B', 0, 2], ['W', 1, 0], ['B', 2, 1], ['W', 3, 0]]], ['illegal', 8]], [[3, [['B', 'pass'], ['W', 1, 2], ['B', 0, 0], ['W', 1, 1], ['B', 0, 2], ['W', 0, 1], ['B', 'pass'], ['W', 'pass']]], [0, 1, ['BW.', '.WW', '...']]], [[3, [['B', 1, 0], ['W', 0, 0], ['B', 1, 1], ['W', 0, 1], ['B', 0, 2]]], [2, 0, ['..B', 'BB.', '...']]]], [[[3, [['B', 0, 1], ['W', 2, 0], ['B', 1, 1], ['W', 1, 2], ['B', 0, 0], ['W', 2, 1], ['B', 2, 1], ['W', 'pass'], ['B', 0, 2], ['W', 1, 1], ['B', 1, 2], ['W', 0, 0], ['B', 'pass']]], ['illegal', 6]], [[4, [['B', 2, 0], ['W', 0, 2], ['B', 1, 1], ['W', 3, 0], ['B', 3, 2]]], [0, 0, ['..W.', '.B..', 'B...', 'W.B.']]], [[3, [['B', 2, 1], ['W', 2, 1], ['B', 1, 2], ['W', 2, 2], ['B', 0, 2], ['W', 0, 0], ['B', 1, 1], ['W', 0, 1], ['B', 0, 2]]], ['illegal', 1]], [[4, [['B', 0, 1], ['W', 'pass'], ['B', 1, 3], ['W', 2, 3], ['B', 0, 2], ['W', 2, 0], ['B', 2, 0], ['W', 1, 1], ['B', 'pass'], ['W', 1, 2], ['B', 1, 0], ['W', 3, 2]]], ['illegal', 6]], [[3, [['B', 1, 0], ['W', 2, 2], ['B', 'pass'], ['W', 1, 0], ['B', 1, 2]]], ['illegal', 3]], [[4, [['B', 1, 0], ['W', 2, 0], ['B', 1, 3], ['W', 0, 0], ['B', 1, 1], ['W', 2, 2], ['B', 3, 1], ['W', 1, 2], ['B', 0, 0], ['W', 0, 2], ['B', 1, 0], ['W', 0, 0]]], ['illegal', 8]], [[4, [['B', 1, 0], ['W', 0, 0], ['B', 1, 1], ['W', 0, 1], ['B', 1, 2], ['W', 0, 2], ['B', 0, 3]]], [3, 0, ['...B', 'BBB.', '....', '....']]], [[3, [['W', 1, 0], ['B', 0, 0], ['W', 1, 1], ['B', 0, 1], ['W', 0, 2], ['B', 2, 2]]], [0, 2, ['..W', 'WW.', '..B']]]], [[[3, [['B', 2, 0], ['W', 1, 1], ['B', 'pass'], ['W', 2, 1], ['B', 0, 1], ['W', 1, 1]]], ['illegal', 5]], [[4, [['B', 3, 1], ['W', 1, 3], ['B', 2, 3], ['W', 2, 0], ['B', 0, 1], ['W', 1, 3], ['B', 'pass'], ['W', 0, 0], ['B', 3, 0], ['W', 'pass'], ['B', 'pass'], ['W', 1, 1], ['B', 0, 2], ['W', 'pass'], ['B', 0, 0]]], ['illegal', 5]], [[4, [['B', 1, 1], ['W', 0, 2], ['B', 2, 3], ['W', 'pass'], ['B', 1, 1], ['W', 0, 2], ['B', 0, 3], ['W', 2, 0], ['B', 2, 2], ['W', 3, 0], ['B', 3, 0]]], ['illegal', 4]], [[3, [['B', 0, 0], ['W', 2, 2], ['B', 2, 1], ['W', 2, 2], ['B', 1, 2], ['W', 2, 2], ['B', 1, 0]]], ['illegal', 3]], [[3, [['B', 1, 2], ['W', 2, 0], ['B', 1, 0], ['W', 0, 1], ['B', 2, 2], ['W', 2, 2], ['B', 1, 2], ['W', 2, 0], ['B', 'pass'], ['W', 2, 0], ['B', 2, 1], ['W', 2, 0], ['B', 0, 2], ['W', 0, 1], ['B', 2, 2]]], ['illegal', 5]], [[3, [['B', 'pass'], ['W', 1, 2], ['B', 0, 0], ['W', 1, 1], ['B', 0, 2], ['W', 0, 1], ['B', 'pass'], ['W', 'pass']]], [0, 1, ['BW.', '.WW', '...']]], [[4, [['B', 1, 0], ['W', 0, 0], ['B', 1, 1], ['W', 0, 1], ['B', 1, 2], ['W', 0, 2], ['B', 0, 3]]], [3, 0, ['...B', 'BBB.', '....', '....']]], [[3, [['W', 0, 1], ['B', 0, 0], ['W', 1, 0], ['B', 'pass'], ['W', 2, 2]]], [0, 1, ['.W.', 'W..', '..W']]]], [[[4, [['B', 'pass'], ['W', 1, 0], ['B', 2, 3], ['W', 3, 2], ['B', 1, 3]]], [0, 0, ['....', 'W..B', '...B', '..W.']]], [[4, [['B', 0, 3], ['W', 'pass'], ['B', 3, 1], ['W', 3, 3], ['B', 3, 1], ['W', 0, 3], ['B', 1, 3], ['W', 'pass'], ['B', 3, 2], ['W', 'pass'], ['B', 3, 1], ['W', 0, 2], ['B', 3, 0]]], ['illegal', 4]], [[3, [['B', 1, 1], ['W', 2, 1], ['B', 2, 0], ['W', 0, 2], ['B', 0, 2], ['W', 0, 0], ['B', 2, 2], ['W', 2, 0], ['B', 2, 2], ['W', 0, 2], ['B', 2, 2], ['W', 2, 0]]], ['illegal', 4]], [[3, [['B', 1, 0], ['W', 0, 1], ['B', 0, 1], ['W', 0, 2], ['B', 2, 0], ['W', 1, 0], ['B', 0, 0], ['W', 2, 1], ['B', 2, 2], ['W', 2, 0], ['B', 1, 1], ['W', 0, 2], ['B', 1, 1], ['W', 0, 2]]], ['illegal', 2]], [[4, [['B', 0, 3], ['W', 3, 3], ['B', 1, 2], ['W', 0, 1], ['B', 3, 0]]], [0, 0, ['.W.B', '..B.', '....', 'B..W']]], [[4, [['B', 3, 0], ['W', 0, 3], ['B', 0, 2]]], [0, 0, ['..BW', '....', '....', 'B...']]], [[3, [['B', 1, 0], ['W', 0, 0], ['B', 1, 1], ['W', 0, 1], ['B', 0, 2]]], [2, 0, ['..B', 'BB.', '...']]], [[3, [['B', 1, 0], ['W', 0, 0], ['B', 1, 1], ['W', 0, 1], ['B', 0, 2]]], [2, 0, ['..B', 'BB.', '...']]]], [[[3, [['B', 2, 2], ['W', 1, 1], ['B', 1, 0], ['W', 2, 1], ['B', 0, 2]]], [0, 0, ['..B', 'BW.', '.WB']]], [[3, [['B', 0, 2], ['W', 0, 1], ['B', 1, 1], ['W', 2, 2], ['B', 0, 2], ['W', 'pass'], ['B', 1, 1], ['W', 'pass'], ['B', 0, 2], ['W', 2, 1], ['B', 'pass'], ['W', 0, 0], ['B', 'pass']]], ['illegal', 4]], [[3, [['B', 1, 1], ['W', 1, 2], ['B', 0, 2]]], [0, 0, ['..B', '.BW', '...']]], [[3, [['B', 2, 1], ['W', 'pass'], ['B', 'pass'], ['W', 0, 0], ['B', 1, 1], ['W', 0, 2], ['B', 0, 2], ['W', 2, 2], ['B', 0, 1]]], ['illegal', 6]], [[3, [['B', 2, 0], ['W', 0, 1], ['B', 1, 0], ['W', 1, 1], ['B', 2, 0], ['W', 1, 0], ['B', 0, 0], ['W', 'pass']]], ['illegal', 4]], [[4, [['B', 2, 3], ['W', 0, 2], ['B', 1, 3], ['W', 'pass'], ['B', 1, 0], ['W', 2, 1], ['B', 3, 0], ['W', 1, 1]]], [0, 0, ['..W.', 'BW.B', '.W.B', 'B...']]], [[3, [['W', 1, 0], ['B', 0, 0], ['W', 1, 1], ['B', 0, 1], ['W', 0, 2], ['B', 2, 2]]], [0, 2, ['..W', 'WW.', '..B']]], [[3, [['B', 0, 1], ['W', 0, 0], ['B', 1, 0]]], [1, 0, ['.B.', 'B..', '...']]]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("replay 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)

prompt:
Replay prisoner totals are swapped for every capture.

Input [size, moves]; each move is [colour, row, col] or [colour, "pass"]. Replay with captures; captured stones are prisoners of the mover; occupied or suicidal moves stop replay with ["illegal", index]. Return [prisoners_B, prisoners_W, final_board_rows].

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    size, moves = x
    g = [['.'] * size for _ in range(size)]
    pris = {'B': 0, 'W': 0}
    def chain(i, j):
        col = g[i][j]
        seen = {(i, j)}
        todo = [(i, j)]
        libs = 0
        while todo:
            a, b = todo.pop()
            for p, q in ((a - 1, b), (a, b + 1), (a + 1, b), (a, b - 1)):
                if 0 <= p < size and 0 <= q < size:
                    if g[p][q] == '.':
                        libs += 1
                    elif g[p][q] == col and (p, q) not in seen:
                        seen.add((p, q))
                        todo.append((p, q))
        return seen, libs
    for idx, mv in enumerate(moves):
        if mv[1] == 'pass':
            break
        col, r, c = mv
        if g[r][c] != '.':
            return ['illegal', idx]
        g[r][c] = col
        opp = 'B' if col == 'W' else 'W'
        for p, q in ((r - 1, c), (r, c + 1), (r + 1, c), (r, c - 1)):
            if 0 <= p < size and 0 <= q < size and g[p][q] == opp:
                dead, libs = chain(p, q)
                if libs == 0:
                    for s, t in dead:
                        g[s][t] = '.'
                    pris[col] += len(dead)
        own, libs = chain(r, c)
        if libs == 0:
            return ['illegal', idx]
    return [pris['B'], pris['W'], [''.join(row) for row in g]]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[4, [['B', 1, 3], ['W', 0, 0], ['B', 2, 1], ['W', 'pass'], ['B', 1, 2], ['W', 1, 0]]], [0, 0, ['W...', 'W.BB', '.B..', '....']]], [[4, [['B', 2, 0], ['W', 3, 1], ['B', 2, 0], ['W', 0, 1], ['B', 2, 0], ['W', 1, 3], ['B', 'pass'], ['W', 0, 1], ['B', 2, 3], ['W', 1, 2], ['B', 1, 1], ['W', 1, 0]]], ['illegal', 2]], [[3, [['B', 1, 1], ['W', 0, 1], ['B', 1, 1], ['W', 1, 1], ['B', 'pass'], ['W', 1, 1], ['B', 2, 0], ['W', 2, 2], ['B', 2, 0], ['W', 1, 1], ['B', 2, 2], ['W', 0, 0], ['B', 'pass'], ['W', 0, 2], ['B', 2, 1]]], ['illegal', 2]], [[3, [['B', 0, 1], ['W', 1, 0], ['B', 2, 1], ['W', 1, 0], ['B', 'pass'], ['W', 0, 0], ['B', 1, 1], ['W', 1, 1], ['B', 1, 1], ['W', 1, 2], ['B', 2, 0], ['W', 1, 1], ['B', 2, 2], ['W', 2, 1], ['B', 0, 0]]], ['illegal', 3]], [[4, [['B', 3, 0], ['W', 2, 1], ['B', 3, 1], ['W', 3, 0], ['B', 0, 0], ['W', 1, 0], ['B', 'pass']]], ['illegal', 3]], [[4, [['B', 0, 3], ['W', 0, 2], ['B', 2, 0], ['W', 1, 3], ['B', 2, 3], ['W', 'pass'], ['B', 0, 1], ['W', 1, 0], ['B', 0, 2], ['W', 1, 0], ['B', 2, 1], ['W', 3, 0]]], ['illegal', 8]], [[3, [['B', 2, 0], ['W', 'pass'], ['B', 1, 0], ['W', 2, 1], ['B', 1, 2], ['W', 0, 1], ['B', 0, 2], ['W', 1, 2], ['B', 'pass']]], ['illegal', 7]], [[4, [['B', 1, 1], ['W', 'pass'], ['B', 1, 0], ['W', 'pass'], ['B', 2, 3], ['W', 0, 2], ['B', 'pass']]], [0, 0, ['..W.', 'BB..', '...B', '....']]]], [[[4, [['B', 0, 3], ['W', 0, 2], ['B', 2, 0], ['W', 1, 3], ['B', 2, 3], ['W', 'pass'], ['B', 0, 1], ['W', 1, 0], ['B', 0, 2], ['W', 1, 0], ['B', 2, 1], ['W', 3, 0]]], ['illegal', 8]], [[4, [['B', 2, 0], ['W', 0, 2], ['B', 1, 1], ['W', 3, 0], ['B', 3, 2]]], [0, 0, ['..W.', '.B..', 'B...', 'W.B.']]], [[3, [['B', 2, 1], ['W', 2, 1], ['B', 1, 2], ['W', 2, 2], ['B', 0, 2], ['W', 0, 0], ['B', 1, 1], ['W', 0, 1], ['B', 0, 2]]], ['illegal', 1]], [[4, [['B', 0, 1], ['W', 'pass'], ['B', 1, 3], ['W', 2, 3], ['B', 0, 2], ['W', 2, 0], ['B', 2, 0], ['W', 1, 1], ['B', 'pass'], ['W', 1, 2], ['B', 1, 0], ['W', 3, 2]]], ['illegal', 6]], [[3, [['B', 1, 0], ['W', 2, 2], ['B', 'pass'], ['W', 1, 0], ['B', 1, 2]]], ['illegal', 3]], [[4, [['B', 1, 0], ['W', 2, 0], ['B', 1, 3], ['W', 0, 0], ['B', 1, 1], ['W', 2, 2], ['B', 3, 1], ['W', 1, 2], ['B', 0, 0], ['W', 0, 2], ['B', 1, 0], ['W', 0, 0]]], ['illegal', 8]], [[3, [['B', 0, 1], ['W', 1, 2], ['B', 1, 2]]], ['illegal', 2]], [[3, [['B', 'pass'], ['W', 0, 2], ['B', 2, 2], ['W', 0, 0], ['B', 0, 1], ['W', 2, 0], ['B', 'pass'], ['W', 1, 0]]], [0, 0, ['WBW', 'W..', 'W.B']]]], [[[3, [['B', 1, 0], ['W', 2, 2], ['B', 'pass'], ['W', 1, 0], ['B', 1, 2]]], ['illegal', 3]], [[4, [['B', 3, 1], ['W', 1, 3], ['B', 2, 3], ['W', 2, 0], ['B', 0, 1], ['W', 1, 3], ['B', 'pass'], ['W', 0, 0], ['B', 3, 0], ['W', 'pass'], ['B', 'pass'], ['W', 1, 1], ['B', 0, 2], ['W', 'pass'], ['B', 0, 0]]], ['illegal', 5]], [[4, [['B', 1, 1], ['W', 0, 2], ['B', 2, 3], ['W', 'pass'], ['B', 1, 1], ['W', 0, 2], ['B', 0, 3], ['W', 2, 0], ['B', 2, 2], ['W', 3, 0], ['B', 3, 0]]], ['illegal', 4]], [[3, [['B', 0, 0], ['W', 2, 2], ['B', 2, 1], ['W', 2, 2], ['B', 1, 2], ['W', 2, 2], ['B', 1, 0]]], ['illegal', 3]], [[3, [['B', 1, 2], ['W', 2, 0], ['B', 1, 0], ['W', 0, 1], ['B', 2, 2], ['W', 2, 2], ['B', 1, 2], ['W', 2, 0], ['B', 'pass'], ['W', 2, 0], ['B', 2, 1], ['W', 2, 0], ['B', 0, 2], ['W', 0, 1], ['B', 2, 2]]], ['illegal', 5]], [[3, [['B', 'pass'], ['W', 1, 2], ['B', 0, 0], ['W', 1, 1], ['B', 0, 2], ['W', 0, 1], ['B', 'pass'], ['W', 'pass']]], [0, 1, ['BW.', '.WW', '...']]], [[4, [['B', 3, 2], ['W', 2, 3], ['B', 2, 0], ['W', 1, 0], ['B', 0, 0], ['W', 2, 0], ['B', 'pass'], ['W', 0, 1], ['B', 2, 0]]], ['illegal', 5]], [[3, [['W', 0, 1], ['B', 0, 0], ['W', 1, 0], ['B', 'pass'], ['W', 2, 2]]], [0, 1, ['.W.', 'W..', '..W']]]], [[[3, [['B', 'pass'], ['W', 1, 2], ['B', 0, 0], ['W', 1, 1], ['B', 0, 2], ['W', 0, 1], ['B', 'pass'], ['W', 'pass']]], [0, 1, ['BW.', '.WW', '...']]], [[4, [['B', 0, 3], ['W', 'pass'], ['B', 3, 1], ['W', 3, 3], ['B', 3, 1], ['W', 0, 3], ['B', 1, 3], ['W', 'pass'], ['B', 3, 2], ['W', 'pass'], ['B', 3, 1], ['W', 0, 2], ['B', 3, 0]]], ['illegal', 4]], [[3, [['B', 1, 1], ['W', 2, 1], ['B', 2, 0], ['W', 0, 2], ['B', 0, 2], ['W', 0, 0], ['B', 2, 2], ['W', 2, 0], ['B', 2, 2], ['W', 0, 2], ['B', 2, 2], ['W', 2, 0]]], ['illegal', 4]], [[3, [['B', 1, 0], ['W', 0, 1], ['B', 0, 1], ['W', 0, 2], ['B', 2, 0], ['W', 1, 0], ['B', 0, 0], ['W', 2, 1], ['B', 2, 2], ['W', 2, 0], ['B', 1, 1], ['W', 0, 2], ['B', 1, 1], ['W', 0, 2]]], ['illegal', 2]], [[4, [['B', 0, 3], ['W', 3, 3], ['B', 1, 2], ['W', 0, 1], ['B', 3, 0]]], [0, 0, ['.W.B', '..B.', '....', 'B..W']]], [[4, [['B', 3, 0], ['W', 0, 3], ['B', 0, 2]]], [0, 0, ['..BW', '....', '....', 'B...']]], [[3, [['B', 0, 0], ['W', 1, 1], ['B', 0, 0], ['W', 'pass'], ['B', 0, 0], ['W', 2, 1], ['B', 2, 2], ['W', 2, 1], ['B', 1, 1]]], ['illegal', 2]], [[4, [['B', 2, 3], ['W', 0, 2], ['B', 1, 3], ['W', 'pass'], ['B', 1, 0], ['W', 2, 1], ['B', 3, 0], ['W', 1, 1]]], [0, 0, ['..W.', 'BW.B', '.W.B', 'B...']]]], [[[3, [['B', 2, 2], ['W', 1, 1], ['B', 1, 0], ['W', 2, 1], ['B', 0, 2]]], [0, 0, ['..B', 'BW.', '.WB']]], [[3, [['B', 0, 2], ['W', 0, 1], ['B', 1, 1], ['W', 2, 2], ['B', 0, 2], ['W', 'pass'], ['B', 1, 1], ['W', 'pass'], ['B', 0, 2], ['W', 2, 1], ['B', 'pass'], ['W', 0, 0], ['B', 'pass']]], ['illegal', 4]], [[3, [['B', 1, 1], ['W', 1, 2], ['B', 0, 2]]], [0, 0, ['..B', '.BW', '...']]], [[3, [['B', 2, 1], ['W', 'pass'], ['B', 'pass'], ['W', 0, 0], ['B', 1, 1], ['W', 0, 2], ['B', 0, 2], ['W', 2, 2], ['B', 0, 1]]], ['illegal', 6]], [[3, [['B', 2, 0], ['W', 0, 1], ['B', 1, 0], ['W', 1, 1], ['B', 2, 0], ['W', 1, 0], ['B', 0, 0], ['W', 'pass']]], ['illegal', 4]], [[4, [['B', 2, 3], ['W', 0, 2], ['B', 1, 3], ['W', 'pass'], ['B', 1, 0], ['W', 2, 1], ['B', 3, 0], ['W', 1, 1]]], [0, 0, ['..W.', 'BW.B', '.W.B', 'B...']]], [[4, [['B', 2, 1], ['W', 2, 0], ['B', 2, 1], ['W', 2, 3], ['B', 'pass'], ['W', 0, 0], ['B', 3, 1], ['W', 3, 2], ['B', 1, 1], ['W', 1, 1]]], ['illegal', 2]], [[4, [['B', 3, 0], ['W', 'pass'], ['B', 'pass']]], [0, 0, ['....', '....', '....', 'B...']]]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("replay 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)

meaning: Fixture-count band, not measured model difficulty

deps: stdlib

source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    size, moves = x
    g = [['.'] * size for _ in range(size)]
    pris = {'B': 0, 'W': 0}
    def chain(i, j):
        col = g[i][j]
        seen = {(i, j)}
        todo = [(i, j)]
        libs = 0
        while todo:
            a, b = todo.pop()
            for p, q in ((a - 1, b), (a, b + 1), (a + 1, b), (a, b - 1)):
                if 0 <= p < size and 0 <= q < size:
                    if g[p][q] == '.':
                        libs += 1
                    elif g[p][q] == col and (p, q) not in seen:
                        seen.add((p, q))
                        todo.append((p, q))
        return seen, libs
    for idx, mv in enumerate(moves):
        if mv[1] == 'pass':
            pris['W' if mv[0] == 'B' else 'B'] += 1
            continue
        col, r, c = mv
        if g[r][c] != '.':
            return ['illegal', idx]
        g[r][c] = col
        opp = 'B' if col == 'W' else 'W'
        for p, q in ((r - 1, c), (r, c + 1), (r + 1, c), (r, c - 1)):
            if 0 <= p < size and 0 <= q < size and g[p][q] == opp:
                dead, libs = chain(p, q)
                if libs == 0:
                    for s, t in dead:
                        g[s][t] = '.'
                    pris[col] += len(dead)
        own, libs = chain(r, c)
        if libs == 0:
            return ['illegal', idx]
    return [pris['B'], pris['W'], [''.join(row) for row in g]]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[4, [['B', 1, 3], ['W', 0, 0], ['B', 2, 1], ['W', 'pass'], ['B', 1, 2], ['W', 1, 0]]], [0, 0, ['W...', 'W.BB', '.B..', '....']]], [[4, [['B', 2, 0], ['W', 3, 1], ['B', 2, 0], ['W', 0, 1], ['B', 2, 0], ['W', 1, 3], ['B', 'pass'], ['W', 0, 1], ['B', 2, 3], ['W', 1, 2], ['B', 1, 1], ['W', 1, 0]]], ['illegal', 2]], [[3, [['B', 1, 1], ['W', 0, 1], ['B', 1, 1], ['W', 1, 1], ['B', 'pass'], ['W', 1, 1], ['B', 2, 0], ['W', 2, 2], ['B', 2, 0], ['W', 1, 1], ['B', 2, 2], ['W', 0, 0], ['B', 'pass'], ['W', 0, 2], ['B', 2, 1]]], ['illegal', 2]], [[3, [['B', 0, 1], ['W', 1, 0], ['B', 2, 1], ['W', 1, 0], ['B', 'pass'], ['W', 0, 0], ['B', 1, 1], ['W', 1, 1], ['B', 1, 1], ['W', 1, 2], ['B', 2, 0], ['W', 1, 1], ['B', 2, 2], ['W', 2, 1], ['B', 0, 0]]], ['illegal', 3]], [[4, [['B', 3, 0], ['W', 2, 1], ['B', 3, 1], ['W', 3, 0], ['B', 0, 0], ['W', 1, 0], ['B', 'pass']]], ['illegal', 3]], [[4, [['B', 0, 3], ['W', 0, 2], ['B', 2, 0], ['W', 1, 3], ['B', 2, 3], ['W', 'pass'], ['B', 0, 1], ['W', 1, 0], ['B', 0, 2], ['W', 1, 0], ['B', 2, 1], ['W', 3, 0]]], ['illegal', 8]], [[3, [['B', 2, 0], ['W', 'pass'], ['B', 1, 0], ['W', 2, 1], ['B', 1, 2], ['W', 0, 1], ['B', 0, 2], ['W', 1, 2], ['B', 'pass']]], ['illegal', 7]], [[4, [['B', 1, 1], ['W', 'pass'], ['B', 1, 0], ['W', 'pass'], ['B', 2, 3], ['W', 0, 2], ['B', 'pass']]], [0, 0, ['..W.', 'BB..', '...B', '....']]]], [[[4, [['B', 0, 3], ['W', 0, 2], ['B', 2, 0], ['W', 1, 3], ['B', 2, 3], ['W', 'pass'], ['B', 0, 1], ['W', 1, 0], ['B', 0, 2], ['W', 1, 0], ['B', 2, 1], ['W', 3, 0]]], ['illegal', 8]], [[4, [['B', 2, 0], ['W', 0, 2], ['B', 1, 1], ['W', 3, 0], ['B', 3, 2]]], [0, 0, ['..W.', '.B..', 'B...', 'W.B.']]], [[3, [['B', 2, 1], ['W', 2, 1], ['B', 1, 2], ['W', 2, 2], ['B', 0, 2], ['W', 0, 0], ['B', 1, 1], ['W', 0, 1], ['B', 0, 2]]], ['illegal', 1]], [[4, [['B', 0, 1], ['W', 'pass'], ['B', 1, 3], ['W', 2, 3], ['B', 0, 2], ['W', 2, 0], ['B', 2, 0], ['W', 1, 1], ['B', 'pass'], ['W', 1, 2], ['B', 1, 0], ['W', 3, 2]]], ['illegal', 6]], [[3, [['B', 1, 0], ['W', 2, 2], ['B', 'pass'], ['W', 1, 0], ['B', 1, 2]]], ['illegal', 3]], [[4, [['B', 1, 0], ['W', 2, 0], ['B', 1, 3], ['W', 0, 0], ['B', 1, 1], ['W', 2, 2], ['B', 3, 1], ['W', 1, 2], ['B', 0, 0], ['W', 0, 2], ['B', 1, 0], ['W', 0, 0]]], ['illegal', 8]], [[3, [['B', 0, 1], ['W', 1, 2], ['B', 1, 2]]], ['illegal', 2]], [[3, [['B', 'pass'], ['W', 0, 2], ['B', 2, 2], ['W', 0, 0], ['B', 0, 1], ['W', 2, 0], ['B', 'pass'], ['W', 1, 0]]], [0, 0, ['WBW', 'W..', 'W.B']]]], [[[3, [['B', 1, 0], ['W', 2, 2], ['B', 'pass'], ['W', 1, 0], ['B', 1, 2]]], ['illegal', 3]], [[4, [['B', 3, 1], ['W', 1, 3], ['B', 2, 3], ['W', 2, 0], ['B', 0, 1], ['W', 1, 3], ['B', 'pass'], ['W', 0, 0], ['B', 3, 0], ['W', 'pass'], ['B', 'pass'], ['W', 1, 1], ['B', 0, 2], ['W', 'pass'], ['B', 0, 0]]], ['illegal', 5]], [[4, [['B', 1, 1], ['W', 0, 2], ['B', 2, 3], ['W', 'pass'], ['B', 1, 1], ['W', 0, 2], ['B', 0, 3], ['W', 2, 0], ['B', 2, 2], ['W', 3, 0], ['B', 3, 0]]], ['illegal', 4]], [[3, [['B', 0, 0], ['W', 2, 2], ['B', 2, 1], ['W', 2, 2], ['B', 1, 2], ['W', 2, 2], ['B', 1, 0]]], ['illegal', 3]], [[3, [['B', 1, 2], ['W', 2, 0], ['B', 1, 0], ['W', 0, 1], ['B', 2, 2], ['W', 2, 2], ['B', 1, 2], ['W', 2, 0], ['B', 'pass'], ['W', 2, 0], ['B', 2, 1], ['W', 2, 0], ['B', 0, 2], ['W', 0, 1], ['B', 2, 2]]], ['illegal', 5]], [[3, [['B', 'pass'], ['W', 1, 2], ['B', 0, 0], ['W', 1, 1], ['B', 0, 2], ['W', 0, 1], ['B', 'pass'], ['W', 'pass']]], [0, 1, ['BW.', '.WW', '...']]], [[4, [['B', 3, 2], ['W', 2, 3], ['B', 2, 0], ['W', 1, 0], ['B', 0, 0], ['W', 2, 0], ['B', 'pass'], ['W', 0, 1], ['B', 2, 0]]], ['illegal', 5]], [[3, [['W', 0, 1], ['B', 0, 0], ['W', 1, 0], ['B', 'pass'], ['W', 2, 2]]], [0, 1, ['.W.', 'W..', '..W']]]], [[[3, [['B', 'pass'], ['W', 1, 2], ['B', 0, 0], ['W', 1, 1], ['B', 0, 2], ['W', 0, 1], ['B', 'pass'], ['W', 'pass']]], [0, 1, ['BW.', '.WW', '...']]], [[4, [['B', 0, 3], ['W', 'pass'], ['B', 3, 1], ['W', 3, 3], ['B', 3, 1], ['W', 0, 3], ['B', 1, 3], ['W', 'pass'], ['B', 3, 2], ['W', 'pass'], ['B', 3, 1], ['W', 0, 2], ['B', 3, 0]]], ['illegal', 4]], [[3, [['B', 1, 1], ['W', 2, 1], ['B', 2, 0], ['W', 0, 2], ['B', 0, 2], ['W', 0, 0], ['B', 2, 2], ['W', 2, 0], ['B', 2, 2], ['W', 0, 2], ['B', 2, 2], ['W', 2, 0]]], ['illegal', 4]], [[3, [['B', 1, 0], ['W', 0, 1], ['B', 0, 1], ['W', 0, 2], ['B', 2, 0], ['W', 1, 0], ['B', 0, 0], ['W', 2, 1], ['B', 2, 2], ['W', 2, 0], ['B', 1, 1], ['W', 0, 2], ['B', 1, 1], ['W', 0, 2]]], ['illegal', 2]], [[4, [['B', 0, 3], ['W', 3, 3], ['B', 1, 2], ['W', 0, 1], ['B', 3, 0]]], [0, 0, ['.W.B', '..B.', '....', 'B..W']]], [[4, [['B', 3, 0], ['W', 0, 3], ['B', 0, 2]]], [0, 0, ['..BW', '....', '....', 'B...']]], [[3, [['B', 0, 0], ['W', 1, 1], ['B', 0, 0], ['W', 'pass'], ['B', 0, 0], ['W', 2, 1], ['B', 2, 2], ['W', 2, 1], ['B', 1, 1]]], ['illegal', 2]], [[4, [['B', 2, 3], ['W', 0, 2], ['B', 1, 3], ['W', 'pass'], ['B', 1, 0], ['W', 2, 1], ['B', 3, 0], ['W', 1, 1]]], [0, 0, ['..W.', 'BW.B', '.W.B', 'B...']]]], [[[3, [['B', 2, 2], ['W', 1, 1], ['B', 1, 0], ['W', 2, 1], ['B', 0, 2]]], [0, 0, ['..B', 'BW.', '.WB']]], [[3, [['B', 0, 2], ['W', 0, 1], ['B', 1, 1], ['W', 2, 2], ['B', 0, 2], ['W', 'pass'], ['B', 1, 1], ['W', 'pass'], ['B', 0, 2], ['W', 2, 1], ['B', 'pass'], ['W', 0, 0], ['B', 'pass']]], ['illegal', 4]], [[3, [['B', 1, 1], ['W', 1, 2], ['B', 0, 2]]], [0, 0, ['..B', '.BW', '...']]], [[3, [['B', 2, 1], ['W', 'pass'], ['B', 'pass'], ['W', 0, 0], ['B', 1, 1], ['W', 0, 2], ['B', 0, 2], ['W', 2, 2], ['B', 0, 1]]], ['illegal', 6]], [[3, [['B', 2, 0], ['W', 0, 1], ['B', 1, 0], ['W', 1, 1], ['B', 2, 0], ['W', 1, 0], ['B', 0, 0], ['W', 'pass']]], ['illegal', 4]], [[4, [['B', 2, 3], ['W', 0, 2], ['B', 1, 3], ['W', 'pass'], ['B', 1, 0], ['W', 2, 1], ['B', 3, 0], ['W', 1, 1]]], [0, 0, ['..W.', 'BW.B', '.W.B', 'B...']]], [[4, [['B', 2, 1], ['W', 2, 0], ['B', 2, 1], ['W', 2, 3], ['B', 'pass'], ['W', 0, 0], ['B', 3, 1], ['W', 3, 2], ['B', 1, 1], ['W', 1, 1]]], ['illegal', 2]], [[4, [['B', 3, 0], ['W', 'pass'], ['B', 'pass']]], [0, 0, ['....', '....', '....', 'B...']]]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("replay 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)

prompt:
Moves after an early pass are ignored.

Input [size, moves]; each move is [colour, row, col] or [colour, "pass"]. Replay with captures; captured stones are prisoners of the mover; occupied or suicidal moves stop replay with ["illegal", index]. Return [prisoners_B, prisoners_W, final_board_rows].

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    size, moves = x
    g = [['.'] * size for _ in range(size)]
    pris = {'B': 0, 'W': 0}
    def chain(i, j):
        col = g[i][j]
        seen = {(i, j)}
        todo = [(i, j)]
        libs = 0
        while todo:
            a, b = todo.pop()
            for p, q in ((a - 1, b), (a, b + 1), (a + 1, b), (a, b - 1)):
                if 0 <= p < size and 0 <= q < size:
                    if g[p][q] == '.':
                        libs += 1
                    elif g[p][q] == col and (p, q) not in seen:
                        seen.add((p, q))
                        todo.append((p, q))
        return seen, libs
    for idx, mv in enumerate(moves):
        if mv[1] == 'pass':
            continue
        col, r, c = mv
        if g[r][c] != '.':
            return ['illegal', idx]
        g[r][c] = col
        opp = 'B' if col == 'W' else 'W'
        for p, q in ((r - 1, c), (r, c + 1), (r + 1, c), (r, c - 1)):
            if 0 <= p < size and 0 <= q < size and g[p][q] == opp:
                dead, libs = chain(p, q)
                if libs == 0:
                    for s, t in dead:
                        g[s][t] = '.'
                    pris[col] += len(dead)
    return [pris['B'], pris['W'], [''.join(row) for row in g]]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[4, [['B', 3, 0], ['W', 2, 3], ['B', 'pass']]], [0, 0, ['....', '....', '...W', 'B...']]], [[4, [['B', 2, 0], ['W', 3, 1], ['B', 2, 0], ['W', 0, 1], ['B', 2, 0], ['W', 1, 3], ['B', 'pass'], ['W', 0, 1], ['B', 2, 3], ['W', 1, 2], ['B', 1, 1], ['W', 1, 0]]], ['illegal', 2]], [[3, [['B', 1, 1], ['W', 0, 1], ['B', 1, 1], ['W', 1, 1], ['B', 'pass'], ['W', 1, 1], ['B', 2, 0], ['W', 2, 2], ['B', 2, 0], ['W', 1, 1], ['B', 2, 2], ['W', 0, 0], ['B', 'pass'], ['W', 0, 2], ['B', 2, 1]]], ['illegal', 2]], [[3, [['B', 0, 1], ['W', 1, 0], ['B', 2, 1], ['W', 1, 0], ['B', 'pass'], ['W', 0, 0], ['B', 1, 1], ['W', 1, 1], ['B', 1, 1], ['W', 1, 2], ['B', 2, 0], ['W', 1, 1], ['B', 2, 2], ['W', 2, 1], ['B', 0, 0]]], ['illegal', 3]], [[4, [['B', 3, 0], ['W', 2, 1], ['B', 3, 1], ['W', 3, 0], ['B', 0, 0], ['W', 1, 0], ['B', 'pass']]], ['illegal', 3]], [[4, [['B', 0, 3], ['W', 0, 2], ['B', 2, 0], ['W', 1, 3], ['B', 2, 3], ['W', 'pass'], ['B', 0, 1], ['W', 1, 0], ['B', 0, 2], ['W', 1, 0], ['B', 2, 1], ['W', 3, 0]]], ['illegal', 8]], [[3, [['B', 2, 0], ['W', 2, 1], ['B', 1, 1], ['W', 1, 0], ['B', 'pass'], ['W', 0, 0], ['B', 2, 0]]], ['illegal', 6]], [[3, [['B', 2, 0], ['W', 2, 1], ['B', 1, 1], ['W', 1, 0], ['B', 'pass'], ['W', 0, 0], ['B', 2, 0]]], ['illegal', 6]]], [[[3, [['B', 0, 1], ['W', 2, 0], ['B', 1, 1], ['W', 1, 2], ['B', 0, 0], ['W', 2, 1], ['B', 2, 1], ['W', 'pass'], ['B', 0, 2], ['W', 1, 1], ['B', 1, 2], ['W', 0, 0], ['B', 'pass']]], ['illegal', 6]], [[4, [['B', 2, 0], ['W', 0, 2], ['B', 1, 1], ['W', 3, 0], ['B', 3, 2]]], [0, 0, ['..W.', '.B..', 'B...', 'W.B.']]], [[3, [['B', 2, 1], ['W', 2, 1], ['B', 1, 2], ['W', 2, 2], ['B', 0, 2], ['W', 0, 0], ['B', 1, 1], ['W', 0, 1], ['B', 0, 2]]], ['illegal', 1]], [[4, [['B', 0, 1], ['W', 'pass'], ['B', 1, 3], ['W', 2, 3], ['B', 0, 2], ['W', 2, 0], ['B', 2, 0], ['W', 1, 1], ['B', 'pass'], ['W', 1, 2], ['B', 1, 0], ['W', 3, 2]]], ['illegal', 6]], [[3, [['B', 1, 0], ['W', 2, 2], ['B', 'pass'], ['W', 1, 0], ['B', 1, 2]]], ['illegal', 3]], [[4, [['B', 1, 0], ['W', 2, 0], ['B', 1, 3], ['W', 0, 0], ['B', 1, 1], ['W', 2, 2], ['B', 3, 1], ['W', 1, 2], ['B', 0, 0], ['W', 0, 2], ['B', 1, 0], ['W', 0, 0]]], ['illegal', 8]], [[2, [['B', 0, 1], ['W', 'pass'], ['B', 1, 0], ['W', 0, 0]]], ['illegal', 3]], [[2, [['B', 0, 1], ['W', 'pass'], ['B', 1, 0], ['W', 0, 0]]], ['illegal', 3]]], [[[3, [['B', 2, 0], ['W', 1, 1], ['B', 'pass'], ['W', 2, 1], ['B', 0, 1], ['W', 1, 1]]], ['illegal', 5]], [[4, [['B', 3, 1], ['W', 1, 3], ['B', 2, 3], ['W', 2, 0], ['B', 0, 1], ['W', 1, 3], ['B', 'pass'], ['W', 0, 0], ['B', 3, 0], ['W', 'pass'], ['B', 'pass'], ['W', 1, 1], ['B', 0, 2], ['W', 'pass'], ['B', 0, 0]]], ['illegal', 5]], [[4, [['B', 1, 1], ['W', 0, 2], ['B', 2, 3], ['W', 'pass'], ['B', 1, 1], ['W', 0, 2], ['B', 0, 3], ['W', 2, 0], ['B', 2, 2], ['W', 3, 0], ['B', 3, 0]]], ['illegal', 4]], [[3, [['B', 0, 0], ['W', 2, 2], ['B', 2, 1], ['W', 2, 2], ['B', 1, 2], ['W', 2, 2], ['B', 1, 0]]], ['illegal', 3]], [[3, [['B', 1, 2], ['W', 2, 0], ['B', 1, 0], ['W', 0, 1], ['B', 2, 2], ['W', 2, 2], ['B', 1, 2], ['W', 2, 0], ['B', 'pass'], ['W', 2, 0], ['B', 2, 1], ['W', 2, 0], ['B', 0, 2], ['W', 0, 1], ['B', 2, 2]]], ['illegal', 5]], [[3, [['B', 'pass'], ['W', 1, 2], ['B', 0, 0], ['W', 1, 1], ['B', 0, 2], ['W', 0, 1], ['B', 'pass'], ['W', 'pass']]], [0, 1, ['BW.', '.WW', '...']]], [[3, [['B', 2, 0], ['W', 2, 1], ['B', 1, 1], ['W', 1, 0], ['B', 'pass'], ['W', 0, 0], ['B', 2, 0]]], ['illegal', 6]], [[3, [['B', 2, 0], ['W', 2, 1], ['B', 1, 1], ['W', 1, 0], ['B', 'pass'], ['W', 0, 0], ['B', 2, 0]]], ['illegal', 6]]], [[[4, [['B', 'pass'], ['W', 1, 0], ['B', 2, 3], ['W', 3, 2], ['B', 1, 3]]], [0, 0, ['....', 'W..B', '...B', '..W.']]], [[4, [['B', 0, 3], ['W', 'pass'], ['B', 3, 1], ['W', 3, 3], ['B', 3, 1], ['W', 0, 3], ['B', 1, 3], ['W', 'pass'], ['B', 3, 2], ['W', 'pass'], ['B', 3, 1], ['W', 0, 2], ['B', 3, 0]]], ['illegal', 4]], [[3, [['B', 1, 1], ['W', 2, 1], ['B', 2, 0], ['W', 0, 2], ['B', 0, 2], ['W', 0, 0], ['B', 2, 2], ['W', 2, 0], ['B', 2, 2], ['W', 0, 2], ['B', 2, 2], ['W', 2, 0]]], ['illegal', 4]], [[3, [['B', 1, 0], ['W', 0, 1], ['B', 0, 1], ['W', 0, 2], ['B', 2, 0], ['W', 1, 0], ['B', 0, 0], ['W', 2, 1], ['B', 2, 2], ['W', 2, 0], ['B', 1, 1], ['W', 0, 2], ['B', 1, 1], ['W', 0, 2]]], ['illegal', 2]], [[4, [['B', 0, 3], ['W', 3, 3], ['B', 1, 2], ['W', 0, 1], ['B', 3, 0]]], [0, 0, ['.W.B', '..B.', '....', 'B..W']]], [[4, [['B', 3, 0], ['W', 0, 3], ['B', 0, 2]]], [0, 0, ['..BW', '....', '....', 'B...']]], [[2, [['B', 0, 1], ['W', 'pass'], ['B', 1, 0], ['W', 0, 0]]], ['illegal', 3]], [[2, [['B', 0, 1], ['W', 'pass'], ['B', 1, 0], ['W', 0, 0]]], ['illegal', 3]]], [[[3, [['B', 2, 2], ['W', 1, 1], ['B', 1, 0], ['W', 2, 1], ['B', 0, 2]]], [0, 0, ['..B', 'BW.', '.WB']]], [[3, [['B', 0, 2], ['W', 0, 1], ['B', 1, 1], ['W', 2, 2], ['B', 0, 2], ['W', 'pass'], ['B', 1, 1], ['W', 'pass'], ['B', 0, 2], ['W', 2, 1], ['B', 'pass'], ['W', 0, 0], ['B', 'pass']]], ['illegal', 4]], [[3, [['B', 1, 1], ['W', 1, 2], ['B', 0, 2]]], [0, 0, ['..B', '.BW', '...']]], [[3, [['B', 2, 1], ['W', 'pass'], ['B', 'pass'], ['W', 0, 0], ['B', 1, 1], ['W', 0, 2], ['B', 0, 2], ['W', 2, 2], ['B', 0, 1]]], ['illegal', 6]], [[3, [['B', 2, 0], ['W', 0, 1], ['B', 1, 0], ['W', 1, 1], ['B', 2, 0], ['W', 1, 0], ['B', 0, 0], ['W', 'pass']]], ['illegal', 4]], [[4, [['B', 2, 3], ['W', 0, 2], ['B', 1, 3], ['W', 'pass'], ['B', 1, 0], ['W', 2, 1], ['B', 3, 0], ['W', 1, 1]]], [0, 0, ['..W.', 'BW.B', '.W.B', 'B...']]], [[3, [['B', 2, 0], ['W', 2, 1], ['B', 1, 1], ['W', 1, 0], ['B', 'pass'], ['W', 0, 0], ['B', 2, 0]]], ['illegal', 6]], [[3, [['B', 2, 0], ['W', 2, 1], ['B', 1, 1], ['W', 1, 0], ['B', 'pass'], ['W', 0, 0], ['B', 2, 0]]], ['illegal', 6]]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("replay 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)

source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    size, moves = x
    g = [['.'] * size for _ in range(size)]
    pris = {'B': 0, 'W': 0}
    def chain(i, j):
        col = g[i][j]
        seen = {(i, j)}
        todo = [(i, j)]
        libs = 0
        while todo:
            a, b = todo.pop()
            for p, q in ((a - 1, b), (a, b + 1), (a + 1, b), (a, b - 1)):
                if 0 <= p < size and 0 <= q < size:
                    if g[p][q] == '.':
                        libs += 1
                    elif g[p][q] == col and (p, q) not in seen:
                        seen.add((p, q))
                        todo.append((p, q))
        return seen, libs
    for idx, mv in enumerate(moves):
        if mv[1] == 'pass':
            continue
        col, r, c = mv
        if g[r][c] != '.':
            return ['illegal', idx]
        g[r][c] = col
        opp = 'B' if col == 'W' else 'W'
        for p, q in ((r - 1, c), (r, c + 1), (r + 1, c), (r, c - 1)):
            if 0 <= p < size and 0 <= q < size and g[p][q] == opp:
                dead, libs = chain(p, q)
                if libs == 0:
                    for s, t in dead:
                        g[s][t] = '.'
                    pris[col] += len(dead)
        own, libs = chain(r, c)
        if libs == 0:
            for s, t in own:
                g[s][t] = '.'
            pris[opp] += len(own)
    return [pris['B'], pris['W'], [''.join(row) for row in g]]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[4, [['B', 3, 0], ['W', 2, 3], ['B', 'pass']]], [0, 0, ['....', '....', '...W', 'B...']]], [[4, [['B', 2, 0], ['W', 3, 1], ['B', 2, 0], ['W', 0, 1], ['B', 2, 0], ['W', 1, 3], ['B', 'pass'], ['W', 0, 1], ['B', 2, 3], ['W', 1, 2], ['B', 1, 1], ['W', 1, 0]]], ['illegal', 2]], [[3, [['B', 1, 1], ['W', 0, 1], ['B', 1, 1], ['W', 1, 1], ['B', 'pass'], ['W', 1, 1], ['B', 2, 0], ['W', 2, 2], ['B', 2, 0], ['W', 1, 1], ['B', 2, 2], ['W', 0, 0], ['B', 'pass'], ['W', 0, 2], ['B', 2, 1]]], ['illegal', 2]], [[3, [['B', 0, 1], ['W', 1, 0], ['B', 2, 1], ['W', 1, 0], ['B', 'pass'], ['W', 0, 0], ['B', 1, 1], ['W', 1, 1], ['B', 1, 1], ['W', 1, 2], ['B', 2, 0], ['W', 1, 1], ['B', 2, 2], ['W', 2, 1], ['B', 0, 0]]], ['illegal', 3]], [[4, [['B', 3, 0], ['W', 2, 1], ['B', 3, 1], ['W', 3, 0], ['B', 0, 0], ['W', 1, 0], ['B', 'pass']]], ['illegal', 3]], [[4, [['B', 0, 3], ['W', 0, 2], ['B', 2, 0], ['W', 1, 3], ['B', 2, 3], ['W', 'pass'], ['B', 0, 1], ['W', 1, 0], ['B', 0, 2], ['W', 1, 0], ['B', 2, 1], ['W', 3, 0]]], ['illegal', 8]], [[3, [['B', 2, 0], ['W', 2, 1], ['B', 1, 1], ['W', 1, 0], ['B', 'pass'], ['W', 0, 0], ['B', 2, 0]]], ['illegal', 6]], [[3, [['B', 2, 0], ['W', 2, 1], ['B', 1, 1], ['W', 1, 0], ['B', 'pass'], ['W', 0, 0], ['B', 2, 0]]], ['illegal', 6]]], [[[3, [['B', 0, 1], ['W', 2, 0], ['B', 1, 1], ['W', 1, 2], ['B', 0, 0], ['W', 2, 1], ['B', 2, 1], ['W', 'pass'], ['B', 0, 2], ['W', 1, 1], ['B', 1, 2], ['W', 0, 0], ['B', 'pass']]], ['illegal', 6]], [[4, [['B', 2, 0], ['W', 0, 2], ['B', 1, 1], ['W', 3, 0], ['B', 3, 2]]], [0, 0, ['..W.', '.B..', 'B...', 'W.B.']]], [[3, [['B', 2, 1], ['W', 2, 1], ['B', 1, 2], ['W', 2, 2], ['B', 0, 2], ['W', 0, 0], ['B', 1, 1], ['W', 0, 1], ['B', 0, 2]]], ['illegal', 1]], [[4, [['B', 0, 1], ['W', 'pass'], ['B', 1, 3], ['W', 2, 3], ['B', 0, 2], ['W', 2, 0], ['B', 2, 0], ['W', 1, 1], ['B', 'pass'], ['W', 1, 2], ['B', 1, 0], ['W', 3, 2]]], ['illegal', 6]], [[3, [['B', 1, 0], ['W', 2, 2], ['B', 'pass'], ['W', 1, 0], ['B', 1, 2]]], ['illegal', 3]], [[4, [['B', 1, 0], ['W', 2, 0], ['B', 1, 3], ['W', 0, 0], ['B', 1, 1], ['W', 2, 2], ['B', 3, 1], ['W', 1, 2], ['B', 0, 0], ['W', 0, 2], ['B', 1, 0], ['W', 0, 0]]], ['illegal', 8]], [[2, [['B', 0, 1], ['W', 'pass'], ['B', 1, 0], ['W', 0, 0]]], ['illegal', 3]], [[2, [['B', 0, 1], ['W', 'pass'], ['B', 1, 0], ['W', 0, 0]]], ['illegal', 3]]], [[[3, [['B', 2, 0], ['W', 1, 1], ['B', 'pass'], ['W', 2, 1], ['B', 0, 1], ['W', 1, 1]]], ['illegal', 5]], [[4, [['B', 3, 1], ['W', 1, 3], ['B', 2, 3], ['W', 2, 0], ['B', 0, 1], ['W', 1, 3], ['B', 'pass'], ['W', 0, 0], ['B', 3, 0], ['W', 'pass'], ['B', 'pass'], ['W', 1, 1], ['B', 0, 2], ['W', 'pass'], ['B', 0, 0]]], ['illegal', 5]], [[4, [['B', 1, 1], ['W', 0, 2], ['B', 2, 3], ['W', 'pass'], ['B', 1, 1], ['W', 0, 2], ['B', 0, 3], ['W', 2, 0], ['B', 2, 2], ['W', 3, 0], ['B', 3, 0]]], ['illegal', 4]], [[3, [['B', 0, 0], ['W', 2, 2], ['B', 2, 1], ['W', 2, 2], ['B', 1, 2], ['W', 2, 2], ['B', 1, 0]]], ['illegal', 3]], [[3, [['B', 1, 2], ['W', 2, 0], ['B', 1, 0], ['W', 0, 1], ['B', 2, 2], ['W', 2, 2], ['B', 1, 2], ['W', 2, 0], ['B', 'pass'], ['W', 2, 0], ['B', 2, 1], ['W', 2, 0], ['B', 0, 2], ['W', 0, 1], ['B', 2, 2]]], ['illegal', 5]], [[3, [['B', 'pass'], ['W', 1, 2], ['B', 0, 0], ['W', 1, 1], ['B', 0, 2], ['W', 0, 1], ['B', 'pass'], ['W', 'pass']]], [0, 1, ['BW.', '.WW', '...']]], [[3, [['B', 2, 0], ['W', 2, 1], ['B', 1, 1], ['W', 1, 0], ['B', 'pass'], ['W', 0, 0], ['B', 2, 0]]], ['illegal', 6]], [[3, [['B', 2, 0], ['W', 2, 1], ['B', 1, 1], ['W', 1, 0], ['B', 'pass'], ['W', 0, 0], ['B', 2, 0]]], ['illegal', 6]]], [[[4, [['B', 'pass'], ['W', 1, 0], ['B', 2, 3], ['W', 3, 2], ['B', 1, 3]]], [0, 0, ['....', 'W..B', '...B', '..W.']]], [[4, [['B', 0, 3], ['W', 'pass'], ['B', 3, 1], ['W', 3, 3], ['B', 3, 1], ['W', 0, 3], ['B', 1, 3], ['W', 'pass'], ['B', 3, 2], ['W', 'pass'], ['B', 3, 1], ['W', 0, 2], ['B', 3, 0]]], ['illegal', 4]], [[3, [['B', 1, 1], ['W', 2, 1], ['B', 2, 0], ['W', 0, 2], ['B', 0, 2], ['W', 0, 0], ['B', 2, 2], ['W', 2, 0], ['B', 2, 2], ['W', 0, 2], ['B', 2, 2], ['W', 2, 0]]], ['illegal', 4]], [[3, [['B', 1, 0], ['W', 0, 1], ['B', 0, 1], ['W', 0, 2], ['B', 2, 0], ['W', 1, 0], ['B', 0, 0], ['W', 2, 1], ['B', 2, 2], ['W', 2, 0], ['B', 1, 1], ['W', 0, 2], ['B', 1, 1], ['W', 0, 2]]], ['illegal', 2]], [[4, [['B', 0, 3], ['W', 3, 3], ['B', 1, 2], ['W', 0, 1], ['B', 3, 0]]], [0, 0, ['.W.B', '..B.', '....', 'B..W']]], [[4, [['B', 3, 0], ['W', 0, 3], ['B', 0, 2]]], [0, 0, ['..BW', '....', '....', 'B...']]], [[2, [['B', 0, 1], ['W', 'pass'], ['B', 1, 0], ['W', 0, 0]]], ['illegal', 3]], [[2, [['B', 0, 1], ['W', 'pass'], ['B', 1, 0], ['W', 0, 0]]], ['illegal', 3]]], [[[3, [['B', 2, 2], ['W', 1, 1], ['B', 1, 0], ['W', 2, 1], ['B', 0, 2]]], [0, 0, ['..B', 'BW.', '.WB']]], [[3, [['B', 0, 2], ['W', 0, 1], ['B', 1, 1], ['W', 2, 2], ['B', 0, 2], ['W', 'pass'], ['B', 1, 1], ['W', 'pass'], ['B', 0, 2], ['W', 2, 1], ['B', 'pass'], ['W', 0, 0], ['B', 'pass']]], ['illegal', 4]], [[3, [['B', 1, 1], ['W', 1, 2], ['B', 0, 2]]], [0, 0, ['..B', '.BW', '...']]], [[3, [['B', 2, 1], ['W', 'pass'], ['B', 'pass'], ['W', 0, 0], ['B', 1, 1], ['W', 0, 2], ['B', 0, 2], ['W', 2, 2], ['B', 0, 1]]], ['illegal', 6]], [[3, [['B', 2, 0], ['W', 0, 1], ['B', 1, 0], ['W', 1, 1], ['B', 2, 0], ['W', 1, 0], ['B', 0, 0], ['W', 'pass']]], ['illegal', 4]], [[4, [['B', 2, 3], ['W', 0, 2], ['B', 1, 3], ['W', 'pass'], ['B', 1, 0], ['W', 2, 1], ['B', 3, 0], ['W', 1, 1]]], [0, 0, ['..W.', 'BW.B', '.W.B', 'B...']]], [[3, [['B', 2, 0], ['W', 2, 1], ['B', 1, 1], ['W', 1, 0], ['B', 'pass'], ['W', 0, 0], ['B', 2, 0]]], ['illegal', 6]], [[3, [['B', 2, 0], ['W', 2, 1], ['B', 1, 1], ['W', 1, 0], ['B', 'pass'], ['W', 0, 0], ['B', 2, 0]]], ['illegal', 6]]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("replay 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)

prompt:
A libertyless chain remains on the replay board.

Input [size, moves]; each move is [colour, row, col] or [colour, "pass"]. Replay with captures; captured stones are prisoners of the mover; occupied or suicidal moves stop replay with ["illegal", index]. Return [prisoners_B, prisoners_W, final_board_rows].

split: open-access


prompt:
The estimate shrinks every moyo by one ring.

Input [board, reach]. Each empty point belongs to the colour of the strictly nearest stones by Manhattan distance, provided that distance <= reach; ties between colours or no stone in reach leave it neutral. Return [black_points, white_points].

split: open-access


prompt:
Boundary points are assigned by scan order.

Input [board, reach]. Each empty point belongs to the colour of the strictly nearest stones by Manhattan distance, provided that distance <= reach; ties between colours or no stone in reach leave it neutral. Return [black_points, white_points].

split: open-access


prompt:
Estimated territory extends diagonally past the intended shape.

Input [board, reach]. Each empty point belongs to the colour of the strictly nearest stones by Manhattan distance, provided that distance <= reach; ties between colours or no stone in reach leave it neutral. Return [black_points, white_points].

split: open-access


prompt:
Each side loses territory for stones it captured.

Input [terr_b, terr_w, prisoners_taken_by_b, prisoners_taken_by_w, komi_tenths]. Prisoners are filled into the opponent territory. Return [remaining_b, remaining_w, result] with result "B+x.y", "W+x.y" or "Jigo".

split: open-access


prompt:
A 6.5 komi is applied as 65 points.

Input [terr_b, terr_w, prisoners_taken_by_b, prisoners_taken_by_w, komi_tenths]. Prisoners are filled into the opponent territory. Return [remaining_b, remaining_w, result] with result "B+x.y", "W+x.y" or "Jigo".

split: open-access


prompt:
Players who marked the same stones in a different order are sent back to dispute.

Input [black_proposal, white_proposal] as lists of points (any order, duplicates allowed). Equal point sets -> ["agree", sorted points]; otherwise ["dispute", sorted symmetric difference].

split: open-access


prompt:
Stones only white marked are omitted from the dispute list.

Input [black_proposal, white_proposal] as lists of points (any order, duplicates allowed). Equal point sets -> ["agree", sorted points]; otherwise ["dispute", sorted symmetric difference].

split: open-access


prompt:
Agreed results carry duplicates and caller order.

Input [black_proposal, white_proposal] as lists of points (any order, duplicates allowed). Equal point sets -> ["agree", sorted points]; otherwise ["dispute", sorted symmetric difference].

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    s = x.strip()
    neg = s.startswith('-')
    if s[:1] in '+-' and s:
        s = s[1:]
    half = 0
    if s.endswith('½'):
        half = 5
        s = s[:-1]
    elif '.' in s:
        s, _, frac = s.partition('.')
        if frac not in ('0', '5'):
            return 'invalid'
        half = int(frac)
    if not s.isdigit():
        if s == '' and half:
            s = '0'
        else:
            return 'invalid'
    v = int(s) * 10 + half
    return v
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['-0.5', -5], ['-0.5', -5], ['+5.5', 55], ['7.0', 70], ['6.3', 'invalid'], ['.5', 5], ['', 'invalid'], ['-', 'invalid']], [['abc', 'invalid'], ['5.', 'invalid'], [' 6.5 ', 65], ['-3', -30], ['-7.5', -75], ['-7.5', -75], ['0.0', 0], ['1 1/2', 'invalid']], [['6.5', 65], ['7', 70], ['-0.5', -5], ['-6½', -65], ['-3', -30], ['6.50', 'invalid'], ['+', 'invalid'], ['+½', 5]], [['-0.5', -5], ['½', 5], ['-6½', -65], ['0', 0], ['+5.5', 55], ['7.0', 70], ['6.3', 'invalid'], ['.5', 5]], [['-0.5', -5], ['', 'invalid'], ['-', 'invalid'], ['abc', 'invalid'], ['5.', 'invalid'], [' 6.5 ', 65], ['-3', -30], ['-7.5', -75]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("komi 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)

source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    s = x.strip()
    neg = s.startswith('-')
    if s[:1] in '+-' and s:
        s = s[1:]
    half = 0
    if s.endswith('½'):
        half = 5
        s = s[:-1]
    elif '.' in s:
        s, _, frac = s.partition('.')
        if frac not in ('0', '5'):
            return 'invalid'
        half = int(frac)
    if not s.isdigit():
        if s == '' and half:
            s = '0'
        else:
            return 'invalid'
    v = int(s) * 10 + half
    return -int(s) * 10 + half if neg else v
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['-0.5', -5], ['-0.5', -5], ['+5.5', 55], ['7.0', 70], ['6.3', 'invalid'], ['.5', 5], ['', 'invalid'], ['-', 'invalid']], [['abc', 'invalid'], ['5.', 'invalid'], [' 6.5 ', 65], ['-3', -30], ['-7.5', -75], ['-7.5', -75], ['0.0', 0], ['1 1/2', 'invalid']], [['6.5', 65], ['7', 70], ['-0.5', -5], ['-6½', -65], ['-3', -30], ['6.50', 'invalid'], ['+', 'invalid'], ['+½', 5]], [['-0.5', -5], ['½', 5], ['-6½', -65], ['0', 0], ['+5.5', 55], ['7.0', 70], ['6.3', 'invalid'], ['.5', 5]], [['-0.5', -5], ['', 'invalid'], ['-', 'invalid'], ['abc', 'invalid'], ['5.', 'invalid'], [' 6.5 ', 65], ['-3', -30], ['-7.5', -75]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("komi 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)

prompt:
Reverse komi of -6.5 is applied as +6.5.

Input a komi string: optional sign, whole points, and an optional half written ".5"/".0" or "½". A bare half ("½", ".5") is allowed. Return komi in tenths or "invalid".

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    s = x.strip()
    neg = s.startswith('-')
    if s[:1] in '+-' and s:
        s = s[1:]
    half = 0
    if s.endswith('1/2'):
        half = 5
        s = s[:-1]
    elif '.' in s:
        s, _, frac = s.partition('.')
        if frac not in ('0', '5'):
            return 'invalid'
        half = int(frac)
    if not s.isdigit():
        if s == '' and half:
            s = '0'
        else:
            return 'invalid'
    v = int(s) * 10 + half
    return -v if neg else v
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['6½', 65], ['-6½', -65], ['7.0', 70], ['6.3', 'invalid'], ['.5', 5], ['', 'invalid'], ['-', 'invalid'], ['abc', 'invalid']], [['abc', 'invalid'], ['5.', 'invalid'], [' 6.5 ', 65], ['-3', -30], ['-7.5', -75], ['0.0', 0], ['+½', 5], ['+½', 5]], [['6.5', 65], ['7', 70], ['-0.5', -5], ['6½', 65], ['-6½', -65], ['6.50', 'invalid'], ['+', 'invalid'], ['+½', 5]], [['0.5', 5], ['6½', 65], ['½', 5], ['½', 5], ['-6½', -65], ['0', 0], ['+5.5', 55], ['7.0', 70]], [['6½', 65], ['-6½', -65], ['-', 'invalid'], ['abc', 'invalid'], ['5.', 'invalid'], [' 6.5 ', 65], ['-3', -30], ['-7.5', -75]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("komi 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)

source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    s = x.strip()
    neg = s.startswith('-')
    if s[:1] in '+-' and s:
        s = s[1:]
    half = 0
    if s.endswith('½'):
        half = 5
    elif '.' in s:
        s, _, frac = s.partition('.')
        if frac not in ('0', '5'):
            return 'invalid'
        half = int(frac)
    if not s.isdigit():
        if s == '' and half:
            s = '0'
        else:
            return 'invalid'
    v = int(s) * 10 + half
    return -v if neg else v
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['6½', 65], ['-6½', -65], ['7.0', 70], ['6.3', 'invalid'], ['.5', 5], ['', 'invalid'], ['-', 'invalid'], ['abc', 'invalid']], [['abc', 'invalid'], ['5.', 'invalid'], [' 6.5 ', 65], ['-3', -30], ['-7.5', -75], ['0.0', 0], ['+½', 5], ['+½', 5]], [['6.5', 65], ['7', 70], ['-0.5', -5], ['6½', 65], ['-6½', -65], ['6.50', 'invalid'], ['+', 'invalid'], ['+½', 5]], [['0.5', 5], ['6½', 65], ['½', 5], ['½', 5], ['-6½', -65], ['0', 0], ['+5.5', 55], ['7.0', 70]], [['6½', 65], ['-6½', -65], ['-', 'invalid'], ['abc', 'invalid'], ['5.', 'invalid'], [' 6.5 ', 65], ['-3', -30], ['-7.5', -75]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("komi 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)

prompt:
Komi written as 6½ is rejected.

Input a komi string: optional sign, whole points, and an optional half written ".5"/".0" or "½". A bare half ("½", ".5") is allowed. Return komi in tenths or "invalid".

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    s = x.strip()
    neg = s.startswith('-')
    if s[:1] in '+-' and s:
        s = s[1:]
    half = 0
    if s.endswith('½'):
        half = 5
        s = s[:-1]
    elif '.' in s:
        s, _, frac = s.partition('.')
        if not frac.isdigit():
            return 'invalid'
        half = int(frac)
    if not s.isdigit():
        if s == '' and half:
            s = '0'
        else:
            return 'invalid'
    v = int(s) * 10 + half
    return -v if neg else v
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['0', 0], ['+5.5', 55], ['7.0', 70], ['6.3', 'invalid'], ['.5', 5], ['', 'invalid'], ['-', 'invalid'], ['abc', 'invalid']], [['abc', 'invalid'], ['5.', 'invalid'], [' 6.5 ', 65], ['-3', -30], ['-7.5', -75], ['0.0', 0], ['1 1/2', 'invalid'], ['6.50', 'invalid']], [['6.5', 65], ['7', 70], ['-0.5', -5], ['7.0', 70], ['6.3', 'invalid'], ['6.50', 'invalid'], ['+', 'invalid'], ['+½', 5]], [['6½', 65], ['½', 5], ['-6½', -65], ['0', 0], ['+5.5', 55], ['7.0', 70], ['0.0', 0], ['6.50', 'invalid']], [['7.0', 70], ['6.3', 'invalid'], ['-', 'invalid'], ['abc', 'invalid'], ['5.', 'invalid'], [' 6.5 ', 65], ['-3', -30], ['-7.5', -75]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("komi 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)

source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    s = x.strip()
    neg = s.startswith('-')
    if s[:1] in '+-' and s:
        s = s[1:]
    half = 0
    if s.endswith('½'):
        half = 5
        s = s[:-1]
    elif '.' in s:
        s, _, frac = s.partition('.')
        if frac not in ('5',):
            return 'invalid'
        half = int(frac)
    if not s.isdigit():
        if s == '' and half:
            s = '0'
        else:
            return 'invalid'
    v = int(s) * 10 + half
    return -v if neg else v
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['0', 0], ['+5.5', 55], ['7.0', 70], ['6.3', 'invalid'], ['.5', 5], ['', 'invalid'], ['-', 'invalid'], ['abc', 'invalid']], [['abc', 'invalid'], ['5.', 'invalid'], [' 6.5 ', 65], ['-3', -30], ['-7.5', -75], ['0.0', 0], ['1 1/2', 'invalid'], ['6.50', 'invalid']], [['6.5', 65], ['7', 70], ['-0.5', -5], ['7.0', 70], ['6.3', 'invalid'], ['6.50', 'invalid'], ['+', 'invalid'], ['+½', 5]], [['6½', 65], ['½', 5], ['-6½', -65], ['0', 0], ['+5.5', 55], ['7.0', 70], ['0.0', 0], ['6.50', 'invalid']], [['7.0', 70], ['6.3', 'invalid'], ['-', 'invalid'], ['abc', 'invalid'], ['5.', 'invalid'], [' 6.5 ', 65], ['-3', -30], ['-7.5', -75]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("komi 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)

prompt:
Komi 6.3 is accepted as 6.3 points.

Input a komi string: optional sign, whole points, and an optional half written ".5"/".0" or "½". A bare half ("½", ".5") is allowed. Return komi in tenths or "invalid".

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    s = x.strip()
    neg = s.startswith('-')
    if s[:1] in '+-' and s:
        s = s[1:]
    half = 0
    if s.endswith('½'):
        half = 5
        s = s[:-1]
    elif '.' in s:
        s, _, frac = s.partition('.')
        if frac not in ('0', '5'):
            return 'invalid'
        half = int(frac)
    if not s.isdigit():
        return 'invalid'
    v = int(s) * 10 + half
    return -v if neg else v
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['½', 5], ['+5.5', 55], ['7.0', 70], ['6.3', 'invalid'], ['.5', 5], ['', 'invalid'], ['-', 'invalid'], ['abc', 'invalid']], [['½', 5], ['5.', 'invalid'], [' 6.5 ', 65], ['-3', -30], ['-7.5', -75], ['0.0', 0], ['1 1/2', 'invalid'], ['+', 'invalid']], [['6.5', 65], ['7', 70], ['-0.5', -5], ['½', 5], ['-', 'invalid'], ['6.50', 'invalid'], ['+', 'invalid'], ['+½', 5]], [['6½', 65], ['½', 5], ['-6½', -65], ['0', 0], ['+5.5', 55], ['7.0', 70], ['6.3', 'invalid'], ['', 'invalid']], [['½', 5], ['', 'invalid'], ['-', 'invalid'], ['abc', 'invalid'], ['5.', 'invalid'], [' 6.5 ', 65], ['-3', -30], ['+', 'invalid']]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("komi 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)

source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    s = x.strip()
    neg = s.startswith('-')
    if s[:1] in '+-' and s:
        s = s[1:]
    half = 0
    if s.endswith('½'):
        half = 5
        s = s[:-1]
    elif '.' in s:
        s, _, frac = s.partition('.')
        if frac not in ('0', '5'):
            return 'invalid'
        half = int(frac)
    if not s.isdigit():
        if s == '':
            s = '0'
        else:
            return 'invalid'
    v = int(s) * 10 + half
    return -v if neg else v
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['½', 5], ['+5.5', 55], ['7.0', 70], ['6.3', 'invalid'], ['.5', 5], ['', 'invalid'], ['-', 'invalid'], ['abc', 'invalid']], [['½', 5], ['5.', 'invalid'], [' 6.5 ', 65], ['-3', -30], ['-7.5', -75], ['0.0', 0], ['1 1/2', 'invalid'], ['+', 'invalid']], [['6.5', 65], ['7', 70], ['-0.5', -5], ['½', 5], ['-', 'invalid'], ['6.50', 'invalid'], ['+', 'invalid'], ['+½', 5]], [['6½', 65], ['½', 5], ['-6½', -65], ['0', 0], ['+5.5', 55], ['7.0', 70], ['6.3', 'invalid'], ['', 'invalid']], [['½', 5], ['', 'invalid'], ['-', 'invalid'], ['abc', 'invalid'], ['5.', 'invalid'], [' 6.5 ', 65], ['-3', -30], ['+', 'invalid']]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("komi 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)

prompt:
½ and .5 are rejected as invalid.

Input a komi string: optional sign, whole points, and an optional half written ".5"/".0" or "½". A bare half ("½", ".5") is allowed. Return komi in tenths or "invalid".

split: open-access


prompt:
Black places more free handicap stones than agreed.

Input [size, count, stones]. Check in order: every stone on the board ("range"), no duplicate ("duplicate"), exactly count stones and 2 <= count <= 9 ("count"). Otherwise "ok".

split: open-access


prompt:
A coordinate equal to size passes validation.

Input [size, count, stones]. Check in order: every stone on the board ("range"), no duplicate ("duplicate"), exactly count stones and 2 <= count <= 9 ("count"). Otherwise "ok".

split: open-access


broken_source:
"""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 board:
        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
    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)

source:
"""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
    for r, c in dd:
        if board[r][c] != '.':
            area[board[r][c]] += 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
    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)

prompt:
A dead group adds its stones to its owner area.

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].

split: open-access


broken_source:
"""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)

source:
"""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)

prompt:
Removing a dead stone gives the capturer an extra point on top of the recovered area.

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].

split: open-access


prompt:
When the leader is late in the rotation the winner is reported as seat 4, 5 or 6.

Input [cards_in_play_order, leader_seat, trump_or_None, seats]. The highest trump wins; with no trump played the highest card of the led suit wins (A high). Off-suit non-trump cards never win. Return the winning seat, counting clockwise from the leader.

split: open-access


prompt:
Discarding an ace of another suit steals a trick won by a lower card of the led suit.

Input [cards_in_play_order, leader_seat, trump_or_None, seats]. The highest trump wins; with no trump played the highest card of the led suit wins (A high). Off-suit non-trump cards never win. Return the winning seat, counting clockwise from the leader.

split: open-access


prompt:
A player who ruffs with a small trump loses to the led ace.

Input [cards_in_play_order, leader_seat, trump_or_None, seats]. The highest trump wins; with no trump played the highest card of the led suit wins (A high). Off-suit non-trump cards never win. Return the winning seat, counting clockwise from the leader.

split: open-access


prompt:
A led ace loses to a deuce of the same suit.

Input [cards_in_play_order, leader_seat, trump_or_None, seats]. The highest trump wins; with no trump played the highest card of the led suit wins (A high). Off-suit non-trump cards never win. Return the winning seat, counting clockwise from the leader.

split: open-access


prompt:
After the first trick a player holding 2C can only lead it.

Input [hand, trick_so_far, hearts_broken, first_trick]. Leading: on the first trick the holder of 2C must lead it; hearts may not be led before they are broken unless the hand is all hearts (QS may be led). Following: follow the led suit if possible; on the first trick a void player may not discard hearts or QS unless nothing else is held. Return legal cards in hand order.

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    hand, trick, broken, first = x
    def penalty(c):
        return c[1] == 'H' or c == 'QS'
    if not trick:
        if first and '2C' in hand:
            return ['2C']
        if not broken:
            safe = [c for c in hand if not penalty(c)]
            if safe:
                return safe
        return list(hand)
    suit = trick[0][1]
    follow = [c for c in hand if c[1] == suit]
    if follow:
        return follow
    if first:
        clean = [c for c in hand if not penalty(c)]
        if clean:
            return clean
    return list(hand)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[['6H', 'AH', 'JC'], ['7S', 'KC'], False, False], ['6H', 'AH', 'JC']], [[['5H', '6C', '7C', '9C', 'KD', 'QC', 'TS'], ['3S', '8S', '2S'], False, True], ['TS']], [[['2C', 'JS'], [], True, True], ['2C']], [[['AS', 'TH'], [], False, True], ['AS']], [[['2C', '8C', 'AS', 'KH'], [], True, False], ['2C', '8C', 'AS', 'KH']], [[['2H', '3C', '3H', 'QC'], [], True, False], ['2H', '3C', '3H', 'QC']], [[['3D', '9H', 'QS'], [], False, False], ['3D', 'QS']], [[['3H'], [], False, False], ['3H']]], [[[['2S', 'KS', 'TH'], ['JC', '2C'], False, True], ['2S', 'KS']], [[['2S'], ['QS'], False, False], ['2S']], [[['2H', '6C', '7H', '9C', '9S'], ['QC', '2C', '6H'], False, False], ['6C', '9C']], [[['3H', '5D', '9D'], ['3C'], True, False], ['3H', '5D', '9D']], [[['AH', 'JH', 'TH'], ['9C', 'TS'], True, False], ['AH', 'JH', 'TH']], [[['2H', '6S', '8D', 'AC', 'JD', 'QH'], ['4H', 'KC', '3S'], True, True], ['2H', 'QH']], [[['2H', '4C', 'AH', 'AS', 'KC', 'QS', 'TS'], [], False, False], ['4C', 'AS', 'KC', 'QS', 'TS']], [[['3H', '5H'], [], False, False], ['3H', '5H']]], [[[['5C'], [], False, True], ['5C']], [[['5D', 'JH'], ['QH', 'KC', '8S'], True, False], ['JH']], [[['4H'], [], True, True], ['4H']], [[['3D', '5C'], [], True, False], ['3D', '5C']], [[['2H', '5H'], ['KS', '9C', '7H'], False, False], ['2H', '5H']], [[['8C', 'AC', 'KD', 'TS'], [], False, True], ['8C', 'AC', 'KD', 'TS']], [[['4H', '6D', '7C', '7S', '9D', 'QS', 'TD'], [], False, True], ['6D', '7C', '7S', '9D', 'QS', 'TD']], [[['4H'], [], False, False], ['4H']]], [[[['2H', '6C', '6D', '7C', 'KS', 'QC'], ['3C', '7D'], True, False], ['6C', '7C', 'QC']], [[['AC'], ['2C', '8D'], False, False], ['AC']], [[['2S', '6D'], [], True, False], ['2S', '6D']], [[['5D', 'AS'], ['5S', '3C'], False, False], ['AS']], [[['3C', '4S', '6S', '7D', '8H', 'AS', 'KC', 'KH'], [], False, False], ['3C', '4S', '6S', '7D', 'AS', 'KC']], [[['2H', '3D', '5H', '9D', 'JC', 'KS', 'QD'], [], False, False], ['3D', '9D', 'JC', 'KS', 'QD']], [[['7H'], [], False, False], ['7H']], [[['QS', 'AD'], [], False, False], ['QS', 'AD']]], [[[['4D', '6S', '9C', 'JD'], ['9H', 'AS', 'KC'], False, True], ['4D', '6S', '9C', 'JD']], [[['3S', '7D'], [], False, True], ['3S', '7D']], [[['2D', '3H', '3S', '4S', '6D', 'QC', 'QH'], ['6C', 'AH'], False, False], ['QC']], [[['3C', '6D', 'TH'], [], False, False], ['3C', '6D']], [[['3D', '5C', '6S', '7H', 'KH', 'TH', 'TS'], [], False, False], ['3D', '5C', '6S', 'TS']], [[['7D', '8H', 'AD', 'AS'], ['AH', '4H', '9C'], True, True], ['8H']], [[['3C', '3S', '4H', 'KC', 'QS'], [], False, False], ['3C', '3S', 'KC', 'QS']], [[['3H'], [], False, False], ['3H']]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("legal plays 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)

source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    hand, trick, broken, first = x
    def penalty(c):
        return c[1] == 'H' or c == 'QS'
    if not trick:
        if first and '2C' in hand:
            return ['2C']
        if not broken:
            safe = [c for c in hand if c[1] != 'H']
            return safe
        return list(hand)
    suit = trick[0][1]
    follow = [c for c in hand if c[1] == suit]
    if follow:
        return follow
    if first:
        clean = [c for c in hand if not penalty(c)]
        if clean:
            return clean
    return list(hand)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[['6H', 'AH', 'JC'], ['7S', 'KC'], False, False], ['6H', 'AH', 'JC']], [[['5H', '6C', '7C', '9C', 'KD', 'QC', 'TS'], ['3S', '8S', '2S'], False, True], ['TS']], [[['2C', 'JS'], [], True, True], ['2C']], [[['AS', 'TH'], [], False, True], ['AS']], [[['2C', '8C', 'AS', 'KH'], [], True, False], ['2C', '8C', 'AS', 'KH']], [[['2H', '3C', '3H', 'QC'], [], True, False], ['2H', '3C', '3H', 'QC']], [[['3D', '9H', 'QS'], [], False, False], ['3D', 'QS']], [[['3H'], [], False, False], ['3H']]], [[[['2S', 'KS', 'TH'], ['JC', '2C'], False, True], ['2S', 'KS']], [[['2S'], ['QS'], False, False], ['2S']], [[['2H', '6C', '7H', '9C', '9S'], ['QC', '2C', '6H'], False, False], ['6C', '9C']], [[['3H', '5D', '9D'], ['3C'], True, False], ['3H', '5D', '9D']], [[['AH', 'JH', 'TH'], ['9C', 'TS'], True, False], ['AH', 'JH', 'TH']], [[['2H', '6S', '8D', 'AC', 'JD', 'QH'], ['4H', 'KC', '3S'], True, True], ['2H', 'QH']], [[['2H', '4C', 'AH', 'AS', 'KC', 'QS', 'TS'], [], False, False], ['4C', 'AS', 'KC', 'QS', 'TS']], [[['3H', '5H'], [], False, False], ['3H', '5H']]], [[[['5C'], [], False, True], ['5C']], [[['5D', 'JH'], ['QH', 'KC', '8S'], True, False], ['JH']], [[['4H'], [], True, True], ['4H']], [[['3D', '5C'], [], True, False], ['3D', '5C']], [[['2H', '5H'], ['KS', '9C', '7H'], False, False], ['2H', '5H']], [[['8C', 'AC', 'KD', 'TS'], [], False, True], ['8C', 'AC', 'KD', 'TS']], [[['4H', '6D', '7C', '7S', '9D', 'QS', 'TD'], [], False, True], ['6D', '7C', '7S', '9D', 'QS', 'TD']], [[['4H'], [], False, False], ['4H']]], [[[['2H', '6C', '6D', '7C', 'KS', 'QC'], ['3C', '7D'], True, False], ['6C', '7C', 'QC']], [[['AC'], ['2C', '8D'], False, False], ['AC']], [[['2S', '6D'], [], True, False], ['2S', '6D']], [[['5D', 'AS'], ['5S', '3C'], False, False], ['AS']], [[['3C', '4S', '6S', '7D', '8H', 'AS', 'KC', 'KH'], [], False, False], ['3C', '4S', '6S', '7D', 'AS', 'KC']], [[['2H', '3D', '5H', '9D', 'JC', 'KS', 'QD'], [], False, False], ['3D', '9D', 'JC', 'KS', 'QD']], [[['7H'], [], False, False], ['7H']], [[['QS', 'AD'], [], False, False], ['QS', 'AD']]], [[[['4D', '6S', '9C', 'JD'], ['9H', 'AS', 'KC'], False, True], ['4D', '6S', '9C', 'JD']], [[['3S', '7D'], [], False, True], ['3S', '7D']], [[['2D', '3H', '3S', '4S', '6D', 'QC', 'QH'], ['6C', 'AH'], False, False], ['QC']], [[['3C', '6D', 'TH'], [], False, False], ['3C', '6D']], [[['3D', '5C', '6S', '7H', 'KH', 'TH', 'TS'], [], False, False], ['3D', '5C', '6S', 'TS']], [[['7D', '8H', 'AD', 'AS'], ['AH', '4H', '9C'], True, True], ['8H']], [[['3C', '3S', '4H', 'KC', 'QS'], [], False, False], ['3C', '3S', 'KC', 'QS']], [[['3H'], [], False, False], ['3H']]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("legal plays 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)

prompt:
A player cannot lead QS before hearts are broken.

Input [hand, trick_so_far, hearts_broken, first_trick]. Leading: on the first trick the holder of 2C must lead it; hearts may not be led before they are broken unless the hand is all hearts (QS may be led). Following: follow the led suit if possible; on the first trick a void player may not discard hearts or QS unless nothing else is held. Return legal cards in hand order.

split: open-access