def boardToPieceFeatures(board, player = chess.WHITE): boardState = np.zeros((0, 8, 8)) # Pawn = 1, King = 6 for currPiece in range(1,7): pieceBits = np.array(SquareSet(board.pieces(currPiece, player)).tolist(), dtype = np.uint8).reshape(8, 8) pieceBits = np.flip(pieceBits) # If the current player is black, then rotate the board 180 degrees. if player == chess.BLACK: pieceBits = np.rot90(pieceBits, k=2) boardState = np.append(boardState, [pieceBits], axis = 0) for currPiece in range(1,7): pieceBits = np.array(SquareSet(board.pieces(currPiece, not player)).tolist(), dtype = np.uint8).reshape(8, 8) pieceBits = np.flip(pieceBits) # If the current player is black, then rotate the board 180 degrees. if player == chess.BLACK: pieceBits = np.rot90(pieceBits, k=2) boardState = np.append(boardState, [pieceBits], axis = 0) # Returns a 12 x 8 x 8 array of the current board state. return boardState
def develops(self, move): if self.board.san(move) == 'O-O' or self.board.san(move) == 'O-O-O': return True to_move = self.board.turn piece_type = self.board.piece_type_at(move.from_square) if piece_type == chess.ROOK: return True elif piece_type == chess.PAWN or piece_type == chess.KING: return False if to_move == chess.WHITE: return move.from_square in SquareSet(chess.BB_RANK_1) elif to_move == chess.BLACK: return move.from_square in SquareSet(chess.BB_RANK_8) return False
def back_rank_mate(puzzle: Puzzle) -> bool: node = puzzle.game.end() board = node.board() king = board.king(not puzzle.pov) assert king is not None assert isinstance(node, ChildNode) back_rank = 7 if puzzle.pov else 0 if board.is_checkmate() and square_rank(king) == back_rank: squares = SquareSet.from_square(king + (-8 if puzzle.pov else 8)) if puzzle.pov: if chess.square_file(king) < 7: squares.add(king - 7) if chess.square_file(king) > 0: squares.add(king - 9) else: if chess.square_file(king) < 7: squares.add(king + 9) if chess.square_file(king) > 0: squares.add(king + 7) for square in squares: piece = board.piece_at(square) if piece is None or piece.color == puzzle.pov or board.attackers( puzzle.pov, square): return False return any( square_rank(checker) == back_rank for checker in board.checkers()) return False
def _generate_svg(x, y, previous_positions): """ Generate a single svg for one frame of the animation Parameters ---------- x: int the current x position of the knight starting from the top left (zero-indexed) y: int the current y position of the knight starting from the top left (zero-indexed) previous_positions: list a list of previous positions of the knight, which will be marked with an 'x' symbol in the animation Returns ------- str the SVG of the current position of the knight with previous steps shown """ # represent the knight on the board board = Board(_convert_coord_to_fen(x, y)) # represent the previous positions of the knight squares = SquareSet( [square(prev_x, 7 - prev_y) for prev_x, prev_y in previous_positions]) # generate SVG return svg_board(board=board, squares=squares)
def exposed_king(puzzle: Puzzle) -> bool: if puzzle.pov: pov = puzzle.pov board = puzzle.mainline[0].board() else: pov = not puzzle.pov board = puzzle.mainline[0].board().mirror() king = board.king(not pov) assert king is not None if chess.square_rank(king) < 5: return False squares = SquareSet.from_square(king - 8) if chess.square_file(king) > 0: squares.add(king - 1) squares.add(king - 9) if chess.square_file(king) < 7: squares.add(king + 1) squares.add(king - 7) for square in squares: if board.piece_at(square) == Piece(PAWN, not pov): return False for node in puzzle.mainline[1::2][1:-1]: if node.board().is_check(): return True return False
def dovetail_mate(puzzle: Puzzle) -> bool: node = puzzle.game.end() board = node.board() king = board.king(not puzzle.pov) assert king is not None assert isinstance(node, ChildNode) if square_file(king) in [0, 7] or square_rank(king) in [0, 7]: return False queen_square = node.move.to_square if (util.moved_piece_type(node) != QUEEN or square_file(queen_square) == square_file(king) or square_rank(queen_square) == square_rank(king) or square_distance(queen_square, king) > 1): return False for square in [ s for s in SquareSet(chess.BB_ALL) if square_distance(s, king) == 1 ]: if square == queen_square: continue attackers = list(board.attackers(puzzle.pov, square)) if attackers == [queen_square]: if board.piece_at(square): return False elif attackers: return False return True
def get_attacked_defended(self): attacked = np.full(64, 0.0) defended = np.full(64, 0.0) our = self.occupied_co[self.turn] their = self.occupied_co[not self.turn] for square in SquareSet(our): for our_defended in SquareSet(self.attacks_mask(square)): defended[our_defended] = 1.0 for square in SquareSet(their): for our_attacked in SquareSet(self.attacks_mask(square)): attacked[our_attacked] = 1.0 return attacked, defended
def clearance(puzzle: Puzzle) -> bool: for node in puzzle.mainline[1::2][1:]: board = node.board() if not node.parent.board().piece_at(node.move.to_square): piece = board.piece_at(node.move.to_square) if piece and piece.piece_type in util.ray_piece_types: prev = node.parent.parent assert prev prev_move = prev.move assert prev_move assert isinstance(node.parent, ChildNode) if (not prev_move.promotion and prev_move.to_square != node.move.from_square and prev_move.to_square != node.move.to_square and not node.parent.board().is_check() and (not board.is_check() or util.moved_piece_type(node.parent) != KING)): if (prev_move.from_square == node.move.to_square or prev_move.from_square in SquareSet.between( node.move.from_square, node.move.to_square)): if prev.parent and not prev.parent.board().piece_at( prev_move.to_square) or util.is_in_bad_spot( prev.board(), prev_move.to_square): return True return False
def dims_knight(self, move): '''Knight on the rim is dim''' if self.board.piece_type_at(move.from_square) == chess.KNIGHT: rim = SquareSet( chess.BB_RANK_1 | \ chess.BB_RANK_8 | \ chess.BB_FILE_A | \ chess.BB_FILE_H) return move.to_square in rim
def opens_position(self, move): to_move = self.board.turn if self.board.piece_type_at(move.from_square) == chess.PAWN: if move.to_square not in SquareSet(chess.BB_RANK_1 | chess.BB_RANK_8): num_pawns_before = len(self.board.pieces(chess.PAWN, not to_move)) analysis_board = chess.Board(self.board.fen()) analysis_board.push(move) num_pawns_after = len(analysis_board.pieces(chess.PAWN, not to_move)) return num_pawns_before != num_pawns_after return False
def controls(self, move): '''Returns a set of attacked/defended squares''' to_move = self.board.turn analysis_board = chess.Board(self.board.fen()) analysis_board.push(move) squares = 0 for square in chess.SQUARES: if move.to_square in analysis_board.attackers(to_move, square): squares |= chess.BB_SQUARES[square] return SquareSet(squares)
def discovered_attack(puzzle: Puzzle) -> bool: if discovered_check(puzzle): return True for node in puzzle.mainline[1::2][1:]: if util.is_capture(node): between = SquareSet.between(node.move.from_square, node.move.to_square) if node.parent.move.to_square == node.move.to_square: return False prev = node.parent.parent if prev.move.from_square in between and node.move.to_square != prev.move.to_square: return True return False
def self_interference(puzzle: Puzzle) -> bool: # intereference by opponent piece for node in puzzle.mainline[1::2][1:]: prev_board = node.parent.board() square = node.move.to_square capture = prev_board.piece_at(square) if capture and util.is_hanging(prev_board, capture, square): init_board = node.parent.parent.board() defenders = init_board.attackers(capture.color, square) defender = defenders.pop() if defenders else None if defender and init_board.piece_at( defender).piece_type in util.ray_piece_types: if node.parent.move.to_square in SquareSet.between( square, defender): return True return False
def skewer(puzzle: Puzzle) -> bool: for node in puzzle.mainline[1::2][1:]: prev = node.parent assert isinstance(prev, ChildNode) capture = prev.board().piece_at(node.move.to_square) if capture and util.moved_piece_type(node) in util.ray_piece_types and not node.board().is_checkmate(): between = SquareSet.between(node.move.from_square, node.move.to_square) op_move = prev.move assert op_move if op_move.to_square == node.move.to_square or not op_move.from_square in between: continue if util.king_values[util.moved_piece_type(prev)] > util.king_values[capture.piece_type] and util.is_in_bad_spot( prev.board(), node.move.to_square ): return True return False
def x_ray(puzzle: Puzzle) -> bool: for node in puzzle.mainline[1::2][1:]: if not util.is_capture(node): continue prev_op_node = node.parent assert isinstance(prev_op_node, ChildNode) if prev_op_node.move.to_square != node.move.to_square or util.moved_piece_type(prev_op_node) == KING: continue prev_pl_node = prev_op_node.parent assert isinstance(prev_pl_node, ChildNode) if prev_pl_node.move.to_square != prev_op_node.move.to_square: continue if prev_op_node.move.from_square in SquareSet.between(node.move.from_square, node.move.to_square): return True return False
def boden_or_double_bishop_mate(puzzle: Puzzle): node = puzzle.game.end() board = node.board() king = board.king(not puzzle.pov) assert king is not None assert isinstance(node, ChildNode) bishop_squares = list(board.pieces(BISHOP, puzzle.pov)) if len(bishop_squares) < 2: return None for square in [s for s in SquareSet(chess.BB_ALL) if square_distance(s, king) < 2]: if not all([p.piece_type == BISHOP for p in util.attacker_pieces(board, puzzle.pov, square)]): return None if (square_file(bishop_squares[0]) < square_file(king)) == (square_file(bishop_squares[1]) > square_file(king)): return "bodenMate" else: return "doubleBishopMate"
def discovered_attack(puzzle: Puzzle) -> bool: if discovered_check(puzzle): return True for node in puzzle.mainline[1::2][1:]: if util.is_capture(node): between = SquareSet.between(node.move.from_square, node.move.to_square) assert isinstance(node.parent, ChildNode) if node.parent.move.to_square == node.move.to_square: return False prev = node.parent.parent assert isinstance(prev, ChildNode) if (prev.move.from_square in between and node.move.to_square != prev.move.to_square and node.move.from_square != prev.move.to_square and not util.is_castling(prev)): return True return False
def skewer(puzzle: Puzzle) -> bool: def value(pt: PieceType): return 10 if pt == KING else util.values[pt] for node in puzzle.mainline[1::2][1:]: prev = node.parent capture = prev.board().piece_at(node.move.to_square) if capture and util.moved_piece_type( node ) in util.ray_piece_types and not node.board().is_checkmate(): between = SquareSet.between(node.move.from_square, node.move.to_square) op_move = prev.move if (op_move.to_square == node.move.to_square or not op_move.from_square in between): continue if value(util.moved_piece_type(prev)) > value(capture.piece_type): return True return False
def closes_position(self, move): piece = self.board.piece_at(move.from_square) if piece and piece.piece_type == chess.PAWN: if not self.opens_position(move): from_bb_square = chess.BB_SQUARES[move.from_square] pawn_attack = 0 if piece.color == chess.WHITE: pawn_attack |= chess.shift_up_left(from_bb_square) pawn_attack |= chess.shift_up_right(from_bb_square) elif piece.color == chess.BLACK: pawn_attack |= chess.shift_down_left(from_bb_square) pawn_attack |= chess.shift_down_right(from_bb_square) for square in SquareSet(pawn_attack): passed_up_piece = self.board.piece_at(square) if passed_up_piece: if passed_up_piece.color != self.board.turn and \ passed_up_piece.piece_type == chess.PAWN: return True return False
def interference(puzzle: Puzzle) -> bool: # intereference by player piece for node in puzzle.mainline[1::2][1:]: prev_board = node.parent.board() square = node.move.to_square capture = prev_board.piece_at(square) assert node.parent.move if capture and square != node.parent.move.to_square and util.is_hanging(prev_board, capture, square): assert node.parent assert node.parent.parent assert node.parent.parent.parent init_board = node.parent.parent.parent.board() defenders = init_board.attackers(capture.color, square) defender = defenders.pop() if defenders else None defender_piece = init_board.piece_at(defender) if defender else None if defender and defender_piece and defender_piece.piece_type in util.ray_piece_types: interfering = node.parent.parent if interfering.move and interfering.move.to_square in SquareSet.between(square, defender): return True return False
def bit_set_count(square_set: chess.SquareSet): result = 0 while square_set: square_set.pop() result += 1 return result
def controls_center(self, move): center = SquareSet(chess.BB_D4 | chess.BB_D5 | chess.BB_E4 | chess.BB_E5) for square in self.controls(move): if square in center: return True return False