Пример #1
0
 def legal_play(self, x, y, ignore_ko=False, allow_filling_in_own_eye=False):
     b = self.board
     # (x, y) must be on the board
     if not b.on_board(x, y):
         return False
     # (x, y) must be an empty intersection
     if b.color(x, y) != EMPTY:
         return False
     # determine if (x, y) is in ko
     captured_chains = self.captured_chains(x, y)
     if not ignore_ko and len(captured_chains) == 1 \
             and b.chain_size_(captured_chains[0]) == 1 \
             and self.previous_captured_size == 1 \
             and b.find(self.previous_x, self.previous_y) == \
             captured_chains[0]:
         return False
     # the play is illegal if it causes suicide without capturing
     # any opponent's stones
     if self.suicide(x, y) and len(captured_chains) == 0:
         return False
     # now the play is legal if filling in own eye is allowed
     if allow_filling_in_own_eye:
         return True
     # otherwise check if the play fills in own eye
     adjacent_chains = SmallSet(4)
     for dx, dy in _directions:
         if b.on_board(x + dx, y + dy):
             if b.color(x + dx, y + dy) != self.turn:
                 return True
             else:
                 adjacent_chains.add(b.find(x + dx, y + dy))
     return len(adjacent_chains) != 1
Пример #2
0
    def place(self, x, y, color):
        # create a stone chain of size 1 on (x, y)
        z = x * self.board_size + y
        self._color[z] = color
        self._parent[z] = z
        self._chain_size[z] = 1
        if self._liberties[z] is None:
            self._liberties[z] = BitSet(self.board_size * self.board_size)
        for dx, dy in _directions:
            if self.on_board(x + dx, y + dy) \
                    and self.color(x + dx, y + dy) == EMPTY:
                self._liberties[z].add((x + dx) * self.board_size + y + dy)

        # update the liberty of the chains adjacent to (x, y)
        adjacent_chains = SmallSet(4)
        for dx, dy in _directions:
            if self.on_board(x + dx, y + dy) \
                    and self.color(x + dx, y + dy) != EMPTY:
                adjacent_chains.add(self.find(x + dx, y + dy))
        for c in adjacent_chains:
            self._liberties[c].remove(z)

        # merge the stone on (x, y) with all the own stone chains that
        # are adjacent to (x, y)
        for dx, dy in _directions:
            if self.on_board(x + dx, y + dy) \
                    and self.color(x + dx, y + dy) == color:
                self._union(x, y, x + dx, y + dy)

        # remove all the opponent's stone chains that are captured
        for dx, dy in _directions:
            if self.on_board(x + dx, y + dy) \
                    and self.color(x + dx, y + dy) == -color \
                    and len(self.liberties(x + dx, y + dy)) == 0:
                self._remove(x + dx, y + dy)
Пример #3
0
 def captured_chains(self, x, y):
     captured_chains = SmallSet(4)
     b = self.board
     for dx, dy in _directions:
         if b.on_board(x + dx, y + dy) \
                 and b.color(x + dx, y + dy) == -self.turn \
                 and len(b.liberties(x + dx, y + dy)) == 1:
             captured_chains.add(b.find(x + dx, y + dy))
     return captured_chains
Пример #4
0
 def ladder_escape(self, x, y):
     adjacent_chains = SmallSet(4)
     b = self.board
     for dx, dy in _directions:
         if b.on_board(x + dx, y + dy) \
                 and b.color(x + dx, y + dy) == self.turn \
                 and not adjacent_chains.contains(b.find(x + dx, y + dy)):
             if self.ladder_escape_(x, y, x + dx, y + dy):
                 return True
             adjacent_chains.add(b.find(x + dx, y + dy))
     return False
Пример #5
0
    def _remove(self, x, y):
        self._liberties[self.find(x, y)] = None

        n = self.board_size * self.board_size
        z = x * self.board_size + y
        color = self._color[z]

        # insert (x, y) into the queue, and mark it as "visited but not
        # processed" (color = _GRAY)
        # we abuse the _color array to store the BFS state here:
        #   - color = EMPTY: processed
        #   - color = BLACK: not visited (for black stones)
        #   - color = WHITE: not visited (for white stones)
        #   - color = _GRAY: visited (i.e., in queue) but not processed
        q = Queue(n)
        q.enqueue((x, y))
        self._color[z] = _GRAY
        adjacent_opponent_chains = SmallSet(4)
        while not q.is_empty():
            x, y = q.dequeue()
            adjacent_opponent_chains.clear()
            for dx, dy in _directions:
                if self.on_board(x + dx, y + dy):
                    # insert all the own adjacent stones that are not
                    # visited into the queue
                    if self.color(x + dx, y + dy) == color:
                        q.enqueue((x + dx, y + dy))
                        self._color[(x + dx) * self.board_size + y +
                                    dy] = _GRAY
                    # save opponent's stone chains that are adjacent to
                    # this new empty intersection
                    if self.color(x + dx, y + dy) == -color:
                        adjacent_opponent_chains.add(self.find(x + dx, y + dy))
            # the new empty intersection (x, y) provides liberty to its
            # adjacent stone chains
            z = x * self.board_size + y
            for c in adjacent_opponent_chains:
                if self._liberties[c] is None:
                    self._liberties[c] = BitSet(n)
                self._liberties[c].add(z)
            self._color[z] = EMPTY