Subversion Repositories Games.Chess Giants

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.     Texel - A UCI chess engine.
  3.     Copyright (C) 2012-2014  Peter Ă–sterlund, peterosterlund2@gmail.com
  4.  
  5.     This program is free software: you can redistribute it and/or modify
  6.     it under the terms of the GNU General Public License as published by
  7.     the Free Software Foundation, either version 3 of the License, or
  8.     (at your option) any later version.
  9.  
  10.     This program is distributed in the hope that it will be useful,
  11.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.     GNU General Public License for more details.
  14.  
  15.     You should have received a copy of the GNU General Public License
  16.     along with this program.  If not, see <http://www.gnu.org/licenses/>.
  17. */
  18.  
  19. /*
  20.  * endGameEval.cpp
  21.  *
  22.  *  Created on: Dec 26, 2014
  23.  *      Author: petero
  24.  */
  25.  
  26. #include "endGameEval.hpp"
  27. #include "position.hpp"
  28. #include "piece.hpp"
  29. #include "parameters.hpp"
  30.  
  31. const int EndGameEval::distToH1A8[8][8] = { { 0, 1, 2, 3, 4, 5, 6, 7 },
  32.                                             { 1, 2, 3, 4, 5, 6, 7, 6 },
  33.                                             { 2, 3, 4, 5, 6, 7, 6, 5 },
  34.                                             { 3, 4, 5, 6, 7, 6, 5, 4 },
  35.                                             { 4, 5, 6, 7, 6, 5, 4, 3 },
  36.                                             { 5, 6, 7, 6, 5, 4, 3, 2 },
  37.                                             { 6, 7, 6, 5, 4, 3, 2, 1 },
  38.                                             { 7, 6, 5, 4, 3, 2, 1, 0 } };
  39.  
  40. const int EndGameEval::winKingTable[64] = {
  41.     0,   4,  10,  10,  10,  10,   4,   0,
  42.     4,  15,  19,  20,  20,  19,  15,   4,
  43.    10,  19,  25,  25,  25,  25,  19,  10,
  44.    10,  20,  25,  25,  25,  25,  20,  10,
  45.    10,  20,  25,  25,  25,  25,  20,  10,
  46.    10,  19,  25,  25,  25,  25,  19,  10,
  47.     4,  15,  19,  20,  20,  19,  15,   4,
  48.     0,   4,  10,  10,  10,  10,   4,   0
  49. };
  50.  
  51.  
  52. template int EndGameEval::endGameEval<false>(const Position&, U64, int);
  53. template int EndGameEval::endGameEval<true>(const Position&, U64, int);
  54.  
  55. /** Implements special knowledge for some endgame situations. */
  56. template <bool doEval>
  57. int
  58. EndGameEval::endGameEval(const Position& pos, U64 passedPawns, int oldScore) {
  59.     int score = oldScore;
  60.     const int wMtrlPawns = pos.wMtrlPawns();
  61.     const int bMtrlPawns = pos.bMtrlPawns();
  62.     const int wMtrlNoPawns = pos.wMtrl() - wMtrlPawns;
  63.     const int bMtrlNoPawns = pos.bMtrl() - bMtrlPawns;
  64.  
  65.     // Handle special endgames
  66.     using MI = MatId;
  67.     switch (pos.materialId()) {
  68.     case 0:
  69.     case MI::WN: case MI::BN: case MI::WB: case MI::BB:
  70.     case MI::WN + MI::BN: case MI::WN + MI::BB:
  71.     case MI::WB + MI::BN: case MI::WB + MI::BB:
  72.         if (!doEval) return 1;
  73.         return 0; // King + minor piece vs king + minor piece is a draw
  74.     case MI::WQ + MI::BP: {
  75.         if (!doEval) return 1;
  76.         int wk = pos.getKingSq(true);
  77.         int wq = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::WQUEEN));
  78.         int bk = pos.getKingSq(false);
  79.         int bp = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::BPAWN));
  80.         return kqkpEval(wk, wq, bk, bp, pos.isWhiteMove(), score);
  81.     }
  82.     case MI::BQ + MI::WP: {
  83.         if (!doEval) return 1;
  84.         int bk = pos.getKingSq(false);
  85.         int bq = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::BQUEEN));
  86.         int wk = pos.getKingSq(true);
  87.         int wp = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::WPAWN));
  88.         return -kqkpEval(63-bk, 63-bq, 63-wk, 63-wp, !pos.isWhiteMove(), -score);
  89.     }
  90.     case MI::WQ: {
  91.         if (!doEval) return 1;
  92.         if (!pos.isWhiteMove() &&
  93.             (pos.pieceTypeBB(Piece::BKING) & BitBoard::maskCorners) &&
  94.             (pos.pieceTypeBB(Piece::WQUEEN) & BitBoard::sqMask(C2,B3,F2,G3,B6,C7,G6,F7)) &&
  95.             (BitBoard::getTaxiDistance(pos.getKingSq(false),
  96.                                        BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::WQUEEN))) == 3))
  97.             return 0;
  98.         break;
  99.     }
  100.     case MI::BQ: {
  101.         if (!doEval) return 1;
  102.         if (pos.isWhiteMove() &&
  103.             (pos.pieceTypeBB(Piece::WKING) & BitBoard::maskCorners) &&
  104.             (pos.pieceTypeBB(Piece::BQUEEN) & BitBoard::sqMask(C2,B3,F2,G3,B6,C7,G6,F7)) &&
  105.             (BitBoard::getTaxiDistance(pos.getKingSq(true),
  106.                                        BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::BQUEEN))) == 3))
  107.             return 0;
  108.         break;
  109.     }
  110.     case MI::WR + MI::BP: {
  111.         if (!doEval) return 1;
  112.         int bp = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::BPAWN));
  113.         return krkpEval(pos.getKingSq(true), pos.getKingSq(false),
  114.                         bp, pos.isWhiteMove(), score);
  115.     }
  116.     case MI::BR + MI::WP: {
  117.         if (!doEval) return 1;
  118.         int wp = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::WPAWN));
  119.         return -krkpEval(63-pos.getKingSq(false), 63-pos.getKingSq(true),
  120.                          63-wp, !pos.isWhiteMove(), -score);
  121.     }
  122.     case MI::WR + MI::BB: {
  123.         if (!doEval) return 1;
  124.         score /= 8;
  125.         const int kSq = pos.getKingSq(false);
  126.         const int x = Position::getX(kSq);
  127.         const int y = Position::getY(kSq);
  128.         if ((pos.pieceTypeBB(Piece::BBISHOP) & BitBoard::maskDarkSq) != 0)
  129.             score += (7 - distToH1A8[7-y][7-x]) * 7;
  130.         else
  131.             score += (7 - distToH1A8[7-y][x]) * 7;
  132.         return score;
  133.     }
  134.     case MI::BR + MI::WB: {
  135.         if (!doEval) return 1;
  136.         score /= 8;
  137.         const int kSq = pos.getKingSq(true);
  138.         const int x = Position::getX(kSq);
  139.         const int y = Position::getY(kSq);
  140.         if ((pos.pieceTypeBB(Piece::WBISHOP) & BitBoard::maskDarkSq) != 0)
  141.             score -= (7 - distToH1A8[7-y][7-x]) * 7;
  142.         else
  143.             score -= (7 - distToH1A8[7-y][x]) * 7;
  144.         return score;
  145.     }
  146.     case MI::WR + MI::WP + MI::BR: {
  147.         if (!doEval) return 1;
  148.         int wk = pos.getKingSq(true);
  149.         int bk = pos.getKingSq(false);
  150.         int wp = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::WPAWN));
  151.         int wr = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::WROOK));
  152.         int br = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::BROOK));
  153.         return krpkrEval(wk, bk, wp, wr, br, pos.isWhiteMove());
  154.     }
  155.     case MI::BR + MI::BP + MI::WR: {
  156.         if (!doEval) return 1;
  157.         int wk = pos.getKingSq(true);
  158.         int bk = pos.getKingSq(false);
  159.         int bp = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::BPAWN));
  160.         int wr = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::WROOK));
  161.         int br = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::BROOK));
  162.         return -krpkrEval(63-bk, 63-wk, 63-bp, 63-br, 63-wr, !pos.isWhiteMove());
  163.     }
  164.     case MI::WR + MI::WP + MI::BR + MI::BP: {
  165.         if (!doEval) return 1;
  166.         int wk = pos.getKingSq(true);
  167.         int bk = pos.getKingSq(false);
  168.         int wp = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::WPAWN));
  169.         int wr = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::WROOK));
  170.         int br = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::BROOK));
  171.         int bp = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::BPAWN));
  172.         return krpkrpEval(wk, bk, wp, wr, br, bp, pos.isWhiteMove(), score);
  173.     }
  174.     case MI::WN * 2:
  175.     case MI::BN * 2:
  176.         if (!doEval) return 1;
  177.         return 0; // KNNK is a draw
  178.     case MI::WN + MI::WB: {
  179.         if (!doEval) return 1;
  180.         bool darkBishop = (pos.pieceTypeBB(Piece::WBISHOP) & BitBoard::maskDarkSq) != 0;
  181.         return kbnkEval(pos.getKingSq(true), pos.getKingSq(false), darkBishop);
  182.     }
  183.     case MI::BN + MI::BB: {
  184.         if (!doEval) return 1;
  185.         bool darkBishop = (pos.pieceTypeBB(Piece::BBISHOP) & BitBoard::maskDarkSq) != 0;
  186.         return -kbnkEval(63-pos.getKingSq(false), 63-pos.getKingSq(true), darkBishop);
  187.     }
  188.     case MI::WP: {
  189.         if (!doEval) return 1;
  190.         int wp = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::WPAWN));
  191.         return kpkEval(pos.getKingSq(true), pos.getKingSq(false),
  192.                        wp, pos.isWhiteMove());
  193.     }
  194.     case MI::BP: {
  195.         if (!doEval) return 1;
  196.         int bp = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::BPAWN));
  197.         return -kpkEval(63-pos.getKingSq(false), 63-pos.getKingSq(true),
  198.                         63-bp, !pos.isWhiteMove());
  199.     }
  200.     case MI::WP + MI::BP: {
  201.         if (!doEval) return 1;
  202.         int wk = pos.getKingSq(true);
  203.         int bk = pos.getKingSq(false);
  204.         int wp = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::WPAWN));
  205.         int bp = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::BPAWN));
  206.         if (kpkpEval(wk, bk, wp, bp, score))
  207.             return score;
  208.         break;
  209.     }
  210.     case MI::WB + MI::WP + MI::BB: {
  211.         if (!doEval) return 1;
  212.         int wb = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::WBISHOP));
  213.         int wp = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::WPAWN));
  214.         int bb = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::BBISHOP));
  215.         return kbpkbEval(pos.getKingSq(true), wb, wp, pos.getKingSq(false), bb, score);
  216.     }
  217.     case MI::BB + MI::BP + MI::WB: {
  218.         if (!doEval) return 1;
  219.         int bb = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::BBISHOP));
  220.         int bp = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::BPAWN));
  221.         int wb = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::WBISHOP));
  222.         return -kbpkbEval(63-pos.getKingSq(false), 63-bb, 63-bp, 63-pos.getKingSq(true), 63-wb, -score);
  223.     }
  224.     case MI::WB + MI::WP + MI::BN: {
  225.         if (!doEval) return 1;
  226.         int wb = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::WBISHOP));
  227.         int wp = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::WPAWN));
  228.         int bn = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::BKNIGHT));
  229.         return kbpknEval(pos.getKingSq(true), wb, wp, pos.getKingSq(false), bn, score);
  230.     }
  231.     case MI::BB + MI::BP + MI::WN: {
  232.         if (!doEval) return 1;
  233.         int bb = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::BBISHOP));
  234.         int bp = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::BPAWN));
  235.         int wn = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::WKNIGHT));
  236.         return -kbpknEval(63-pos.getKingSq(false), 63-bb, 63-bp, 63-pos.getKingSq(true), 63-wn, -score);
  237.     }
  238.     case MI::WN + MI::WP + MI::BB: {
  239.         if (!doEval) return 1;
  240.         int wn = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::WKNIGHT));
  241.         int wp = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::WPAWN));
  242.         int bb = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::BBISHOP));
  243.         return knpkbEval(pos.getKingSq(true), wn, wp, pos.getKingSq(false), bb,
  244.                          score, pos.isWhiteMove());
  245.     }
  246.     case MI::BN + MI::BP + MI::WB: {
  247.         if (!doEval) return 1;
  248.         int bn = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::BKNIGHT));
  249.         int bp = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::BPAWN));
  250.         int wb = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::WBISHOP));
  251.         return -knpkbEval(63-pos.getKingSq(false), 63-bn, 63-bp, 63-pos.getKingSq(true), 63-wb,
  252.                           -score, !pos.isWhiteMove());
  253.     }
  254.     case MI::WN + MI::WP: {
  255.         if (!doEval) return 1;
  256.         int wn = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::WKNIGHT));
  257.         int wp = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::WPAWN));
  258.         return knpkEval(pos.getKingSq(true), wn, wp, pos.getKingSq(false),
  259.                         score, pos.isWhiteMove());
  260.     }
  261.     case MI::BN + MI::BP: {
  262.         if (!doEval) return 1;
  263.         int bn = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::BKNIGHT));
  264.         int bp = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::BPAWN));
  265.         return -knpkEval(63-pos.getKingSq(false), 63-bn, 63-bp, 63-pos.getKingSq(true),
  266.                          -score, !pos.isWhiteMove());
  267.     }
  268.     }
  269.  
  270.     // QvsRP fortress detection
  271.     if (pos.pieceTypeBB(Piece::WQUEEN) && (pos.wMtrl() == qV) &&
  272.         pos.pieceTypeBB(Piece::BROOK) && pos.pieceTypeBB(Piece::BPAWN) &&
  273.         (pos.bMtrl() - pos.bMtrlPawns() < rV * 2)) {
  274.         if (!doEval) return 1;
  275.         if (score > 0) {
  276.             int wk = pos.getKingSq(true);
  277.             int wq = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::WQUEEN));
  278.             int bk = pos.getKingSq(false);
  279.             int br = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::BROOK));
  280.             U64 m = pos.pieceTypeBB(Piece::BPAWN);
  281.             int newScore = score;
  282.             while (m) {
  283.                 int bp = BitBoard::extractSquare(m);
  284.                 int s2 = kqkrpEval(wk, wq, bk, br, bp, pos.isWhiteMove(), score);
  285.                 newScore = std::min(newScore, s2);
  286.             }
  287.             if (newScore < score)
  288.                 return newScore;
  289.         }
  290.     }
  291.     if (pos.pieceTypeBB(Piece::BQUEEN) && (pos.bMtrl() == qV) &&
  292.         pos.pieceTypeBB(Piece::WROOK) && pos.pieceTypeBB(Piece::WPAWN) &&
  293.         (pos.wMtrl() - pos.wMtrlPawns() < rV * 2)) {
  294.         if (!doEval) return 1;
  295.         if (score < 0) {
  296.             int bk = pos.getKingSq(false);
  297.             int bq = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::BQUEEN));
  298.             int wk = pos.getKingSq(true);
  299.             int wr = BitBoard::numberOfTrailingZeros(pos.pieceTypeBB(Piece::WROOK));
  300.             U64 m = pos.pieceTypeBB(Piece::WPAWN);
  301.             int newScore = score;
  302.             while (m) {
  303.                 int wp = BitBoard::extractSquare(m);
  304.                 int s2 = -kqkrpEval(63-bk, 63-bq, 63-wk, 63-wr, 63-wp, !pos.isWhiteMove(), -score);
  305.                 newScore = std::max(newScore, s2);
  306.             }
  307.             if (newScore > score)
  308.                 return newScore;
  309.         }
  310.     }
  311.  
  312.     const int nWN = BitBoard::bitCount(pos.pieceTypeBB(Piece::WKNIGHT));
  313.     const int nBN = BitBoard::bitCount(pos.pieceTypeBB(Piece::BKNIGHT));
  314.     const int nWB1 = BitBoard::bitCount(pos.pieceTypeBB(Piece::WBISHOP) & BitBoard::maskLightSq);
  315.     const int nWB2 = BitBoard::bitCount(pos.pieceTypeBB(Piece::WBISHOP) & BitBoard::maskDarkSq);
  316.     const int nBB1 = BitBoard::bitCount(pos.pieceTypeBB(Piece::BBISHOP) & BitBoard::maskLightSq);
  317.     const int nBB2 = BitBoard::bitCount(pos.pieceTypeBB(Piece::BBISHOP) & BitBoard::maskDarkSq);
  318.     const int qV = ::qV;
  319.  
  320.     if (pos.materialId() == MI::WB * 2 + MI::BN) {
  321.         if (!doEval) return 1;
  322.         if (nWB1 == 1)
  323.             return 100 + mateEval(pos.getKingSq(true), pos.getKingSq(false));
  324.     }
  325.     if (pos.materialId() == MI::BB * 2 + MI::WN) {
  326.         if (!doEval) return 1;
  327.         if (nBB1 == 1)
  328.             return -(100 + mateEval(pos.getKingSq(false), pos.getKingSq(true)));
  329.     }
  330.  
  331.     // Bonus for K[BN][BN]KQ
  332.     if ((pos.bMtrl() == qV) && pos.pieceTypeBB(Piece::BQUEEN) && ((nWN >= 2) || (nWB1 + nWB2 >= 2))) {
  333.         if (!doEval) return 1;
  334.         if ((score < 0) && ((nWN >= 2) || ((nWB1 >= 1) && (nWB2 >= 1))))
  335.             return -((pos.bMtrl() - pos.wMtrl()) / 8 + mateEval(pos.getKingSq(false), pos.getKingSq(true)));
  336.     }
  337.     if ((pos.wMtrl() == qV) && pos.pieceTypeBB(Piece::WQUEEN) && ((nBN >= 2) || (nBB1 + nBB2 >= 2))) {
  338.         if (!doEval) return 1;
  339.         if ((score > 0) && ((nBN >= 2) || ((nBB1 >= 1) && (nBB2 >= 1))))
  340.             return (pos.wMtrl() - pos.bMtrl()) / 8 + mateEval(pos.getKingSq(true), pos.getKingSq(false));
  341.     }
  342.     if ((pos.bMtrl() == qV) && pos.pieceTypeBB(Piece::BQUEEN) && ((nWN >= 1) && (nWB1 + nWB2 >= 1))) {
  343.         if (!doEval) return 1;
  344.         if (score < 0)
  345.             return -((pos.bMtrl() - pos.wMtrl()) / 2 + mateEval(pos.getKingSq(false), pos.getKingSq(true)));
  346.     }
  347.     if ((pos.wMtrl() == qV) && pos.pieceTypeBB(Piece::WQUEEN) && ((nBN >= 1) && (nBB1 + nBB2 >= 1))) {
  348.         if (!doEval) return 1;
  349.         if (score > 0)
  350.             return (pos.wMtrl() - pos.bMtrl()) / 2 + mateEval(pos.getKingSq(true), pos.getKingSq(false));
  351.     }
  352.  
  353.     // Bonus for KRK
  354.     if ((pos.bMtrl() == 0) && pos.pieceTypeBB(Piece::WROOK)) {
  355.         if (!doEval) return 1;
  356.         return 400 + pos.wMtrl() - pos.bMtrl() + mateEval(pos.getKingSq(true), pos.getKingSq(false));
  357.     }
  358.     if ((pos.wMtrl() == 0) && pos.pieceTypeBB(Piece::BROOK)) {
  359.         if (!doEval) return 1;
  360.         return -(400 + pos.bMtrl() - pos.wMtrl() + mateEval(pos.getKingSq(false), pos.getKingSq(true)));
  361.     }
  362.  
  363.     // Bonus for KQK[BN]
  364.     const int bV = ::bV;
  365.     const int nV = ::nV;
  366.     if (pos.pieceTypeBB(Piece::WQUEEN) && (bMtrlPawns == 0) && (pos.bMtrl() <= std::max(bV,nV))) {
  367.         if (!doEval) return 1;
  368.         return 200 + pos.wMtrl() - pos.bMtrl() + mateEval(pos.getKingSq(true), pos.getKingSq(false));
  369.     }
  370.     if (pos.pieceTypeBB(Piece::BQUEEN) && (wMtrlPawns == 0) && (pos.wMtrl() <= std::max(bV,nV))) {
  371.         if (!doEval) return 1;
  372.         return -(200 + pos.bMtrl() - pos.wMtrl() + mateEval(pos.getKingSq(false), pos.getKingSq(true)));
  373.     }
  374.  
  375.     // Bonus for KQK
  376.     if ((pos.bMtrl() == 0) && pos.pieceTypeBB(Piece::WQUEEN)) {
  377.         if (!doEval) return 1;
  378.         return 100 + pos.wMtrl() - pos.bMtrl() + mateEval(pos.getKingSq(true), pos.getKingSq(false));
  379.     }
  380.     if ((pos.wMtrl() == 0) && pos.pieceTypeBB(Piece::BQUEEN)) {
  381.         if (!doEval) return 1;
  382.         return -(100 + pos.bMtrl() - pos.wMtrl() + mateEval(pos.getKingSq(false), pos.getKingSq(true)));
  383.     }
  384.  
  385.     if (pos.pieceTypeBB(Piece::WROOK, Piece::WKNIGHT, Piece::WQUEEN) == 0) {
  386.         if (!doEval) return 1;
  387.         if ((score > 0) && isBishopPawnDraw<true>(pos))
  388.             return 0;
  389.     }
  390.     if (pos.pieceTypeBB(Piece::BROOK, Piece::BKNIGHT, Piece::BQUEEN) == 0) {
  391.         if (!doEval) return 1;
  392.         if ((score < 0) && isBishopPawnDraw<false>(pos))
  393.             return 0;
  394.     }
  395.  
  396.     // Give bonus/penalty if advantage is/isn't large enough to win
  397.     if ((wMtrlPawns == 0) && (wMtrlNoPawns <= bMtrlNoPawns + bV)) {
  398.         if (!doEval) return 1;
  399.         if (score > 0) {
  400.             if (wMtrlNoPawns < rV)
  401.                 return -pos.bMtrl() / 50;
  402.             else
  403.                 return score / 8;        // Too little excess material, probably draw
  404.         }
  405.     }
  406.     if ((bMtrlPawns == 0) && (bMtrlNoPawns <= wMtrlNoPawns + bV)) {
  407.         if (!doEval) return 1;
  408.         if (score < 0) {
  409.             if (bMtrlNoPawns < rV)
  410.                 return pos.wMtrl() / 50;
  411.             else
  412.                 return score / 8;        // Too little excess material, probably draw
  413.         }
  414.     }
  415.  
  416.     if ((bMtrlPawns == 0) && (wMtrlNoPawns - bMtrlNoPawns > bV)) {
  417.         if (!doEval) return 1;
  418.         return score + 300;       // Enough excess material, should win
  419.     }
  420.     if ((wMtrlPawns == 0) && (bMtrlNoPawns - wMtrlNoPawns > bV)) {
  421.         if (!doEval) return 1;
  422.         return score - 300;       // Enough excess material, should win
  423.     }
  424.  
  425.     // Give bonus for advantage larger than KRKP, to avoid evaluation discontinuity
  426.     if ((pos.bMtrl() == pV) && pos.pieceTypeBB(Piece::WROOK) && (pos.wMtrl() > rV)) {
  427.         if (!doEval) return 1;
  428.         return score + krkpBonus;
  429.     }
  430.     if ((pos.wMtrl() == pV) && pos.pieceTypeBB(Piece::BROOK) && (pos.bMtrl() > rV)) {
  431.         if (!doEval) return 1;
  432.         return score - krkpBonus;
  433.     }
  434.  
  435.     // Bonus for KRPKN
  436.     if (pos.pieceTypeBB(Piece::WROOK) && pos.pieceTypeBB(Piece::WPAWN) &&
  437.         !pos.pieceTypeBB(Piece::BBISHOP) && (pos.bMtrl() == nV)  && (bMtrlPawns == 0)) {
  438.         if (!doEval) return 1;
  439.         return score + krpknBonus;
  440.     }
  441.     if (pos.pieceTypeBB(Piece::BROOK) && pos.pieceTypeBB(Piece::BPAWN) &&
  442.         !pos.pieceTypeBB(Piece::WBISHOP) && (pos.wMtrl() == nV)  && (wMtrlPawns == 0)) {
  443.         if (!doEval) return 1;
  444.         return score - krpknBonus;
  445.     }
  446.  
  447.     // Bonus for KRPKB
  448.     int krpkbAdjustment = 0;
  449.     if (pos.pieceTypeBB(Piece::WROOK) && pos.pieceTypeBB(Piece::WPAWN) &&
  450.         !pos.pieceTypeBB(Piece::BKNIGHT) && (pos.bMtrl() == bV)  && (bMtrlPawns == 0)) {
  451.         if (!doEval) return 1;
  452.         score += krpkbBonus;
  453.         krpkbAdjustment += krpkbBonus;
  454.     }
  455.     if (pos.pieceTypeBB(Piece::BROOK) && pos.pieceTypeBB(Piece::BPAWN) &&
  456.         !pos.pieceTypeBB(Piece::WKNIGHT) && (pos.wMtrl() == bV)  && (wMtrlPawns == 0)) {
  457.         if (!doEval) return 1;
  458.         score -= krpkbBonus;
  459.         krpkbAdjustment += krpkbBonus;
  460.     }
  461.  
  462.     // Penalty for KRPKB when pawn is on a/h file
  463.      if ((wMtrlNoPawns == rV) && (wMtrlPawns <= pV) && pos.pieceTypeBB(Piece::BBISHOP)) {
  464.         if (!doEval) return 1;
  465.         if (score - krpkbAdjustment > 0) {
  466.             U64 pMask = pos.pieceTypeBB(Piece::WPAWN);
  467.             U64 bMask = pos.pieceTypeBB(Piece::BBISHOP);
  468.             if (((pMask & BitBoard::maskFile[0]) && (bMask & BitBoard::maskDarkSq)) ||
  469.                 ((pMask & BitBoard::maskFile[7]) && (bMask & BitBoard::maskLightSq))) {
  470.                 score = (score - krpkbAdjustment) * krpkbPenalty / 128;
  471.                 return score;
  472.             }
  473.         }
  474.     }
  475.     if ((bMtrlNoPawns == rV) && (bMtrlPawns <= pV) && pos.pieceTypeBB(Piece::WBISHOP)) {
  476.         if (!doEval) return 1;
  477.         if (score + krpkbAdjustment < 0) {
  478.             U64 pMask = pos.pieceTypeBB(Piece::BPAWN);
  479.             U64 bMask = pos.pieceTypeBB(Piece::WBISHOP);
  480.             if (((pMask & BitBoard::maskFile[0]) && (bMask & BitBoard::maskLightSq)) ||
  481.                 ((pMask & BitBoard::maskFile[7]) && (bMask & BitBoard::maskDarkSq))) {
  482.                 score = (score + krpkbAdjustment) * krpkbPenalty / 128;
  483.                 return score;
  484.             }
  485.         }
  486.     }
  487.  
  488.     auto getPawnAsymmetry = [passedPawns, &pos]() {
  489.         int f1 = BitBoard::southFill(pos.pieceTypeBB(Piece::WPAWN)) & 0xff;
  490.         int f2 = BitBoard::southFill(pos.pieceTypeBB(Piece::BPAWN)) & 0xff;
  491.         int asymmetry = BitBoard::bitCount((f1 & ~f2) | (f2 & ~f1));
  492.         U64 passedPawnsW = passedPawns & pos.pieceTypeBB(Piece::WPAWN);
  493.         U64 passedPawnsB = passedPawns & pos.pieceTypeBB(Piece::BPAWN);
  494.         asymmetry += BitBoard::bitCount(passedPawnsW) + BitBoard::bitCount(passedPawnsB);
  495.         return asymmetry;
  496.     };
  497.  
  498.     // Account for draw factor in rook endgames
  499.     if ((BitBoard::bitCount(pos.pieceTypeBB(Piece::WROOK)) == 1) &&
  500.         (BitBoard::bitCount(pos.pieceTypeBB(Piece::BROOK)) == 1) &&
  501.         (pos.pieceTypeBB(Piece::WQUEEN, Piece::WBISHOP, Piece::WKNIGHT,
  502.                          Piece::BQUEEN, Piece::BBISHOP, Piece::BKNIGHT) == 0) &&
  503.         (BitBoard::bitCount(pos.pieceTypeBB(Piece::WPAWN, Piece::BPAWN)) > 1)) {
  504.         if (!doEval) return 1;
  505.         int asymmetry = getPawnAsymmetry();
  506.         score = score * rookEGDrawFactor[std::min(asymmetry, 6)] / 128;
  507.         return score;
  508.     }
  509.  
  510.     // Correction for draw factor in RvsB endgames
  511.     if ((BitBoard::bitCount(pos.pieceTypeBB(Piece::WROOK)) == 1) &&
  512.         (BitBoard::bitCount(pos.pieceTypeBB(Piece::BBISHOP)) == 1) &&
  513.         (pos.pieceTypeBB(Piece::WQUEEN, Piece::WBISHOP, Piece::WKNIGHT,
  514.                          Piece::BQUEEN, Piece::BROOK, Piece::BKNIGHT) == 0) &&
  515.         (wMtrlPawns - bMtrlPawns == -pV)) {
  516.         if (!doEval) return 1;
  517.         int asymmetry = getPawnAsymmetry();
  518.         score = score * RvsBPDrawFactor[std::min(asymmetry, 6)] / 128;
  519.         return score;
  520.     }
  521.     // Correction for draw factor in RvsB endgames
  522.     if ((BitBoard::bitCount(pos.pieceTypeBB(Piece::BROOK)) == 1) &&
  523.         (BitBoard::bitCount(pos.pieceTypeBB(Piece::WBISHOP)) == 1) &&
  524.         (pos.pieceTypeBB(Piece::BQUEEN, Piece::BBISHOP, Piece::BKNIGHT,
  525.                          Piece::WQUEEN, Piece::WROOK, Piece::WKNIGHT) == 0) &&
  526.         (wMtrlPawns - bMtrlPawns == pV)) {
  527.         if (!doEval) return 1;
  528.         int asymmetry = getPawnAsymmetry();
  529.         score = score * RvsBPDrawFactor[std::min(asymmetry, 6)] / 128;
  530.         return score;
  531.     }
  532.  
  533.     if (!doEval) return 0;
  534.     return score;
  535. }
  536.  
  537. int
  538. EndGameEval::mateEval(int k1, int k2) {
  539.     static const int loseKingTable[64] = {
  540.         0,   4,   8,  12,  12,   8,   4,   0,
  541.         4,   8,  12,  16,  16,  12,   8,   4,
  542.         8,  12,  16,  20,  20,  16,  12,   8,
  543.        12,  16,  20,  24,  24,  20,  16,  12,
  544.        12,  16,  20,  24,  24,  20,  16,  12,
  545.         8,  12,  16,  20,  20,  16,  12,   8,
  546.         4,   8,  12,  16,  16,  12,   8,   4,
  547.         0,   4,   8,  12,  12,   8,   4,   0
  548.     };
  549.     return winKingTable[k1] - loseKingTable[k2];
  550. }
  551.  
  552. template <bool whiteBishop>
  553. bool
  554. EndGameEval::isBishopPawnDraw(const Position& pos) {
  555.     const Piece::Type bishop = whiteBishop ? Piece::WBISHOP : Piece::BBISHOP;
  556.     const bool darkBishop  = (pos.pieceTypeBB(bishop) & BitBoard::maskDarkSq) != 0;
  557.     const bool lightBishop = (pos.pieceTypeBB(bishop) & BitBoard::maskLightSq) != 0;
  558.     if (darkBishop && lightBishop)
  559.         return false; // No draw against proper bishop pair
  560.  
  561.     const Piece::Type pawn = whiteBishop ? Piece::WPAWN : Piece::BPAWN;
  562.     if (pos.pieceTypeBB(pawn) == 0)
  563.         return true; // Only bishops on same color can not win
  564.  
  565.     // Check for rook pawn + wrong color bishop
  566.     if (whiteBishop) {
  567.         if (((pos.pieceTypeBB(pawn) & BitBoard::maskBToHFiles) == 0) &&
  568.             !lightBishop &&
  569.             ((pos.pieceTypeBB(Piece::BKING) & BitBoard::sqMask(A8,B8,A7,B7)) != 0)) {
  570.             return true;
  571.         } else
  572.         if (((pos.pieceTypeBB(pawn) & BitBoard::maskAToGFiles) == 0) &&
  573.             !darkBishop &&
  574.             ((pos.pieceTypeBB(Piece::BKING) & BitBoard::sqMask(G8,H8,G7,H7)) != 0)) {
  575.             return true;
  576.         }
  577.     } else {
  578.         if (((pos.pieceTypeBB(pawn) & BitBoard::maskBToHFiles) == 0) &&
  579.             !darkBishop &&
  580.             ((pos.pieceTypeBB(Piece::WKING) & BitBoard::sqMask(A1,B1,A2,B2)) != 0)) {
  581.             return true;
  582.         } else
  583.         if (((pos.pieceTypeBB(pawn) & BitBoard::maskAToGFiles) == 0) &&
  584.             !lightBishop &&
  585.             ((pos.pieceTypeBB(Piece::WKING) & BitBoard::sqMask(G1,H1,G2,H2)) != 0)) {
  586.             return true;
  587.         }
  588.     }
  589.  
  590.     // Check for fortress containing WPb6, BPb7, white bishop on dark square
  591.     const Piece::Type king = whiteBishop ? Piece::WKING : Piece::BKING;
  592.     const Piece::Type oPawn = whiteBishop ? Piece::BPAWN : Piece::WPAWN;
  593.     const Piece::Type oKnight = whiteBishop ? Piece::BKNIGHT : Piece::WKNIGHT;
  594.     const int b7 = whiteBishop ? (darkBishop ? B7 : G7) : (lightBishop ? B2 : G2);
  595.     const int b6 = whiteBishop ? (darkBishop ? B6 : G6) : (lightBishop ? B3 : G3);
  596.     const int c7 = whiteBishop ? (darkBishop ? C7 : F7) : (lightBishop ? C2 : F2);
  597.     const int a8 = whiteBishop ? (darkBishop ? A8 : H8) : (lightBishop ? A1 : H1);
  598.     const int b8 = whiteBishop ? (darkBishop ? B8 : G8) : (lightBishop ? B1 : G1);
  599.     const int c8 = whiteBishop ? (darkBishop ? C8 : F8) : (lightBishop ? C1 : F1);
  600.     const int d8 = whiteBishop ? (darkBishop ? D8 : E8) : (lightBishop ? D1 : E1);
  601.     const int d7 = whiteBishop ? (darkBishop ? D7 : E7) : (lightBishop ? D2 : E2);
  602.     const U64 bFile = (whiteBishop == darkBishop) ? 0x0202020202020202ULL : 0x4040404040404040ULL;
  603.     const U64 acFile = (whiteBishop == darkBishop) ? 0x0505050505050505ULL : 0xA0A0A0A0A0A0A0A0ULL;
  604.     const U64 corner = whiteBishop ? (darkBishop ? BitBoard::sqMask(A8,B8,A7) : BitBoard::sqMask(G8,H8,H7))
  605.                                    : (lightBishop ? BitBoard::sqMask(A1,B1,A2) : BitBoard::sqMask(G1,H1,H2));
  606.  
  607.     if ((pos.getPiece(b7) == oPawn) && (pos.getPiece(b6) == pawn) &&
  608.         (pos.getPiece(a8) != oKnight) && ((pos.pieceTypeBB(king) & corner) == 0) &&
  609.         (BitBoard::bitCount(pos.pieceTypeBB(oPawn) & acFile) <= 1)) {
  610.         if (pos.getPiece(c7) == pawn) {
  611.             if (BitBoard::bitCount(pos.pieceTypeBB(pawn) & ~bFile) == 1) {
  612.                 int oKingSq = pos.getKingSq(!whiteBishop);
  613.                 if ((oKingSq == c8) || (oKingSq == d7))
  614.                     return true;
  615.             }
  616.         } else {
  617.             int oKingSq = pos.getKingSq(!whiteBishop);
  618.             if ((pos.pieceTypeBB(pawn) & ~bFile) == 0) {
  619.                 if ((oKingSq == a8) || (oKingSq == b8) || (oKingSq == c8) ||
  620.                     (oKingSq == d8) || (oKingSq == d7))
  621.                     return true;
  622.             } else if (pos.isWhiteMove() != whiteBishop) { // Test if stale-mate
  623.                 int oMtrl = whiteBishop ? pos.bMtrl() : pos.wMtrl();
  624.                 U64 bShift = whiteBishop ? (pos.pieceTypeBB(bishop) << 8) : (pos.pieceTypeBB(bishop) >> 8);
  625.                 U64 kShift = whiteBishop ? (pos.pieceTypeBB(king) << 8) : (pos.pieceTypeBB(king) >> 8);
  626.                 const U64 md6_h2 = whiteBishop ?
  627.                         (darkBishop  ? BitBoard::sqMask(D6,E5,F4,G3,H2) : BitBoard::sqMask(E6,D5,C4,B3,A2)) :
  628.                         (lightBishop ? BitBoard::sqMask(D3,E4,F5,G6,H7) : BitBoard::sqMask(E3,D4,C5,B6,A7));
  629.                 if ((oMtrl == pV) ||
  630.                     ((oMtrl == 2*pV) && ((bShift & pos.pieceTypeBB(oPawn)) ||
  631.                                          ((kShift & pos.pieceTypeBB(oPawn)) &&
  632.                                           ((pos.pieceTypeBB(oPawn) & md6_h2) == 0))))) {
  633.                     const U64 mc7c8 = whiteBishop ?
  634.                             (darkBishop  ? BitBoard::sqMask(C7,C8) : BitBoard::sqMask(F7,F8)) :
  635.                             (lightBishop ? BitBoard::sqMask(C2,C1) : BitBoard::sqMask(F2,F1));
  636.                     const U64 md6e6e7e8 = whiteBishop ?
  637.                             (darkBishop  ? BitBoard::sqMask(D6,E6,E7,E8) : BitBoard::sqMask(E6,D6,D7,D8)) :
  638.                             (lightBishop ? BitBoard::sqMask(D3,E3,E2,E1) : BitBoard::sqMask(E3,D3,D2,D1));
  639.                     const U64 me7e8 = whiteBishop ?
  640.                             (darkBishop  ? BitBoard::sqMask(E7,E8) : BitBoard::sqMask(D7,D8)) :
  641.                             (lightBishop ? BitBoard::sqMask(E2,E1) : BitBoard::sqMask(D2,D1));
  642.                     if (oKingSq == a8) {
  643.                         if ((pos.pieceTypeBB(king) & mc7c8) ||
  644.                                 (pos.pieceTypeBB(bishop) & (md6_h2 | (1ULL << c7))))
  645.                             return true;
  646.                     } else if (oKingSq == c8) {
  647.                         if (pos.getPiece(c7) == bishop) {
  648.                             if (pos.pieceTypeBB(king) & md6e6e7e8)
  649.                                 return true;
  650.                         } else {
  651.                             if ((pos.pieceTypeBB(bishop) & md6_h2) && (pos.pieceTypeBB(king) & me7e8))
  652.                                 return true;
  653.                         }
  654.                     }
  655.                 }
  656.             }
  657.         }
  658.     }
  659.  
  660.     // Check for fortress when all pawns are on the B file and there is no bishop
  661.     if (whiteBishop) {
  662.         if (pos.pieceTypeBB(Piece::WBISHOP) == 0) {
  663.             if ((pos.pieceTypeBB(Piece::WPAWN,Piece::BPAWN) & ~BitBoard::maskFileB) == 0) {
  664.                 if ((pos.getPiece(B7) == Piece::BPAWN) &&
  665.                     (pos.pieceTypeBB(Piece::BKING) & BitBoard::sqMask(A7,A8,B8)))
  666.                     return true;
  667.             }
  668.             if ((pos.pieceTypeBB(Piece::WPAWN,Piece::BPAWN) & ~BitBoard::maskFileG) == 0) {
  669.                 if ((pos.getPiece(G7) == Piece::BPAWN) &&
  670.                     (pos.pieceTypeBB(Piece::BKING) & BitBoard::sqMask(H7,H8,G8)))
  671.                     return true;
  672.             }
  673.         }
  674.     } else {
  675.         if (pos.pieceTypeBB(Piece::BBISHOP) == 0) {
  676.             if ((pos.pieceTypeBB(Piece::WPAWN,Piece::BPAWN) & ~BitBoard::maskFileB) == 0) {
  677.                 if ((pos.getPiece(B2) == Piece::WPAWN) &&
  678.                     (pos.pieceTypeBB(Piece::WKING) & BitBoard::sqMask(A2,A1,B1)))
  679.                     return true;
  680.             }
  681.             if ((pos.pieceTypeBB(Piece::WPAWN,Piece::BPAWN) & ~BitBoard::maskFileG) == 0) {
  682.                 if ((pos.getPiece(G2) == Piece::WPAWN) &&
  683.                     (pos.pieceTypeBB(Piece::WKING) & BitBoard::sqMask(H2,H1,G1)))
  684.                     return true;
  685.             }
  686.         }
  687.     }
  688.  
  689.     return false;
  690. }
  691.  
  692. int
  693. EndGameEval::kqkpEval(int wKing, int wQueen, int bKing, int bPawn, bool whiteMove, int score) {
  694.     bool canWin = false;
  695.     if (((1ULL << bKing) & 0xFFFF) == 0) {
  696.         canWin = true; // King doesn't support pawn
  697.     } else if (std::abs(Position::getX(bPawn) - Position::getX(bKing)) > 2) {
  698.         canWin = true; // King doesn't support pawn
  699.     } else {
  700.         switch (bPawn) {
  701.         case A2:
  702.             canWin = ((1ULL << wKing) & 0x0F1F1F1F1FULL) != 0;
  703.             if (canWin && (bKing == A1) && (Position::getX(wQueen) == 1) && !whiteMove)
  704.                 canWin = false; // Stale-mate
  705.             break;
  706.         case C2:
  707.             canWin = ((1ULL << wKing) & 0x071F1F1FULL) != 0;
  708.             break;
  709.         case F2:
  710.             canWin = ((1ULL << wKing) & 0xE0F8F8F8ULL) != 0;
  711.             break;
  712.         case H2:
  713.             canWin = ((1ULL << wKing) & 0xF0F8F8F8F8ULL) != 0;
  714.             if (canWin && (bKing == H1) && (Position::getX(wQueen) == 6) && !whiteMove)
  715.                 canWin = false; // Stale-mate
  716.             break;
  717.         default:
  718.             canWin = true;
  719.             break;
  720.         }
  721.     }
  722.  
  723.     const int dist = BitBoard::getKingDistance(wKing, bPawn);
  724.     score = score - 20 * (dist - 4);
  725.     if (!canWin)
  726.         score /= 50;
  727.     return score;
  728. }
  729.  
  730. int
  731. EndGameEval::kqkrpEval(int wKing, int wQueen, int bKing, int bRook, int bPawn, bool whiteMove, int score) {
  732.     if (!(BitBoard::bPawnAttacks[bPawn] & (1ULL << bRook)))
  733.         return score; // Rook not protected by pawn, no fortress
  734.     if ((1ULL << bPawn) & (BitBoard::maskFileE | BitBoard::maskFileF |
  735.                            BitBoard::maskFileG | BitBoard::maskFileH)) { // Mirror X
  736.         wKing ^= 7;
  737.         wQueen ^= 7;
  738.         bKing ^= 7;
  739.         bRook ^= 7;
  740.         bPawn ^= 7;
  741.     }
  742.     bool drawish = false;
  743.     switch (bPawn) {
  744.     case A6:
  745.         drawish = ((1ULL << bKing) & BitBoard::sqMask(A8,B8,A7,B7)) &&
  746.                   (Position::getX(wKing) >= 2) &&
  747.                   (Position::getY(wKing) <= 3);
  748.         break;
  749.     case A2:
  750.         drawish = (((1ULL << bKing) & BitBoard::sqMask(A4,B4,A3,B3)) != 0); // Pierre-Marie Baty -- boolean conversion fix
  751.         break;
  752.     case B7:
  753.         drawish = ((1ULL << bKing) & BitBoard::sqMask(A8,B8,C8,A7,C7)) &&
  754.                   (Position::getY(wKing) <= 4);
  755.         break;
  756.     case B6:
  757.         if (bRook == C5) {
  758.             drawish = ((1ULL << bKing) & BitBoard::sqMask(A7,B7)) ||
  759.                       (((1ULL << bKing) & BitBoard::sqMask(A8,B8)) &&
  760.                        ((Position::getX(wKing) >= 3) || (Position::getY(wKing) <= 3)) &&
  761.                        (((1ULL << wQueen) & BitBoard::maskRow7) ||
  762.                         (!whiteMove && (wQueen != A6)) ||
  763.                         (whiteMove && !((1ULL << wQueen) & BitBoard::sqMask(A6,A5,A4,A3,A2,A1,B5,B4,B3,B2,B1,C4,D3,E2,F1)))));
  764.         }
  765.         break;
  766.     case B5:
  767.         drawish = ((1ULL << bKing) & BitBoard::sqMask(A6,B6,C6,A5)) &&
  768.                   (Position::getY(wKing) <= 2);
  769.         break;
  770.     case B4:
  771.         drawish = ((1ULL << bKing) & BitBoard::sqMask(A6,B6,C6,A5,B5,C5)) &&
  772.                   ((Position::getY(wKing) <= 2) || (Position::getX(wKing) >= 4));
  773.         break;
  774.     case B3:
  775.         drawish = (((1ULL << bKing) & BitBoard::sqMask(A4,B4,C4,A3)) &&
  776.                    ((1ULL << wKing) & BitBoard::maskRow1Row8)) ||
  777.                   (((1ULL << bKing) & BitBoard::sqMask(A5,B5)) &&
  778.                    ((1ULL << wQueen) & BitBoard::maskRow4) &&
  779.                    ((1ULL << wKing) & BitBoard::maskRow1));
  780.         break;
  781.     case B2:
  782.         drawish = ((1ULL << bKing) & BitBoard::sqMask(A4,B4,C4,A3,B3,C3,A2,C2)) &&
  783.                   ((1ULL << wKing) & BitBoard::sqMask(A4,B4,C4,A3,B3,C3,A2,C2)) == 0;
  784.         break;
  785.     case C7:
  786.         drawish = ((1ULL << bKing) & BitBoard::sqMask(B8,C8,D8,B7,D7)) &&
  787.                   (Position::getY(wKing) <= 4);
  788.         break;
  789.     case C3:
  790.         drawish = (((1ULL << bKing) & BitBoard::sqMask(B4,C4,D4)) &&
  791.                    ((1ULL << wKing) & BitBoard::maskRow1Row8)) ||
  792.                   (((1ULL << bKing) & BitBoard::sqMask(B5,C5)) &&
  793.                    (((1ULL << wQueen) & BitBoard::maskRow4) || !whiteMove) &&
  794.                    ((1ULL << wKing) & BitBoard::maskRow1)) ||
  795.                   ((((bKing == B3) && (wQueen != B5)) || ((bKing == D3) && (wQueen != D5))) &&
  796.                    ((1ULL << wKing) & BitBoard::maskRow1));
  797.  
  798.         break;
  799.     case C2:
  800.         drawish = ((1ULL << bKing) & BitBoard::sqMask(B3,C3,D3,B2,D2)) &&
  801.                   ((Position::getX(wKing) == 0) || (Position::getX(wKing) >= 4));
  802.         break;
  803.     case D7:
  804.         drawish = ((1ULL << bKing) & BitBoard::sqMask(C8,D8,E8,C7,E7)) &&
  805.                   (Position::getY(wKing) <= 4);
  806.         break;
  807.     case D3:
  808.         drawish = (((1ULL << bKing) & BitBoard::sqMask(C4,D4,E4)) &&
  809.                    ((1ULL << wKing) & BitBoard::maskRow1Row8)) ||
  810.                   (((1ULL << bKing) & BitBoard::sqMask(C5,D5,E5)) &&
  811.                    (((1ULL << wQueen) & BitBoard::maskRow4) || !whiteMove) &&
  812.                    ((1ULL << wKing) & BitBoard::maskRow1)) ||
  813.                   ((((bKing == C3) && (wQueen != C5)) || ((bKing == E3) && (wQueen != E5))) &&
  814.                    ((1ULL << wKing) & BitBoard::maskRow1));
  815.         break;
  816.     case D2:
  817.         drawish = ((1ULL << bKing) & BitBoard::sqMask(C4,D4,E4,C3,D3,E3,C2,E2)) &&
  818.                   ((1ULL << wKing) & BitBoard::sqMask(C4,D4,E4,C3,D3,E3,C2,E2)) == 0;
  819.         break;
  820.     default:
  821.         drawish = false;
  822.         break;
  823.     }
  824.     return drawish ? score / 16 : score;
  825. }
  826.  
  827. int
  828. EndGameEval::kpkEval(int wKing, int bKing, int wPawn, bool whiteMove) {
  829.     if (Position::getX(wKing) >= 4) { // Mirror X
  830.         wKing ^= 7;
  831.         bKing ^= 7;
  832.         wPawn ^= 7;
  833.     }
  834.     int index = whiteMove ? 0 : 1;
  835.     index = index * 32 + Position::getY(wKing)*4+Position::getX(wKing);
  836.     index = index * 64 + bKing;
  837.     index = index * 48 + wPawn - 8;
  838.  
  839.     int bytePos = index / 8;
  840.     int bitPos = index % 8;
  841.     bool draw = (((int)kpkTable[bytePos]) & (1 << bitPos)) == 0;
  842.     if (draw)
  843.         return 0;
  844.     return qV - pV / 4 * (7-Position::getY(wPawn));
  845. }
  846.  
  847. bool
  848. EndGameEval::kpkpEval(int wKing, int bKing, int wPawn, int bPawn, int& score) {
  849.     const U64 wKingMask = 1ULL << wKing;
  850.     const U64 bKingMask = 1ULL << bKing;
  851.     if (wPawn == B6 && bPawn == B7) {
  852.         if ((bKingMask & BitBoard::sqMask(A8,B8,C8,D8,D7)) &&
  853.             ((wKingMask & BitBoard::sqMask(A8,B8,A7)) == 0)) {
  854.             score = 0;
  855.             return true;
  856.         }
  857.     } else if (wPawn == G6 && bPawn == G7) {
  858.         if ((bKingMask & BitBoard::sqMask(E8,F8,G8,H8,E7)) &&
  859.             ((wKingMask & BitBoard::sqMask(G8,H8,H7)) == 0)) {
  860.             score = 0;
  861.             return true;
  862.         }
  863.     } else if (wPawn == B2 && bPawn == B3) {
  864.         if ((wKingMask & BitBoard::sqMask(A1,B1,C1,D1,D2)) &&
  865.             ((bKingMask & BitBoard::sqMask(A1,B1,A2)) == 0)) {
  866.             score = 0;
  867.             return true;
  868.         }
  869.     } else if (wPawn == G2 && bPawn == G3) {
  870.         if ((wKingMask & BitBoard::sqMask(E1,F1,G1,H1,E2)) &&
  871.             ((bKingMask & BitBoard::sqMask(G1,H1,H2)) == 0)) {
  872.             score = 0;
  873.             return true;
  874.         }
  875.     }
  876.     return false;
  877. }
  878.  
  879. int
  880. EndGameEval::krkpEval(int wKing, int bKing, int bPawn, bool whiteMove, int score) {
  881.     if (Position::getX(bKing) >= 4) { // Mirror X
  882.         wKing ^= 7;
  883.         bKing ^= 7;
  884.         bPawn ^= 7;
  885.     }
  886.     int index = whiteMove ? 0 : 1;
  887.     index = index * 32 + Position::getY(bKing)*4+Position::getX(bKing);
  888.     index = index * 48 + bPawn - 8;
  889.     index = index * 8 + Position::getY(wKing);
  890.     U8 mask = krkpTable[index];
  891.     bool canWin = (mask & (1 << Position::getX(wKing))) != 0;
  892.  
  893.     score = score + Position::getY(bPawn) * pV / 4;
  894.     if (!canWin)
  895.         score /= 50;
  896.     else
  897.         score += krkpBonus;
  898.     return score;
  899. }
  900.  
  901. int
  902. EndGameEval::krpkrEval(int wKing, int bKing, int wPawn, int wRook, int bRook, bool whiteMove) {
  903.     if (Position::getX(wPawn) >= 4) { // Mirror X
  904.         wKing ^= 7;
  905.         bKing ^= 7;
  906.         wPawn ^= 7;
  907.         wRook ^= 7;
  908.         bRook ^= 7;
  909.     }
  910.     int index = whiteMove ? 0 : 1;
  911.     index = index * 24 + (Position::getY(wPawn)-1)*4+Position::getX(wPawn);
  912.     index = index * 64 + wKing;
  913.     const U64 kMask = krpkrTable[index];
  914.     const bool canWin = (kMask & (1ULL << bKing)) != 0;
  915.     U64 kingNeighbors = BitBoard::kingAttacks[bKing];
  916.     const U64 occupied = (1ULL<<wKing) | (1ULL<<bKing) | (1ULL<<wPawn) | (1ULL<<bRook);
  917.     const U64 rAtk = BitBoard::rookAttacks(wRook, occupied);
  918.     kingNeighbors &= ~(BitBoard::kingAttacks[wKing] | BitBoard::wPawnAttacks[wPawn] | rAtk);
  919.     bool close;
  920.     if (canWin) {
  921.         close = (kMask & kingNeighbors) != kingNeighbors;
  922.     } else {
  923.         close = (kMask & kingNeighbors) != 0;
  924.     }
  925.     int score = pV + Position::getY(wPawn) * pV / 4;
  926.     if (canWin) {
  927.         if (!close)
  928.             score += pV;
  929.     } else {
  930.         if (close)
  931.             score /= 2;
  932.         else
  933.             score /= 4;
  934.     }
  935.     return score;
  936. }
  937.  
  938. int
  939. EndGameEval::krpkrpEval(int wKing, int bKing, int wPawn, int wRook, int bRook, int bPawn, bool whiteMove, int score) {
  940.     int hiScore = krpkrEval(wKing, bKing, wPawn, wRook, bRook, whiteMove);
  941.     if (score > hiScore * 14 / 16)
  942.         return hiScore * 14 / 16;
  943.     int loScore = -krpkrEval(63-bKing, 63-wKing, 63-bPawn, 63-bRook, 63-wRook, !whiteMove);
  944.     if (score < loScore * 14 / 16)
  945.         return loScore * 14 / 16;
  946.     return score;
  947. }
  948.  
  949. int
  950. EndGameEval::kbnkEval(int wKing, int bKing, bool darkBishop) {
  951.     int score = 600;
  952.     if (darkBishop) { // Mirror X
  953.         wKing ^= 7;
  954.         bKing ^= 7;
  955.     }
  956.     static const int bkTable[64] = { 17, 15, 12,  9,  7,  4,  2,  0,
  957.                                      15, 20, 17, 15, 12,  9,  4,  2,
  958.                                      12, 17, 22, 20, 17, 15,  9,  4,
  959.                                       9, 15, 20, 25, 22, 17, 12,  7,
  960.                                       7, 12, 17, 22, 25, 20, 15,  9,
  961.                                       4,  9, 15, 17, 20, 22, 17, 12,
  962.                                       2,  4,  9, 12, 15, 17, 20, 15,
  963.                                       0,  2,  4,  7,  9, 12, 15, 17 };
  964.  
  965.     score += winKingTable[wKing] - bkTable[bKing];
  966.     score -= std::min(0, BitBoard::getTaxiDistance(wKing, bKing) - 3);
  967.     return score;
  968. }
  969.  
  970. int
  971. EndGameEval::kbpkbEval(int wKing, int wBish, int wPawn, int bKing, int bBish, int score) {
  972.     U64 wPawnMask = 1ULL << wPawn;
  973.     U64 pawnPath = BitBoard::northFill(wPawnMask);
  974.     U64 bKingMask = 1ULL << bKing;
  975.     U64 wBishMask = 1ULL << wBish;
  976.     U64 wBishControl = (wBishMask & BitBoard::maskDarkSq) ? BitBoard::maskDarkSq : BitBoard::maskLightSq;
  977.     if ((bKingMask & pawnPath) && ((bKingMask & wBishControl) == 0))
  978.         return 0;
  979.  
  980.     U64 bBishMask = 1ULL << bBish;
  981.     if (((wBishMask & BitBoard::maskDarkSq) == 0) != ((bBishMask & BitBoard::maskDarkSq) == 0)) { // Different color bishops
  982.         if (((bBishMask | BitBoard::bishopAttacks(bBish, bKingMask)) & pawnPath & ~wPawnMask) != 0)
  983.             if (!(wPawn == A6 && bBish == B8) && !(wPawn == H6 && bBish == G8))
  984.                 return 0;
  985.     }
  986.  
  987.     if (bKingMask & BitBoard::wPawnBlockerMask[wPawn])
  988.         return score / 4;
  989.     return score;
  990. }
  991.  
  992. int
  993. EndGameEval::kbpknEval(int wKing, int wBish, int wPawn, int bKing, int bKnight, int score) {
  994.     U64 wPawnMask = 1ULL << wPawn;
  995.     U64 pawnPath = BitBoard::northFill(wPawnMask);
  996.     U64 bKingMask = 1ULL << bKing;
  997.     U64 wBishMask = 1ULL << wBish;
  998.     U64 wBishControl = (wBishMask & BitBoard::maskDarkSq) ? BitBoard::maskDarkSq : BitBoard::maskLightSq;
  999.  
  1000.     U64 edges = 0xff818181818181ffULL;
  1001.     U64 bKnightMask = 1ULL << bKnight;
  1002.     if ((bKnightMask & edges & ~wBishControl) != 0) // Knight on edge square where it can be trapped
  1003.         return score;
  1004.  
  1005.     if ((bKingMask & pawnPath) && ((bKingMask & wBishControl) == 0))
  1006.         return 0;
  1007.  
  1008.     if (bKingMask & BitBoard::wPawnBlockerMask[wPawn])
  1009.         return score / 4;
  1010.     return score;
  1011. }
  1012.  
  1013. int
  1014. EndGameEval::knpkbEval(int wKing, int wKnight, int wPawn, int bKing, int bBish, int score, bool wtm) {
  1015.     U64 wPawnMask = 1ULL << wPawn;
  1016.     U64 bBishMask = 1ULL << bBish;
  1017.     U64 bBishControl = (bBishMask & BitBoard::maskDarkSq) ? BitBoard::maskDarkSq : BitBoard::maskLightSq;
  1018.  
  1019.     U64 p = wPawnMask;
  1020.     if (bBishControl & wPawnMask) {
  1021.         U64 bKingMask = 1ULL << bKing;
  1022.         U64 wKnightMask = 1ULL << wKnight;
  1023.         if (!wtm && (BitBoard::bishopAttacks(bBish, bKingMask | wKnightMask) & wPawnMask))
  1024.             return 0;
  1025.         p <<= 8;
  1026.     }
  1027.     U64 pawnDrawishMask = 0x183c7e7e7e7eULL;
  1028.     if (p & pawnDrawishMask)
  1029.         return score / 32;
  1030.  
  1031.     return score;
  1032. }
  1033.  
  1034. int
  1035. EndGameEval::knpkEval(int wKing, int wKnight, int wPawn, int bKing, int score, bool wtm) {
  1036.     if (Position::getX(wPawn) >= 4) { // Mirror X
  1037.         wKing ^= 7;
  1038.         wKnight ^= 7;
  1039.         wPawn ^= 7;
  1040.         bKing ^= 7;
  1041.     }
  1042.     if (wPawn == A7) {
  1043.         if (bKing == A8 || bKing == B7) // Fortress
  1044.             return 0;
  1045.         if (wKing == A8 && (bKing == C7 || bKing == C8)) {
  1046.             bool knightDark = Position::darkSquare(Position::getX(wKnight), Position::getY(wKnight));
  1047.             bool kingDark = Position::darkSquare(Position::getX(bKing), Position::getY(bKing));
  1048.             if (wtm == (knightDark == kingDark)) // King trapped
  1049.                 return 0;
  1050.         }
  1051.     }
  1052.     return score;
  1053. }
  1054.