def move_attacks( self, move: chess.Move, min_value: Optional[int] = None, max_value: Optional[int] = None, defended: Optional[bool] = None, ) -> chess.SquareSet: self._board.push(move) try: squares = chess.SquareSet( self._board.attacks_mask(move.to_square) & self._board.occupied_co[self.current_color]) res = chess.SquareSet() for square in squares: if ((min_value is None or self.piece_value_at(square) >= min_value) and (max_value is None or self.piece_value_at(square) <= max_value) and (defended is None or self.is_square_defended(square) == defended)): res.add(square) return res finally: self._board.pop()
def svg_dark_board(public_squares: List[chess.Square] = [], hidden_squares: List[chess.Square] = [], orientation: chess.Color = chess.WHITE, flipped: bool = False, coordinates: bool = True, **kwargs) -> ET.Element: svg = chess_svg.board(**kwargs) defs = ET.SubElement(svg, "defs") defs.append(ET.fromstring(PUBLIC_SQUARE_SVG)) defs.append(ET.fromstring(HIDDEN_SQUARE_SVG)) public_set = chess.SquareSet(public_squares) hidden_set = chess.SquareSet(hidden_squares) orientation ^= flipped margin = 15 if coordinates else 0 for square, bb in enumerate(chess.BB_SQUARES): file_index = chess.square_file(square) rank_index = chess.square_rank(square) x = ( file_index if orientation else 7 - file_index) * \ chess_svg.SQUARE_SIZE + margin y = ( 7 - rank_index if orientation else rank_index) * \ chess_svg.SQUARE_SIZE + margin if square in public_set: ET.SubElement(svg, "use", chess_svg._attrs({ "xlink:href": "#public", "x": x, "y": y, })) if square in hidden_set: ET.SubElement(svg, "use", chess_svg._attrs({ "xlink:href": "#hidden", "x": x, "y": y, })) return svg
def __init__(self): self.StartingPositionsPath = 'PositionsSet.txt' self.MlpClassificationWeights = 'Bobbyweights.h5' self.MlpDimension = 768 self.NumberSimulationGames = 2 self.MlpWins = 0 self.CnnWins = 0 self.Draws = 0 self.width = 8 self.height = 8 self.channels = 16 self.ImportantSquareSet = chess.SquareSet(chess.BB_D4 | chess.BB_D5 | chess.BB_C4 | chess.BB_C5 | chess.BB_E4 | chess.BB_E5 | chess.BB_F2 | chess.BB_F7 | chess.BB_H2 | chess.BB_H7) self.SquareSet = chess.SquareSet( chess.BB_A1 | chess.BB_A2 | chess.BB_A3 | chess.BB_A4 | chess.BB_A5 | chess.BB_A6 | chess.BB_A7 | chess.BB_A8 | chess.BB_B1 | chess.BB_B2 | chess.BB_B3 | chess.BB_B4 | chess.BB_B5 | chess.BB_B6 | chess.BB_B7 | chess.BB_B8 | chess.BB_C1 | chess.BB_C2 | chess.BB_C3 | chess.BB_C4 | chess.BB_C5 | chess.BB_C6 | chess.BB_C7 | chess.BB_C8 | chess.BB_D1 | chess.BB_D2 | chess.BB_D3 | chess.BB_D4 | chess.BB_D5 | chess.BB_D6 | chess.BB_D7 | chess.BB_D8 | chess.BB_A1 | chess.BB_E2 | chess.BB_E3 | chess.BB_E4 | chess.BB_E5 | chess.BB_E6 | chess.BB_E7 | chess.BB_E8 | chess.BB_F1 | chess.BB_F2 | chess.BB_F3 | chess.BB_F4 | chess.BB_F5 | chess.BB_F6 | chess.BB_F7 | chess.BB_F8 | chess.BB_G1 | chess.BB_G2 | chess.BB_G3 | chess.BB_G4 | chess.BB_G5 | chess.BB_G6 | chess.BB_G7 | chess.BB_G8 | chess.BB_H1 | chess.BB_H2 | chess.BB_H3 | chess.BB_H4 | chess.BB_H5 | chess.BB_H6 | chess.BB_H7 | chess.BB_H8)
def fill_piece(iplanes, ix, bb, b, flip_rank, flip_file): """ Compute piece placement and attack plane for a given piece type """ if AUX_INP: abb = 0 squares = chess.SquareSet(bb) for sq in squares: abb = abb | b.attacks_mask(sq) f = chess.square_file(sq) r = chess.square_rank(sq) if flip_rank: r = RANK_U - r if flip_file: f = FILE_U - f iplanes[r, f, ix + 12] = 1.0 squares = chess.SquareSet(abb) for sq in squares: f = chess.square_file(sq) r = chess.square_rank(sq) if flip_rank: r = RANK_U - r if flip_file: f = FILE_U - f iplanes[r, f, ix] = 1.0 else: squares = chess.SquareSet(bb) for sq in squares: f = chess.square_file(sq) r = chess.square_rank(sq) if flip_rank: r = RANK_U - r if flip_file: f = FILE_U - f iplanes[r, f, ix] = 1.0
def squareset(pc, f1, r1, x, f2, r2): hi1 = ~chess.SquareSet() if pc or f1 or r1 else chess.SquareSet() if pc is not None: hi1 &= board.pieces( chess.Piece.from_symbol(pc).piece_type, board.turn) if x and not pc: hi1 &= board.pieces(chess.PAWN, board.turn) if f1 is not None: hi1 &= chess.BB_FILES[ord(f1) - ord("a")] if r1 is not None: hi1 &= chess.BB_RANKS[ord(r1) - ord("1")] hi2 = ~chess.SquareSet() if f2 or r2 else chess.SquareSet() if f2 is not None: hi2 &= chess.BB_FILES[ord(f2) - ord("a")] if r2 is not None: hi2 &= chess.BB_RANKS[ord(r2) - ord("1")] return hi1 | hi2
def has_pawn_structure(fen, white_files, black_files) -> bool: aug = board.AugBoard(fen) white_pawns = aug.pieces(chess.PAWN, chess.WHITE) black_pawns = aug.pieces(chess.PAWN, chess.BLACK) for color_files, color_pawns in zip([white_files, black_files], [white_pawns, black_pawns]): for file_name, ranks in color_files.items(): file_idx = ord(file_name) - ord("a") present = color_pawns & chess.SquareSet(chess.BB_FILES[file_idx]) expected = chess.SquareSet( [8 * (rank - 1) + file_idx for rank in ranks]) if present != expected: return False return True
def __init__(self, color): self.color = color self.depth_limit = 3 self.OUTER_CENTER = chess.SquareSet([ chess.C3, chess.D3, chess.E3, chess.F3, chess.F4, chess.F5, chess.F6, chess.E6, chess.D6, chess.C6, chess.C5, chess.C4 ])
def possible(self): b = self.board.copy() for piece_type in chess.PIECE_TYPES: for sq in b.pieces(piece_type, not self.color): b.remove_piece_at(sq) pawn_capture_moves = [] no_opponents_board = b.copy() for pawn_square in self.board.pieces(chess.PAWN, self.color): for attacked_square in self.board.attacks(pawn_square): # skip this square if one of our own pieces are on the square if no_opponents_board.piece_at(attacked_square): continue pawn_capture_moves.append( chess.Move(pawn_square, attacked_square)) # add in promotion moves if attacked_square in chess.SquareSet(chess.BB_BACKRANKS): for piece_type in chess.PIECE_TYPES[1:-1]: pawn_capture_moves.append( chess.Move(pawn_square, attacked_square, promotion=piece_type)) return list(b.generate_pseudo_legal_moves()) + pawn_capture_moves
def can_image_correspond_to_chessboard(self, move, current_chessboard_image): self.board.push(move) squares = chess.SquareSet(chess.BB_ALL) for square in squares: row = chess.square_rank(square) column = chess.square_file(square) piece = self.board.piece_at(square) shouldBeEmpty = (piece == None) if self.we_play_white == True: rowOnImage = 7 - row columnOnImage = column else: rowOnImage = row columnOnImage = 7 - column squareImage = get_square_image(rowOnImage, columnOnImage, current_chessboard_image) if is_square_empty(squareImage) != shouldBeEmpty: self.board.pop() #print( "Problem with : ", self.board.uci(move) ," the square ", rowOnImage, columnOnImage, "should ",'be empty' if shouldBeEmpty else 'contain a piece') return False #print("Accepted move", self.board.uci(move)) self.board.pop() return True
def IsLocked(self, fen, pc=10, sqs=gamelib.SquareSet([ gamelib.C3, gamelib.C4, gamelib.C5, gamelib.C6, gamelib.D3, gamelib.D4, gamelib.D5, gamelib.D6, gamelib.E3, gamelib.E4, gamelib.E5, gamelib.E6, gamelib.F3, gamelib.F4, gamelib.F5, gamelib.F6, gamelib.B3, gamelib.B4, gamelib.B5, gamelib.B6, gamelib.G3, gamelib.G4, gamelib.G5, gamelib.G6 ])): DetectionRange = sqs PieceThreshold = pc DetectedPieces = 0 fenbrd = gamelib.Board() fenbrd.set_fen(fen) bb = gamelib.BaseBoard() bb.set_board_fen(fenbrd.board_fen()) del (fenbrd) pcs = list(bb.piece_map().keys()) for sqr in DetectionRange: if sqr in pcs: DetectedPieces += 1 if DetectedPieces > PieceThreshold: return True else: return False
def _is_illegal_castle(self, board, move): if not board.is_castling(move): return False # illegal without kingside rights if board.is_kingside_castling( move) and not board.has_kingside_castling_rights(board.turn): return True # illegal without queenside rights if board.is_queenside_castling( move) and not board.has_queenside_castling_rights(board.turn): return True # illegal if any pieces are between king & rook rook_square = chess.square( 7 if board.is_kingside_castling(move) else 0, chess.square_rank(move.from_square)) between_squares = chess.SquareSet( chess.BB_BETWEEN[move.from_square][rook_square]) if any(map(lambda s: board.piece_at(s), between_squares)): return True # its legal return False
def handle_sensed_pawn(self, new_pawn_square, piece): ''' updates self.board if sensed pawn''' # only get rid of old pawn in column if this pawn didn't just capture # print (chess.SQUARE_NAMES[new_pawn_square]) # print (new_pawn_square) # print (self.my_piece_captured_square) if not self.my_piece_captured_square == new_pawn_square: # remove furthest pawn in column pawn_file = chess.square_file(new_pawn_square) pawn_file_list = np.array( chess.SquareSet(chess.BB_FILE_MASKS[pawn_file]).tolist()) pawn_file_locations = np.where(pawn_file_list == True)[0] #if playing as black, must search from top down instead of bottom up if self.color == chess.BLACK: np.flip(pawn_file_locations) for square in pawn_file_locations: if self.board.piece_at(square) == piece: self.board.remove_piece_at(square) break self.set_board_piece(new_pawn_square, piece) # else: # #print ("JUST GOT PIECE CAPTURED") self.set_board_piece(new_pawn_square, piece)
def _pawn_on(self, board, turn): """ Generates all pawn captures on `board`, even if there is no piece to capture. All promotion moves are included. :param board: chess.Board -- a chess board where you want opponnet's pieces to be removed :param turn: bool - True(WHITE's turn) or False(BLACK's turn), the opponnet is the 'not turn' :return: List(chess.Move) """ pawn_capture_moves = [] no_opponents_board = self._no_opp_pieces(board, turn) for pawn_square in board.pieces(chess.PAWN, turn): for attacked_square in board.attacks(pawn_square): # skip this square if one of our own pieces are on the square if no_opponents_board.piece_at(attacked_square): continue pawn_capture_moves.append( chess.Move(pawn_square, attacked_square)) # add in promotion moves if attacked_square in chess.SquareSet(chess.BB_BACKRANKS): for piece_type in chess.PIECE_TYPES[1:-1]: pawn_capture_moves.append( chess.Move(pawn_square, attacked_square, promotion=piece_type)) return pawn_capture_moves
def highlight_san_move(text, board=None): """ Parse a move in SAN (or UCI) notation, and return a set of highlighted squares the move might be affecting. """ # [QKNRB]?[a-h]?[1-8]?x?[a-h][1-8]=?[QNRB] def squareset(pc, f1, r1, x, f2, r2): hi1 = ~chess.SquareSet() if pc or f1 or r1 else chess.SquareSet() if pc is not None: hi1 &= board.pieces( chess.Piece.from_symbol(pc).piece_type, board.turn) if x and not pc: hi1 &= board.pieces(chess.PAWN, board.turn) if f1 is not None: hi1 &= chess.BB_FILES[ord(f1) - ord("a")] if r1 is not None: hi1 &= chess.BB_RANKS[ord(r1) - ord("1")] hi2 = ~chess.SquareSet() if f2 or r2 else chess.SquareSet() if f2 is not None: hi2 &= chess.BB_FILES[ord(f2) - ord("a")] if r2 is not None: hi2 &= chess.BB_RANKS[ord(r2) - ord("1")] return hi1 | hi2 match = rx_move.match(text) if not match: return chess.SquareSet() pc, f1, r1, x, f2, r2, pr = match.groups() ss = squareset(pc, f1, r1, x, f2, r2) if not x and not f2 and not r2: ss |= squareset(pc, None, None, None, f1, r1) return ss
def draw_empty_board(font: pygame.font.SysFont, w) -> pygame.Surface: surface = pygame.Surface((w, w)) pygame.draw.rect(surface, LIGHT_COLOR, (0, 0, w, w)) sw = w / 8 for dark_square in chess.SquareSet(chess.BB_DARK_SQUARES): sx = sw * chess.square_file(dark_square) sy = w - sw - sw * chess.square_rank(dark_square) pygame.draw.rect(surface, DARK_COLOR, (sx, sy, sw, sw)) example_label = font.render("a", True, (0, 0, 0)) rect = example_label.get_rect() for i in range(0, 8, 2): surface.blit( font.render(chess.FILE_NAMES[i], True, LIGHT_COLOR), (sw * i, w - rect.height), ) surface.blit( font.render(chess.RANK_NAMES[i], True, DARK_COLOR), (w - rect.width, w - sw - sw * i), ) for i in range(1, 8, 2): surface.blit( font.render(chess.FILE_NAMES[i], True, DARK_COLOR), (sw * i, w - rect.height), ) surface.blit( font.render(chess.RANK_NAMES[i], True, LIGHT_COLOR), (w - rect.width, w - sw - sw * i), ) return surface
def random_positions(max_pieces=64): board = chess.Board() while True: board.clear() piece_list = random_piece_list(max_pieces) for square, piece in enumerate(piece_list): if piece: board.set_piece_at(square, piece) board.turn = random.choice(chess.COLORS) # Skip positions with the opposite side in check. if board.was_into_check(): continue # Skip positions with pawns on the promotion rank. if board.pawns & board.occupied_co[chess.WHITE] & chess.BB_RANK_8: continue if board.pawns & board.occupied_co[chess.BLACK] & chess.BB_RANK_1: continue yield board # Generate positions with kinda valid en-passant squares. if board.turn == chess.BLACK: for potential_ep in chess.SquareSet(chess.BB_RANK_3): board.ep_square = potential_ep if (board.piece_at( chess.square(chess.file_index(potential_ep), 3)) == chess.Piece(chess.PAWN, chess.WHITE) and not board.piece_at( chess.square(chess.file_index(potential_ep), 2)) and not board.piece_at( chess.square(chess.file_index(potential_ep), 1))): yield board else: for potential_ep in chess.SquareSet(chess.BB_RANK_6): board.ep_square = potential_ep if (board.piece_at( chess.square(chess.file_index(potential_ep), 4)) == chess.Piece(chess.PAWN, chess.BLACK) and not board.piece_at( chess.square(chess.file_index(potential_ep), 5)) and not board.piece_at( chess.square(chess.file_index(potential_ep), 6))): yield board
def PsqtEval(pos, color): board = pos.board if color == chess.WHITE: score = 0 for square in chess.SquareSet(board.occupied_co[chess.WHITE]): piece = board.piece_type_at(square) score += psqt[piece][transform(square, chess.WHITE)] + pieces[piece] return score else: score = 0 for square in chess.SquareSet(board.occupied_co[chess.BLACK]): piece = board.piece_type_at(square) score += psqt[piece][transform(square, chess.BLACK)] + pieces[piece] return score
def evaluate_pinned_pieces(board): squares = chess.SquareSet(chess.BB_ALL) result = 0 for square in list(squares): if board.is_pinned(chess.BLACK, square): result = 20 return result
def diff2squareset(s1, s2): board1 = chess.BaseBoard(s1) board2 = chess.BaseBoard(s2) diffmap = chess.SquareSet() for x in range(chess.A1, chess.H8 + 1): if board1.piece_at(x) != board2.piece_at(x): diffmap.add(x) return diffmap
def _possible_moves(): res = set() for f in SQUARES: for t in chess.SquareSet(chess.BB_RANK_ATTACKS[f][0]): res.add((f, t)) for t in chess.SquareSet(chess.BB_FILE_ATTACKS[f][0]): res.add((f, t)) for t in chess.SquareSet(chess.BB_DIAG_ATTACKS[f][0]): res.add((f, t)) for t in chess.SquareSet(chess.BB_KNIGHT_ATTACKS[f]): res.add((f, t)) assert (10, 26) in res return list(sorted(res))
def get_moves_from_square(self, square): square_moves = chess.SquareSet() for move in self.board.legal_moves: if move.from_square == square: square_moves.add(move.to_square) if len(square_moves.tolist()) == 0: return None else: return square_moves
def _slide_move(self, board, move): psuedo_legal_moves = list(board.generate_pseudo_legal_moves()) squares = list(chess.SquareSet(chess.BB_BETWEEN[move.from_square][move.to_square])) + [move.to_square] squares = sorted(squares, key=lambda s: chess.square_distance(s, move.from_square), reverse=True) for slide_square in squares: revised = chess.Move(move.from_square, slide_square, move.promotion) if revised in psuedo_legal_moves: return revised return None
def square_capturers(self, square: int) -> chess.SquareSet: """ Returns a set of squares that can perform a legal capture on the given square in the current position. """ res = chess.SquareSet() for m in self._board.generate_legal_captures( to_mask=chess.BB_SQUARES[square]): res.add(m.from_square) return res
def make_svg(self, request): try: board = chess.Board(request.query["fen"]) except KeyError: raise aiohttp.web.HTTPBadRequest(reason="fen required") except ValueError: raise aiohttp.web.HTTPBadRequest(reason="invalid fen") try: size = min(max(int(request.query.get("size", 360)), 16), 1024) except ValueError: raise aiohttp.web.HTTPBadRequest(reason="size is not a number") try: uci = request.query.get("lastMove") or request.query["lastmove"] lastmove = chess.Move.from_uci(uci) except KeyError: lastmove = None except ValueError: raise aiohttp.web.HTTPBadRequest(reason="lastMove is not a valid uci move") try: check = chess.parse_square(request.query["check"]) except KeyError: check = None except ValueError: raise aiohttp.web.HTTPBadRequest(reason="check is not a valid square name") try: arrows = [chess.svg.Arrow.from_pgn(s.strip()) for s in request.query.get("arrows", "").split(",") if s.strip()] except ValueError: raise aiohttp.web.HTTPBadRequest(reason="invalid arrow") try: squares = chess.SquareSet(chess.parse_square(s.strip()) for s in request.query.get("squares", "").split(",") if s.strip()) except ValueError: raise aiohttp.web.HTTPBadRequest(reason="invalid squares") flipped = request.query.get("orientation", "white") == "black" coordinates = request.query.get("coordinates", "0") in ["", "1", "true", "True", "yes"] try: colors = THEMES[request.query.get("colors", "lichess-brown")] except KeyError: raise aiohttp.web.HTTPBadRequest(reason="theme colors not found") return chess.svg.board(board, coordinates=coordinates, flipped=flipped, lastmove=lastmove, check=check, arrows=arrows, squares=squares, size=size, colors=colors)
def render_board(self, hint=False): next_moves = chess.SquareSet() if hint: for move in self.board.legal_moves: next_moves.add(move.to_square) # Conversion code: raw_svg = chess.svg.board(board=self.board, squares=next_moves, style=self.css) return svg2png(raw_svg)
def __call__(self, pos, color): # find the lowest piece that we attack score = 0 my_pawns = pos.board.pawns & pos.board.occupied_co[color] for square in chess.SquareSet(my_pawns): if color == chess.BLACK: score += 7 - chess.square_rank(square) else: score += chess.square_rank(square) return 20 * score
def getSquareFromSquareSet(self, bigInt): #convinence method square_set = chess.SquareSet(bigInt) hi = [] for i, boolV in enumerate(square_set.tolist()): if boolV: hi.append(i) if len(hi) <= 1: return hi[0] else: raise error
def move_capturers(self, move: chess.Move) -> chess.SquareSet: self._board.push(move) try: res = chess.SquareSet() for m in self._board.generate_legal_captures( to_mask=chess.BB_SQUARES[move.to_square]): res.add(m.from_square) return res finally: self._board.pop()
def material_value(self, board=None): if board is None: board = self.engine.current_board values = [0, 1, 3, 3, 5, 9, 0] sum = 0 for square in chess.SquareSet(chess.BB_ALL): piece = board.piece_type_at(square) if piece: sum += values[piece] return sum
def get_board_square_set(board: chess.Board) -> chess.SquareSet: """ Returns current board represented in list with 64 bits :returns chess.SquareSet """ square_set = chess.SquareSet() # Empty square set for key in board.piece_map().keys(): square_set.add(key) return square_set