<commit_before>from itertools import product
import string

import gomill
from gomill import boards, sgf, sgf_moves

#NBCOORD_DIAG = tuple(product((1, -1), (1, -1)))

NBCOORD = ((-1,0), (1,0), (0,1), (0,-1))

def board2strings(board):
    """
    Divides board into strings and computes sets of their liberties.
    Takes O(N) time and space, where N is the number of occupied points.
    Algorithm is a simple dfs.
    """
    
    def coord_onboard(row, col):
        return row >= 0 and col >= 0 and row < board.side and col < board.side
    def iter_nbhs((row, col)):
        for dx, dy in NBCOORD:
            nbx, nby = row + dx, col + dy
            if coord_onboard(nbx, nby):
                yield nbx, nby
    
    # pt => color
    colors = dict((pt, color) for (color, pt) in board.list_occupied_points() )
    # pt => string number
    visited = {}
    # string number => set of liberties
    liberties = {}
    i = -1
    for pt in colors.keys():
        if pt in visited:
            continue
        # new string
        i += 1
        # dfs
        fringe = [pt]
        while fringe:
            n = fringe.pop()
            if n in visited:
                continue
            visited[n] = i
            # dfs over unvisited nbhood of the same color
            for nb in iter_nbhs(n):
                # track liberty
                if not nb in colors:
                    liberties.setdefault(i, set()).add(nb)
                    continue
                if nb in visited:
                    # better be safe
                    assert ((colors[nb] != colors[n])
                            or visited[nb] == visited[n])
                    continue
                if colors[nb] == colors[n]:
                    fringe.append(nb)
                    
    return colors, visited, liberties

if __name__ == "__main__":
    with open("test_sgf/test1.sgf", 'r') as fin:
        game = gomill.sgf.Sgf_game.from_string(fin.read())
    
    board, movepairs = gomill.sgf_moves.get_setup_and_moves(game)<commit_msg>go_strings: factorize nbhoood iteration out of closure<commit_after>from itertools import product
import string

import gomill
from gomill import boards, sgf, sgf_moves

#NBCOORD_DIAG = tuple(product((1, -1), (1, -1)))

NBCOORD = ((-1,0), (1,0), (0,1), (0,-1))

def coord_onboard(board, (row, col)):
    return row >= 0 and col >= 0 and row < board.side and col < board.side

def iter_nbhs(board, (row, col)):
    for dx, dy in NBCOORD:
        nbx, nby = row + dx, col + dy
        if coord_onboard(board, (nbx, nby)):
            yield nbx, nby

def board2strings(board):
    """
    Divides board into strings and computes sets of their liberties.
    Takes O(N) time and space, where N is the number of occupied points.
    Algorithm is a simple dfs.
    """
    
    # pt => color
    colors = dict((pt, color) for (color, pt) in board.list_occupied_points() )
    # pt => string number
    visited = {}
    # string number => set of liberties
    liberties = {}
    i = -1
    for pt in colors.keys():
        if pt in visited:
            continue
        # new string
        i += 1
        # dfs
        fringe = [pt]
        while fringe:
            n = fringe.pop()
            if n in visited:
                continue
            visited[n] = i
            # dfs over unvisited nbhood of the same color
            for nb in iter_nbhs(board, n):
                # track liberty
                if not nb in colors:
                    liberties.setdefault(i, set()).add(nb)
                    continue
                if nb in visited:
                    # better be safe
                    assert ((colors[nb] != colors[n])
                            or visited[nb] == visited[n])
                    continue
                if colors[nb] == colors[n]:
                    fringe.append(nb)
                    
    return colors, visited, liberties

if __name__ == "__main__":
    with open("test_sgf/test1.sgf", 'r') as fin:
        game = gomill.sgf.Sgf_game.from_string(fin.read())
    
    board, movepairs = gomill.sgf_moves.get_setup_and_moves(game)
{'fraction_non_alphanumeric': 0.10437956204379562, 'fraction_numerical': 0.008759124087591242, 'mean_word_length': 1.6625647668393781, 'pattern_counts': {'":': 2, '<': 7, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6159564', 'n_tokens_mistral': 1304, 'n_tokens_neox': 1249, 'n_words': 399}