// returns true if last GameState results in a draw by insufficient material, false otherwise public static bool IsDrawByInsufficientMaterial() { // initialize piece counts int w_knight_count = ChessBoard.BitCount(AI.board.white_knight); int w_bishop_count = ChessBoard.BitCount(AI.board.white_bishop); int b_knight_count = ChessBoard.BitCount(AI.board.black_knight); int b_bishop_count = ChessBoard.BitCount(AI.board.black_bishop); int w_piece_count = ChessBoard.BitCount(AI.board.white_pieces); int b_piece_count = ChessBoard.BitCount(AI.board.black_pieces); // white king v. black king if (w_piece_count == 1 && b_piece_count == 1) { return(true); } // white king v. black king and knight or bishop if (w_piece_count == 1 && b_piece_count == 2 && (b_knight_count == 1 || b_bishop_count == 1)) { return(true); } // white king and knight or bishop v. black king if (b_piece_count == 1 && w_piece_count == 2 && (w_knight_count == 1 || w_bishop_count == 1)) { return(true); } // white king and bishop(s) v. black king and bishop(s), bishops all on same color squares if ((w_piece_count - w_bishop_count) == 1 && (b_piece_count - b_bishop_count) == 1) { // initialize light/dark squares Biboards UInt64 light_squares = 0x55AA55AA55AA55AA; UInt64 dark_squares = 0xAA55AA55AA55AA55; // bishops are all on light squares if ((AI.board.white_bishop & dark_squares) == 0 && (AI.board.black_bishop & dark_squares) == 0) { return(true); } // bishops are all on dark squares if ((AI.board.white_bishop & light_squares) == 0 && (AI.board.black_bishop & light_squares) == 0) { return(true); } } // there is still sufficient material to checkmate return(false); }
// returns the king safety score for the specified color public static int GetKingSafetyScore(int player) { // initialize variables int white_king_safety = 0, black_king_safety = 0, net_king_safety = 0; // calculate white king safety score uint white_king_sq = MoveGen.GetNextSquare(AI.board.white_king); white_king_safety += BONUS_KINGSAFETY_STRONG * (ChessBoard.BitCount(W_KINGSAFETY_STRONG[white_king_sq] & AI.board.white_pawn)); white_king_safety += BONUS_KINGSAFETY_WEAK * (ChessBoard.BitCount(W_KINGSAFETY_WEAK[white_king_sq] & AI.board.white_pawn)); // calculate black king safety score uint black_king_sq = MoveGen.GetNextSquare(AI.board.black_king); black_king_safety += BONUS_KINGSAFETY_STRONG * (ChessBoard.BitCount(B_KINGSAFETY_STRONG[black_king_sq] & AI.board.black_pawn)); black_king_safety += BONUS_KINGSAFETY_WEAK * (ChessBoard.BitCount(B_KINGSAFETY_WEAK[black_king_sq] & AI.board.black_pawn)); // give penalty for being in check in end game if (IsEndGame(GetMaterialScore(ChessBoard.WHITE), GetMaterialScore(ChessBoard.BLACK))) { if (MoveGen.IsKingAttacked(ChessBoard.WHITE)) { white_king_safety += PENALTY_KING_CHECKED; } if (MoveGen.IsKingAttacked(ChessBoard.BLACK)) { black_king_safety += PENALTY_KING_CHECKED; } } // calculate net king safety score if (player == ChessBoard.WHITE) { net_king_safety += white_king_safety - black_king_safety; } else if (player == ChessBoard.BLACK) { net_king_safety += black_king_safety - white_king_safety; } // return king safety score return(net_king_safety); }
// returns the material score for the specified player public static int GetMaterialScore(int player) { // initialize variables int white_material = 0, black_material = 0, net_material = 0; int wPawns = ChessBoard.BitCount(AI.board.white_pawn); int wRooks = ChessBoard.BitCount(AI.board.white_rook); int wKnights = ChessBoard.BitCount(AI.board.white_knight); int wBishops = ChessBoard.BitCount(AI.board.white_bishop); int wQueens = ChessBoard.BitCount(AI.board.white_queen); int wTotal = wPawns + wRooks + wKnights + wBishops + wQueens; int bPawns = ChessBoard.BitCount(AI.board.black_pawn); int bRooks = ChessBoard.BitCount(AI.board.black_rook); int bKnights = ChessBoard.BitCount(AI.board.black_knight); int bBishops = ChessBoard.BitCount(AI.board.black_bishop); int bQueens = ChessBoard.BitCount(AI.board.black_queen); int bTotal = bPawns + bRooks + bKnights + bBishops + bQueens; UInt64 light_squares = 0x55AA55AA55AA55AA; UInt64 dark_squares = 0xAA55AA55AA55AA55; // calculate material score for both players white_material += PAWN_SCORE * wPawns; white_material += ROOK_SCORE * wRooks; white_material += KNIGHT_SCORE * wKnights; white_material += BISHOP_SCORE * wBishops; white_material += QUEEN_SCORE * wQueens; black_material += PAWN_SCORE * bPawns; black_material += ROOK_SCORE * bRooks; black_material += KNIGHT_SCORE * bKnights; black_material += BISHOP_SCORE * bBishops; black_material += QUEEN_SCORE * bQueens; // add bonus for bishop pair if ((AI.board.white_bishop & light_squares) != ChessBoard.EMPTY && (AI.board.white_bishop & dark_squares) != ChessBoard.EMPTY) { white_material += BONUS_BISHOP_PAIR; } if ((AI.board.black_bishop & light_squares) != ChessBoard.EMPTY && (AI.board.black_bishop & dark_squares) != ChessBoard.EMPTY) { black_material += BONUS_BISHOP_PAIR; } // if one side is ahead on material, give bonus for pieces remaining on board if (player == ChessBoard.WHITE && (white_material + wTotal) > (black_material + bTotal)) { white_material += (45 + (3 * wTotal)); black_material += (6 * bTotal); } else if (player == ChessBoard.BLACK && (black_material + bTotal) > (white_material + wTotal)) { black_material += (45 + (3 * bTotal)); white_material += (6 * wTotal); } // calculate net material score if (player == ChessBoard.WHITE) { net_material = white_material - black_material; } else if (player == ChessBoard.BLACK) { net_material = black_material - white_material; } // return material score return(net_material); }