<commit_before>import numpy as np

PLAYER1 = -1
PLAYER2 = 1
PLAYERS = {'B': -1, 'W': 1}

def board_shape(board_string):
    lines = board_string.split("|")
    rows, cols = (len(lines)+1)/2, (len(lines[0])+1)/2
    return rows, cols

class DotsAndBoxes(object):
    def __init__(self, initial_player=None, rows=None, cols=None, board_string=None, game_obj=None):
        if isinstance(board_string, str):      # construct from string
            self._from_string(initial_player, board_string)
        elif isinstance(game_obj, DotsAndBoxes):  # copy constructor
            self._copy(game_obj)
        else:
            self.rows, self.cols = rows, cols
            self.score = [0, 0] # B, W
            self.turn = initial_player
            self.board = np.zeros((2*rows-1, 2*cols-1), dtype=np.int)
            r, c = self.board.shape
            self._edges = np.reshape([i%2 != j%2 for j in range(c) for i in range(r)], (r, c))

    def _from_string(self, initial_player, board_string):
        lines = board_string.split("|")
        rows, cols = board_shape(board_string)
        self.__init__(initial_player, rows, cols)
        for i, r in enumerate(lines):
            for j, s in enumerate(r):
                edge, box = i%2 != j%2, i%2 == j%2 == 1
                if edge and s == 'x':      # is a filled edge
                    self.board[i, j] += 1
                elif box and s in PLAYERS: # is a filled box
                    self.board[i, j] = PLAYERS[s]
                    self.score[PLAYERS[s] == 1] += 1

    def _copy(self, game_obj):
        self.__dict__.update(game_obj.__dict__)
        self.board = np.array(game_obj.board)
        self.score = game_obj.score[:]

    def play(self, move=None, i=None, j=None, player=None):
        if not player:
            player = self.turn
        if isinstance(move, np.ndarray):
            i, j = move[0], move[1]
        if self._is_valid(player, i, j):
            self.board[i, j] = player
            self._update(player, i, j)
        else:
            raise Exception('Invalid move %d,%d' % (i, j))

    def get_available_moves(self):
        unplayed = np.logical_not(self.board)
        return np.transpose(np.where(np.logical_and(unplayed, self._edges)))

    def _is_valid(self, player, i, j):
        turn = self.turn == player   # is players' turn
        edge = i%2 != j%2            # i xor j are even
        free = self.board[i, j] == 0 # edge is not already filled
        over = self.is_over()        # game is over
        return not over and turn and edge and free

    def is_over(self):
        return sum(self.score) == (self.rows-1) * (self.cols-1)

    def _update(self, player, i, j):
        vertical = i%2 > j%2
        a = self._check_box(player, i, j-1) if vertical else self._check_box(player, i-1, j)
        b = self._check_box(player, i, j+1) if vertical else self._check_box(player, i+1, j)
        if not (a or b): # did not fill any box
            self.turn *= -1

    def _check_box(self, player, i, j):
        irange = i > 0 and i < 2*self.rows-1
        jrange = j > 0 and j < 2*self.cols-1
        box = i%2 == j%2 == 1        # i and j are odd
        if irange and jrange: # and box:
            filled = self.board[i-1, j] and self.board[i+1, j] and self.board[i, j-1] and self.board[i, j+1]
            if filled:
                self.board[i, j] = player
                self.score[player == 1] += 1
            return filled<commit_msg>Performance tweaks - Remove isinstance cals - Store board shape as a member - Return available moves as a list of tuples (instead of as a matrix) - Remove a few variable assignments<commit_after>import numpy as np

PLAYER1 = -1
PLAYER2 = 1
PLAYERS = {'B': -1, 'W': 1}

def board_shape(board_string):
    lines = board_string.split("|")
    rows, cols = (len(lines)+1)/2, (len(lines[0])+1)/2
    return rows, cols

class DotsAndBoxes(object):
    def __init__(self, initial_player=None, rows=None, cols=None, board_string=None, game_obj=None):
        if board_string is not None: # construct from string
            self._from_string(initial_player, board_string)
        elif game_obj is not None:   # copy constructor
            self._copy(game_obj)
        else:
            self.rows, self.cols = rows, cols
            self.score = [0, 0] # B, W
            self.turn = initial_player
            self.board = np.zeros((2*rows-1, 2*cols-1), dtype=np.int)
            self.r, self.c = self.board.shape
            self._edges = np.reshape([i%2 != j%2 for j in xrange(self.c) for i in xrange(self.r)], (self.r, self.c))
            self.num_boxes = (rows-1) * (cols-1)

    def _from_string(self, initial_player, board_string):
        lines = board_string.split("|")
        rows, cols = board_shape(board_string)
        self.__init__(initial_player, rows, cols)
        for i, r in enumerate(lines):
            for j, s in enumerate(r):
                edge, box = i%2 != j%2, i%2 == j%2 == 1
                if edge and s == 'x':      # is a filled edge
                    self.board[i, j] += 1
                elif box and s in PLAYERS: # is a filled box
                    self.board[i, j] = PLAYERS[s]
                    self.score[PLAYERS[s] == 1] += 1

    def _copy(self, game_obj):
        self.__dict__.update(game_obj.__dict__)
        self.board = np.array(game_obj.board)
        self.score = game_obj.score[:]

    def play(self, move=None, i=None, j=None, player=None):
        if not player:
            player = self.turn
        if move is not None:
            i, j = move
        if self._is_valid(player, i, j):
            self.board[i, j] = player
            self._update(player, i, j)
        else:
            raise Exception('Invalid move %d,%d' % (i, j))

    def get_available_moves(self):
        unplayed = np.logical_not(self.board)
        moves = np.where(np.logical_and(unplayed, self._edges))
        return zip(moves[0], moves[1])

    def _is_valid(self, player, i, j):
        return self.turn == player and self.board[i, j] == 0 and i%2 != j%2 and not self.is_over()

    def is_over(self):
        return sum(self.score) == self.num_boxes

    def _update(self, player, i, j):
        vertical = i%2 > j%2
        a = self._check_box(player, i, j-1) if vertical else self._check_box(player, i-1, j)
        b = self._check_box(player, i, j+1) if vertical else self._check_box(player, i+1, j)
        if not (a or b): # did not fill any box
            self.turn *= -1

    def _check_box(self, player, i, j):
        if (i and i < self.r) and (j and j < self.c):
            filled = self.board[i-1, j] and self.board[i+1, j] and self.board[i, j-1] and self.board[i, j+1]
            if filled:
                self.board[i, j] = player
                self.score[player == 1] += 1
            return filled
{'fraction_non_alphanumeric': 0.12967581047381546, 'fraction_numerical': 0.015109285609505647, 'mean_word_length': 2.0329181494661923, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, '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': '5062107', 'n_tokens_mistral': 2336, 'n_tokens_neox': 2259, 'n_words': 652}