Evaluate { private int endGameEval(Position pos, int oldScore) { int score = oldScore; if (pos.wMtrl + pos.bMtrl > 6 * rV) return score; final int wMtrlPawns = pos.wMtrlPawns; final int bMtrlPawns = pos.bMtrlPawns; final int wMtrlNoPawns = pos.wMtrl - wMtrlPawns; final int bMtrlNoPawns = pos.bMtrl - bMtrlPawns; boolean handled = false; if ((wMtrlPawns + bMtrlPawns == 0) && (wMtrlNoPawns < rV) && (bMtrlNoPawns < rV)) { return 0; } if (!handled && (pos.wMtrl == qV) && (pos.bMtrl == pV) && (pos.pieceTypeBB[Piece.WQUEEN] != 0)) { int wk = BitBoard.numberOfTrailingZeros(pos.pieceTypeBB[Piece.WKING]); int wq = BitBoard.numberOfTrailingZeros(pos.pieceTypeBB[Piece.WQUEEN]); int bk = BitBoard.numberOfTrailingZeros(pos.pieceTypeBB[Piece.BKING]); int bp = BitBoard.numberOfTrailingZeros(pos.pieceTypeBB[Piece.BPAWN]); score = evalKQKP(wk, wq, bk, bp, pos.whiteMove); handled = true; } if (!handled && (pos.wMtrl == rV) && (pos.pieceTypeBB[Piece.WROOK] != 0)) { if (pos.bMtrl == pV) { int bp = BitBoard.numberOfTrailingZeros(pos.pieceTypeBB[Piece.BPAWN]); score = krkpEval(pos.getKingSq(true), pos.getKingSq(false), bp, pos.whiteMove); handled = true; } else if ((pos.bMtrl == bV) && (pos.pieceTypeBB[Piece.BBISHOP] != 0)) { score /= 8; final int kSq = pos.getKingSq(false); final int x = Position.getX(kSq); final int y = Position.getY(kSq); if ((pos.pieceTypeBB[Piece.BBISHOP] & BitBoard.maskDarkSq) != 0) { score += (7 - distToH1A8[7-y][7-x]) * 7; } else { score += (7 - distToH1A8[7-y][x]) * 7; } handled = true; } } if (!handled && (pos.bMtrl == qV) && (pos.wMtrl == pV) && (pos.pieceTypeBB[Piece.BQUEEN] != 0)) { int bk = BitBoard.numberOfTrailingZeros(pos.pieceTypeBB[Piece.BKING]); int bq = BitBoard.numberOfTrailingZeros(pos.pieceTypeBB[Piece.BQUEEN]); int wk = BitBoard.numberOfTrailingZeros(pos.pieceTypeBB[Piece.WKING]); int wp = BitBoard.numberOfTrailingZeros(pos.pieceTypeBB[Piece.WPAWN]); score = -evalKQKP(63-bk, 63-bq, 63-wk, 63-wp, !pos.whiteMove); handled = true; } if (!handled && (pos.bMtrl == rV) && (pos.pieceTypeBB[Piece.BROOK] != 0)) { if (pos.wMtrl == pV) { int wp = BitBoard.numberOfTrailingZeros(pos.pieceTypeBB[Piece.WPAWN]); score = -krkpEval(63-pos.getKingSq(false), 63-pos.getKingSq(true), 63-wp, !pos.whiteMove); handled = true; } else if ((pos.wMtrl == bV) && (pos.pieceTypeBB[Piece.WBISHOP] != 0)) { score /= 8; final int kSq = pos.getKingSq(true); final int x = Position.getX(kSq); final int y = Position.getY(kSq); if ((pos.pieceTypeBB[Piece.WBISHOP] & BitBoard.maskDarkSq) != 0) { score -= (7 - distToH1A8[7-y][7-x]) * 7; } else { score -= (7 - distToH1A8[7-y][x]) * 7; } handled = true; } } if (!handled && (score > 0)) { if ((wMtrlPawns == 0) && (wMtrlNoPawns <= bMtrlNoPawns + bV)) { if (wMtrlNoPawns < rV) { return -pos.bMtrl / 50; } else { score /= 8; handled = true; } } else if ((pos.pieceTypeBB[Piece.WROOK] | pos.pieceTypeBB[Piece.WKNIGHT] | pos.pieceTypeBB[Piece.WQUEEN]) == 0) { if (((pos.pieceTypeBB[Piece.WPAWN] & BitBoard.maskBToHFiles) == 0) && ((pos.pieceTypeBB[Piece.WBISHOP] & BitBoard.maskLightSq) == 0) && ((pos.pieceTypeBB[Piece.BKING] & 0x0303000000000000L) != 0)) { return 0; } else if (((pos.pieceTypeBB[Piece.WPAWN] & BitBoard.maskAToGFiles) == 0) && ((pos.pieceTypeBB[Piece.WBISHOP] & BitBoard.maskDarkSq) == 0) && ((pos.pieceTypeBB[Piece.BKING] & 0xC0C0000000000000L) != 0)) { return 0; } } } if (!handled) { if (bMtrlPawns == 0) { if (wMtrlNoPawns - bMtrlNoPawns > bV) { int wKnights = Long.bitCount(pos.pieceTypeBB[Piece.WKNIGHT]); int wBishops = Long.bitCount(pos.pieceTypeBB[Piece.WBISHOP]); if ((wKnights == 2) && (pos.wMtrl == 2 * nV) && (bMtrlNoPawns == 0)) { score /= 50; } else if ((wKnights == 1) && (wBishops == 1) && (wMtrlNoPawns == nV + bV) && (bMtrlNoPawns == 0)) { score /= 10; score += nV + bV + 300; final int kSq = pos.getKingSq(false); final int x = Position.getX(kSq); final int y = Position.getY(kSq); if ((pos.pieceTypeBB[Piece.WBISHOP] & BitBoard.maskDarkSq) != 0) { score += (7 - distToH1A8[7-y][7-x]) * 10; } else { score += (7 - distToH1A8[7-y][x]) * 10; } } else { score += 300; } handled = true; } else if ((wMtrlNoPawns + bMtrlNoPawns == 0) && (wMtrlPawns == pV)) { int wp = BitBoard.numberOfTrailingZeros(pos.pieceTypeBB[Piece.WPAWN]); score = kpkEval(pos.getKingSq(true), pos.getKingSq(false), wp, pos.whiteMove); handled = true; } } } if (!handled && (score < 0)) { if ((bMtrlPawns == 0) && (bMtrlNoPawns <= wMtrlNoPawns + bV)) { if (bMtrlNoPawns < rV) { return pos.wMtrl / 50; } else { score /= 8; handled = true; } } else if ((pos.pieceTypeBB[Piece.BROOK] | pos.pieceTypeBB[Piece.BKNIGHT] | pos.pieceTypeBB[Piece.BQUEEN]) == 0) { if (((pos.pieceTypeBB[Piece.BPAWN] & BitBoard.maskBToHFiles) == 0) && ((pos.pieceTypeBB[Piece.BBISHOP] & BitBoard.maskDarkSq) == 0) && ((pos.pieceTypeBB[Piece.WKING] & 0x0303L) != 0)) { return 0; } else if (((pos.pieceTypeBB[Piece.BPAWN] & BitBoard.maskAToGFiles) == 0) && ((pos.pieceTypeBB[Piece.BBISHOP] & BitBoard.maskLightSq) == 0) && ((pos.pieceTypeBB[Piece.WKING] & 0xC0C0L) != 0)) { return 0; } } } if (!handled) { if (wMtrlPawns == 0) { if (bMtrlNoPawns - wMtrlNoPawns > bV) { int bKnights = Long.bitCount(pos.pieceTypeBB[Piece.BKNIGHT]); int bBishops = Long.bitCount(pos.pieceTypeBB[Piece.BBISHOP]); if ((bKnights == 2) && (pos.bMtrl == 2 * nV) && (wMtrlNoPawns == 0)) { score /= 50; } else if ((bKnights == 1) && (bBishops == 1) && (bMtrlNoPawns == nV + bV) && (wMtrlNoPawns == 0)) { score /= 10; score -= nV + bV + 300; final int kSq = pos.getKingSq(true); final int x = Position.getX(kSq); final int y = Position.getY(kSq); if ((pos.pieceTypeBB[Piece.BBISHOP] & BitBoard.maskDarkSq) != 0) { score -= (7 - distToH1A8[7-y][7-x]) * 10; } else { score -= (7 - distToH1A8[7-y][x]) * 10; } } else { score -= 300; } handled = true; } else if ((wMtrlNoPawns + bMtrlNoPawns == 0) && (bMtrlPawns == pV)) { int bp = BitBoard.numberOfTrailingZeros(pos.pieceTypeBB[Piece.BPAWN]); score = -kpkEval(63-pos.getKingSq(false), 63-pos.getKingSq(true), 63-bp, !pos.whiteMove); handled = true; } } } return score; } Evaluate(); final int evalPos(Position pos);  }
@Test public void testEndGameEval() throws ChessParseError { System.out.println("endGameEval"); Position pos = new Position(); pos.setPiece(Position.getSquare(4, 1), Piece.WKING); pos.setPiece(Position.getSquare(4, 6), Piece.BKING); int score = evalWhite(pos); assertEquals(0, score); pos.setPiece(Position.getSquare(3, 1), Piece.WBISHOP); score = evalWhite(pos); assertTrue(Math.abs(score) < 50); pos.setPiece(Position.getSquare(3, 1), Piece.WKNIGHT); score = evalWhite(pos); assertTrue(Math.abs(score) < 50); pos.setPiece(Position.getSquare(3, 1), Piece.WROOK); score = evalWhite(pos); final int rV = Evaluate.rV; assertTrue(Math.abs(score) > rV + 100); pos.setPiece(Position.getSquare(3, 6), Piece.BBISHOP); score = evalWhite(pos); final int bV = Evaluate.bV; assertTrue(score >= 0); assertTrue(score < rV - bV); pos.setPiece(Position.getSquare(5, 6), Piece.BROOK); score = evalWhite(pos); assertTrue(score <= 0); assertTrue(-score < bV); pos.setPiece(Position.getSquare(2, 6), Piece.BBISHOP); score = evalWhite(pos); assertTrue(-score > bV * 2 + 100); pos = TextIO.readFEN("8/3bk3/8/8/8/3P4/3RK3/8 w - - 0 1"); score = evalWhite(pos); final int pV = Evaluate.pV; assertTrue(score > rV + pV - bV - 100); pos = TextIO.readFEN("8/8/4k3/8/8/3NK3/3N4/8 w - - 0 1"); score = evalWhite(pos); assertTrue(Math.abs(score) < 50); final int nV = Evaluate.nV; pos = TextIO.readFEN("8/8/8/4k3/N6N/P2K4/8/8 b - - 0 66"); score = evalWhite(pos); assertTrue(score > nV * 2); pos = TextIO.readFEN("8/8/3k4/8/8/3NK3/2B5/8 b - - 0 1"); score = evalWhite(pos); assertTrue(score > bV + nV + 150); score = moveScore(pos, "Kc6"); assertTrue(score > 0); score = moveScore(pos, "Ke6"); assertTrue(score < 0); pos = TextIO.readFEN("rk/p/8/8/8/8/NKR/8 w - - 0 1"); score = evalWhite(pos); assertTrue(score < nV - 2 * pV); pos = TextIO.readFEN("6B1/8/8/8/8/2k5/4r3/2K5 w - - 0 93"); score = evalWhite(pos); assertTrue(score >= -pV); score = moveScore(pos, "Kd1"); assertTrue(score < 0); score = moveScore(pos, "Kb1"); assertTrue(score > 0); }