/// KP vs K. This endgame is evaluated with the help of a bitbase. internal static Value Endgame_KPK(Color strongerSide, Position pos) { Color weakerSide = strongerSide ^ 1; Debug.Assert(pos.non_pawn_material(strongerSide) == ValueC.VALUE_ZERO); Debug.Assert(pos.non_pawn_material(weakerSide) == ValueC.VALUE_ZERO); Debug.Assert(pos.piece_count(strongerSide, PieceTypeC.PAWN) == 1); Debug.Assert(pos.piece_count(weakerSide, PieceTypeC.PAWN) == 0); Square wksq, bksq, wpsq; Color stm; if (strongerSide == ColorC.WHITE) { wksq = pos.king_square(ColorC.WHITE); bksq = pos.king_square(ColorC.BLACK); wpsq = pos.pieceList[ColorC.WHITE][PieceTypeC.PAWN][0]; stm = pos.sideToMove; } else { wksq = Utils.flip_S(pos.king_square(ColorC.BLACK)); bksq = Utils.flip_S(pos.king_square(ColorC.WHITE)); wpsq = Utils.flip_S(pos.pieceList[ColorC.BLACK][PieceTypeC.PAWN][0]); stm = Utils.flip_C(pos.sideToMove); } if (Utils.file_of(wpsq) >= FileC.FILE_E) { wksq = Utils.mirror(wksq); bksq = Utils.mirror(bksq); wpsq = Utils.mirror(wpsq); } if (KPKPosition.probe_kpk_bitbase(wksq, wpsq, bksq, stm) == 0) { return(ValueC.VALUE_DRAW); } Value result = ValueC.VALUE_KNOWN_WIN + Constants.PawnValueEndgame + Utils.rank_of(wpsq); return(strongerSide == pos.sideToMove ? result : -result); }
/// K and a pawn vs K and a pawn. This is done by removing the weakest side's /// pawn and probing the KP vs K bitbase: If the weakest side has a draw without /// the pawn, she probably has at least a draw with the pawn as well. The exception /// is when the stronger side's pawn is far advanced and not on a rook file; in /// this case it is often possible to win (e.g. 8/4k3/3p4/3P4/6K1/8/8/8 w - - 0 1). internal static ScaleFactor Endgame_KPKP(Color strongerSide, Position pos) { Color weakerSide = strongerSide ^ 1; Debug.Assert(pos.non_pawn_material(strongerSide) == ValueC.VALUE_ZERO); Debug.Assert(pos.non_pawn_material(weakerSide) == ValueC.VALUE_ZERO); Debug.Assert(pos.piece_count(ColorC.WHITE, PieceTypeC.PAWN) == 1); Debug.Assert(pos.piece_count(ColorC.BLACK, PieceTypeC.PAWN) == 1); Square wksq = pos.king_square(strongerSide); Square bksq = pos.king_square(weakerSide); Square wpsq = pos.pieceList[strongerSide][PieceTypeC.PAWN][0]; Color stm = pos.sideToMove; if (strongerSide == ColorC.BLACK) { wksq = Utils.flip_S(wksq); bksq = Utils.flip_S(bksq); wpsq = Utils.flip_S(wpsq); stm = Utils.flip_C(stm); } if (Utils.file_of(wpsq) >= FileC.FILE_E) { wksq = Utils.mirror(wksq); bksq = Utils.mirror(bksq); wpsq = Utils.mirror(wpsq); } // If the pawn has advanced to the fifth rank or further, and is not a // rook pawn, it's too dangerous to assume that it's at least a draw. if (Utils.rank_of(wpsq) >= RankC.RANK_5 && Utils.file_of(wpsq) != FileC.FILE_A) { return(ScaleFactorC.SCALE_FACTOR_NONE); } // Probe the KPK bitbase with the weakest side's pawn removed. If it's a draw, // it's probably at least a draw even with the pawn. return((KPKPosition.probe_kpk_bitbase(wksq, wpsq, bksq, stm) != 0) ? ScaleFactorC.SCALE_FACTOR_NONE : ScaleFactorC.SCALE_FACTOR_DRAW); }