/*
Protector -- a UCI chess engine
Copyright (C) 2009-2010 Raimund Heid (Raimund_Heid@yahoo.com)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include <stdlib.h>
#include <math.h>
#include "position.h"
#include "fen.h"
#include "io.h"
#ifdef INCLUDE_TABLEBASE_ACCESS
#include "tablebase.h"
#endif
#define dumpPos dumpPosition(position);
#ifdef TEST_SETUP
/* #define PINNED_KNIGHT_BONUS */
#define MALUS_ROOK_BLOCKING_PASSER /* */
#define BONUS_SPACE_ATTACKS /* */
/* #define MALUS_QUEEN_DEFENDER_DISTANCE */
#define BONUS_OUTPOST_ATTACKS /* */
#define BONUS_WINNING_PASSER /* */
#define BONUS_PIECE_ATTACKS /* */
#define BONUS_SLIDER_ATTACKS /* */
#define MALUS_PAWN_MOBILITY /* */
/* #define BONUS_PIECES_PROTECT_KING */
/* #define MALUS_KING_TRAPPED */
/* #define BONUS_OUTSIDE_PASSER */
#define HOMELAND_SECURITY_BONUS /* */
/* #define GENERATE_TABLES */
/* #define BONUS_PINS */
/* #define BONUS_ROOK_6TH_RANK */
/* #define BONUS_ROOK_8TH_RANK */
#define INCLUDE_PASSERS_IN_FUTILITY_MARGIN /* */
/* #define MALUS_BISHOP_BORDER */
/* #define BONUS_HALF_OPEN_FILE_ROOK */
/* #define EXTRA_BONUS_KING_FILE_ATTACKS */
#define REDUCED_PAWN_EVAL /* */
/* #define HIGH_ATTACK_BONUS */
#else
/* #define PINNED_KNIGHT_BONUS */
#define MALUS_ROOK_BLOCKING_PASSER /* */
#define BONUS_SPACE_ATTACKS /* */
/* #define MALUS_QUEEN_DEFENDER_DISTANCE */
#define BONUS_OUTPOST_ATTACKS /* */
#define BONUS_WINNING_PASSER /* */
#define BONUS_PIECE_ATTACKS /* */
#define BONUS_SLIDER_ATTACKS /* */
#define MALUS_PAWN_MOBILITY /* */
/* #define BONUS_PIECES_PROTECT_KING */
#define MALUS_KING_TRAPPED /* */
/* #define BONUS_OUTSIDE_PASSER */
#define HOMELAND_SECURITY_BONUS /* */
/* #define GENERATE_TABLES */
/* #define BONUS_PINS */
/* #define BONUS_ROOK_6TH_RANK */
/* #define BONUS_ROOK_8TH_RANK */
#define INCLUDE_PASSERS_IN_FUTILITY_MARGIN /* */
/* #define MALUS_BISHOP_BORDER */
/* #define BONUS_HALF_OPEN_FILE_ROOK */
/* #define EXTRA_BONUS_KING_FILE_ATTACKS */
#define REDUCED_PAWN_EVAL /* */
/* #define HIGH_ATTACK_BONUS */
#endif
#include "evaluation.h"
#define MAX_MOVES_KNIGHT 8
#define MAX_MOVES_BISHOP 13
#define MAX_MOVES_ROOK 14
#define MAX_MOVES_QUEEN 27
const INT32 KnightMobilityBonus[MAX_MOVES_KNIGHT + 1] =
{ V(-14, -12), V(-9, -8), V(-4, -5), V(0, -1),
V(4, 2), V(9, 6), V(12, 8), V(14, 10), V(14, 10)
};
const INT32 BishopMobilityBonus[MAX_MOVES_BISHOP + 1] =
{ V(-9, -11), V(-4, -6), V(1, 0), V(6, 4), V(12, 10),
V(17, 15), V(22, 20), V(25, 23), V(27, 25), V(28, 26),
V(29, 27), V(30, 28), V(30, 28), V(31, 29)
};
const INT32 RookMobilityBonus[MAX_MOVES_ROOK + 1] =
{ V(-7, -14), V(-5, -7), V(-3, -1), V(0, 5), V(1, 11),
V(3, 17), V(5, 24), V(7, 30), V(8, 37), V(10, 41), V(10, 43),
V(10, 44), V(11, 45), V(11, 45), V(12, 46)
};
const INT32 QueenMobilityBonus[MAX_MOVES_QUEEN + 1] =
{ V(-3, -7), V(-3, -5), V(-2, -2), V(-1, 0), V(0, 1), V(0, 3), V(1, 5),
V(1, 7), V(3, 8), V(3, 10), V(4, 12), V(5, 13), V(6, 13), V(6, 13),
V(7, 13), V(7, 13), V(7, 13), V(7, 13), V(7, 13), V(7, 13), V(7, 13),
V(7, 13), V(7, 13), V(7, 13), V(7, 13), V(7, 13), V(7, 13), V(7, 13)
};
/* *INDENT-OFF* */
const INT32 PstPawn[64] = {
V( 0, 0), V( 0, 0), V( 0, 0), V( 0, 0), V( 0, 0), V( 0, 0), V( 0, 0), V( 0, 0), /* rank 1 */
V(-10, -3), V( -2, -3), V( 1, -3), V( 5, -3), V( 5, -3), V( 1, -3), V( -2, -3), V(-10, -3), /* rank 2 */
V(-10, -3), V( -2, -3), V( 3, -3), V( 14, -3), V( 14, -3), V( 3, -3), V( -2, -3), V(-10, -3), /* rank 3 */
V(-10, -3), V( -2, -3), V( 6, -3), V( 22, -3), V( 22, -3), V( 6, -3), V( -2, -3), V(-10, -3), /* rank 4 */
V(-10, -3), V( -2, -3), V( 6, -3), V( 14, -3), V( 14, -3), V( 6, -3), V( -2, -3), V(-10, -3), /* rank 5 */
V(-10, -3), V( -2, -3), V( 3, -3), V( 5, -3), V( 5, -3), V( 3, -3), V( -2, -3), V(-10, -3), /* rank 6 */
V(-10, -3), V( -2, -3), V( 1, -3), V( 5, -3), V( 5, -3), V( 1, -3), V( -2, -3), V(-10, -3), /* rank 7 */
V( 0, 0), V( 0, 0), V( 0, 0), V( 0, 0), V( 0, 0), V( 0, 0), V( 0, 0), V( 0, 0)}; /* rank 8 */
const INT32 PstKnight[64] = {
V(-52,-40), V(-41,-30), V(-31,-21), V(-26,-16), V(-26,-16), V(-31,-21), V(-41,-30), V(-52,-40), /* rank 1 */
V(-36,-30), V(-26,-21), V(-15,-11), V( -9, -6), V( -9, -6), V(-15,-11), V(-26,-21), V(-36,-30), /* rank 2 */
V(-20,-21), V( -9,-11), V( 0, -2), V( 5, 1), V( 5, 1), V( 0, -2), V( -9,-11), V(-20,-21), /* rank 3 */
V( -9,-16), V( 0, -6), V( 10, 1), V( 16, 7), V( 16, 7), V( 10, 1), V( 0, -6), V( -9,-16), /* rank 4 */
V( -4,-16), V( 5, -6), V( 16, 1), V( 21, 7), V( 21, 7), V( 16, 1), V( 5, -6), V( -4,-16), /* rank 5 */
V( -4,-21), V( 5,-11), V( 16, -2), V( 21, 1), V( 21, 1), V( 16, -2), V( 5,-11), V( -4,-21), /* rank 6 */
V(-20,-30), V( -9,-21), V( 0,-11), V( 5, -6), V( 5, -6), V( 0,-11), V( -9,-21), V(-20,-30), /* rank 7 */
V(-75,-40), V(-26,-30), V(-15,-21), V( -9,-16), V( -9,-16), V(-15,-21), V(-26,-30), V(-75,-40)}; /* rank 8 */
const INT32 PstBishop[64] = {
V(-15,-23), V(-15,-16), V(-13,-13), V(-11,-10), V(-11,-10), V(-13,-13), V(-15,-16), V(-15,-23), /* rank 1 */
V( -6,-16), V( 0,-10), V( -1, -7), V( 0, -4), V( 0, -4), V( -1, -7), V( 0,-10), V( -6,-16), /* rank 2 */
V( -5,-13), V( -1, -7), V( 3, -4), V( 1, -1), V( 1, -1), V( 3, -4), V( -1, -7), V( -5,-13), /* rank 3 */
V( -3,-10), V( 0, -4), V( 1, -1), V( 6, 1), V( 6, 1), V( 1, -1), V( 0, -4), V( -3,-10), /* rank 4 */
V( -3,-10), V( 0, -4), V( 1, -1), V( 6, 1), V( 6, 1), V( 1, -1), V( 0, -4), V( -3,-10), /* rank 5 */
V( -5,-13), V( -1, -7), V( 3, -4), V( 1, -1), V( 1, -1), V( 3, -4), V( -1, -7), V( -5,-13), /* rank 6 */
V( -6,-16), V( 0,-10), V( -1, -7), V( 0, -4), V( 0, -4), V( -1, -7), V( 0,-10), V( -6,-16), /* rank 7 */
V( -6,-23), V( -6,-16), V( -5,-13), V( -3,-10), V( -3,-10), V( -5,-13), V( -6,-16), V( -6,-23)}; /* rank 8 */
const INT32 PstRook[64] = {
V( -4, 1), V( -2, 1), V( 0, 1), V( 0, 1), V( 0, 1), V( 0, 1), V( -2, 1), V( -4, 1), /* rank 1 */
V( -4, 1), V( -2, 1), V( 0, 1), V( 0, 1), V( 0, 1), V( 0, 1), V( -2, 1), V( -4, 1), /* rank 2 */
V( -4, 1), V( -2, 1), V( 0, 1), V( 0, 1), V( 0, 1), V( 0, 1), V( -2, 1), V( -4, 1), /* rank 3 */
V( -4, 1), V( -2, 1), V( 0, 1), V( 0, 1), V( 0, 1), V( 0, 1), V( -2, 1), V( -4, 1), /* rank 4 */
V( -4, 1), V( -2, 1), V( 0, 1), V( 0, 1), V( 0, 1), V( 0, 1), V( -2, 1), V( -4, 1), /* rank 5 */
V( -4, 1), V( -2, 1), V( 0, 1), V( 0, 1), V( 0, 1), V( 0, 1), V( -2, 1), V( -4, 1), /* rank 6 */
V( -4, 1), V( -2, 1), V( 0, 1), V( 0, 1), V( 0, 1), V( 0, 1), V( -2, 1), V( -4, 1), /* rank 7 */
V( -4, 1), V( -2, 1), V( 0, 1), V( 0, 1), V( 0, 1), V( 0, 1), V( -2, 1), V( -4, 1)}; /* rank 8 */
const INT32 PstQueen[64] = {
V( 3,-31), V( 3,-21), V( 3,-16), V( 3,-11), V( 3,-11), V( 3,-16), V( 3,-21), V( 3,-31), /* rank 1 */
V( 3,-21), V( 3,-11), V( 3, -7), V( 3, -2), V( 3, -2), V( 3, -7), V( 3,-11), V( 3,-21), /* rank 2 */
V( 3,-16), V( 3, -7), V( 3, -2), V( 3, 2), V( 3, 2), V( 3, -2), V( 3, -7), V( 3,-16), /* rank 3 */
V( 3,-11), V( 3, -2), V( 3, 2), V( 3, 7), V( 3, 7), V( 3, 2), V( 3, -2), V( 3,-11), /* rank 4 */
V( 3,-11), V( 3, -2), V( 3, 2), V( 3, 7), V( 3, 7), V( 3, 2), V( 3, -2), V( 3,-11), /* rank 5 */
V( 3,-16), V( 3, -7), V( 3, -2), V( 3, 2), V( 3, 2), V( 3, -2), V( 3, -7), V( 3,-16), /* rank 6 */
V( 3,-21), V( 3,-11), V( 3, -7), V( 3, -2), V( 3, -2), V( 3, -7), V( 3,-11), V( 3,-21), /* rank 7 */
V( 3,-31), V( 3,-21), V( 3,-16), V( 3,-11), V( 3,-11), V( 3,-16), V( 3,-21), V( 3,-31)}; /* rank 8 */
const INT32 PstKing[64] = {
V(112, 7), V(121, 30), V(102, 41), V( 83, 52), V( 83, 52), V(102, 41), V(121, 30), V(112, 7), /* rank 1 */
V(102, 30), V(112, 52), V( 92, 64), V( 74, 75), V( 74, 75), V( 92, 64), V(112, 52), V(102, 30), /* rank 2 */
V( 83, 41), V( 92, 64), V( 74, 75), V( 55, 86), V( 55, 86), V( 74, 75), V( 92, 64), V( 83, 41), /* rank 3 */
V( 74, 52), V( 83, 75), V( 65, 86), V( 46, 98), V( 46, 98), V( 65, 86), V( 83, 75), V( 74, 52), /* rank 4 */
V( 65, 52), V( 74, 75), V( 55, 86), V( 36, 98), V( 36, 98), V( 55, 86), V( 74, 75), V( 65, 52), /* rank 5 */
V( 55, 41), V( 65, 64), V( 46, 75), V( 26, 86), V( 26, 86), V( 46, 75), V( 65, 64), V( 55, 41), /* rank 6 */
V( 46, 30), V( 55, 52), V( 36, 64), V( 17, 75), V( 17, 75), V( 36, 64), V( 55, 52), V( 46, 30), /* rank 7 */
V( 36, 7), V( 46, 30), V( 26, 41), V( 8, 52), V( 8, 52), V( 26, 41), V( 46, 30), V( 36, 7)}; /* rank 8 */
/* *INDENT-ON* */
/* -------------------------------------------------------------------------- */
static const int PAWN_MALUS_DOUBLED_OPENING = 8;
static const int PAWN_MALUS_DOUBLED_ENDGAME = 16;
static const int PAWN_MALUS_ISOLATED_OPENING = 6;
static const int PAWN_MALUS_ISOLATED_ON_OPEN_FILE = 16;
static const int PAWN_MALUS_ISOLATED_ENDGAME = 20;
static const int PAWN_MALUS_ISOLATED_FIXED_OPENING = 4;
static const int PAWN_MALUS_ISOLATED_FIXED_ENDGAME = 6;
static const int PAWN_MALUS_BACKWARD_OPENING = 4;
static const int PAWN_MALUS_BACKWARD_ON_OPEN_FILE = 12;
static const int PAWN_MALUS_BACKWARD_ENDGAME = 10;
static const int PAWN_MALUS_BACKWARD_FIXED_OPENING = 2;
static const int PAWN_MALUS_BACKWARD_FIXED_ENDGAME = 4;
static const int PAWN_CANDIDATE_OPENING_MIN = 5;
static const int PAWN_CANDIDATE_OPENING_MAX = 55;
static const int PAWN_CANDIDATE_ENDGAME_MIN = 10;
static const int PAWN_CANDIDATE_ENDGAME_MAX = 110;
static const int PASSED_PAWN_BONUS_OPENING_MIN = 10;
static const int PASSED_PAWN_BONUS_OPENING_MAX = 70;
static const int PASSED_PAWN_BONUS_ENDGAME_MIN = 20;
static const int PASSED_PAWN_BONUS_ENDGAME_MAX = 140;
static const int PASSED_PAWN_BONUS_UNSTOPPABLE = 800;
static const int PASSED_PAWN_BONUS_NOT_BLOCKED = 60;
static const int PASSED_PAWN_BONUS_ACCOMPANIED = 4;
static const int PASSED_PAWN_MALUS_LACK_OF_SUPPORT = 30;
static const int PASSED_PAWN_ATTACKERDIST_WEIGHT = 15;
static const int PASSED_PAWN_DEFENDERDIST_WEIGHT = 20;
static const int PASSED_PAWN_BONUS_OUTSIDE_OPENING = 8;
static const int PASSED_PAWN_BONUS_OUTSIDE_ENDGAME = 14;
static const int PASSED_PAWN_BONUS_PROTECTED_OPENING = 10;
static const int PASSED_PAWN_BONUS_PROTECTED_ENDGAME = 16;
static const int PASSED_PAWN_BONUS_CONNECTED_OPENING = 16;
static const int PASSED_PAWN_BONUS_CONNECTED_ENDGAME = 24;
static const int KNIGHT_BONUS_ATTACK = 2;
static const int KNIGHT_MALUS_VS_BOTH_WINGS = 10;
static const int KNIGHT_MALUS_VS_OUTSIDE_PASSED = 15;
static const int BISHOP_BONUS_ATTACK = 2;
static const int BISHOP_MALUS_BLOCKED = 50;
static const int BISHOP_MALUS_TRAPPED = 125;
static const int BISHOP_BONUS_PINNING_KNIGHT_OPENING = 15;
static const int BISHOP_BONUS_PINNING_KNIGHT_ENDGAME = 10;
static const int ROOK_BONUS_ON_SEMIOPEN_FILE = 10;
static const int ROOK_BONUS_ON_OPEN_FILE = 20;
static const int ROOK_MALUS_BLOCKED = 48;
static const int ROOK_MALUS_SQUEEZED = 12;
static const int ROOK_BONUS_KING_FILE = 20;
static const int ROOK_BONUS_LATERAL_KING_FILE = 10;
static const int ROOK_BONUS_ON_SEVENTH_RANK_OPENING = 20;
static const int ROOK_BONUS_ON_SEVENTH_RANK_ENDGAME = 40;
static const int ROOK_BONUS_ATTACK = 3;
static const int ROOK_MALUS_BLOCKING_PASSER = 90;
static const int QUEEN_BONUS_ON_SEVENTH_RANK_OPENING = 10;
static const int QUEEN_BONUS_ON_SEVENTH_RANK_ENDGAME = 20;
static const int QUEEN_BONUS_ATTACK = 5;
static const int KINGSAFETY_PAWN_MALUS_DEFENDER[3][8] = {
{30, 0, 5, 15, 20, 25, 25, 25},
{55, 0, 15, 40, 50, 55, 55, 55},
{30, 0, 10, 20, 25, 30, 30, 30}
};
static const int KINGSAFETY_PAWN_BONUS_DEFENDER_DIAG[4][8] = {
{10, 0, 2, 4, 6, 8, 10, 10},
{8, 0, 2, 4, 6, 7, 8, 8},
{6, 0, 2, 3, 4, 5, 6, 6},
{4, 0, 1, 2, 3, 4, 4, 4}
};
static const int KINGSAFETY_PAWN_BONUS_ATTACKER[3][8] = {
{5, 0, 35, 15, 5, 0, 0, 0},
{10, 0, 50, 20, 10, 0, 0, 0},
{10, 0, 50, 20, 10, 0, 0, 0}
};
#define KING_SAFETY_MALUS_DIM 100
int KING_SAFETY_MALUS[KING_SAFETY_MALUS_DIM];
static const INT32 KING_MALUS_TRAPPED = V(10, 15);
static const int SPACE_BONUS_WEIGHT[16] = {
0, 2, 6, 11, 17, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24
};
#define KPKP_TABLESIZE (2*32*49*49)
/* -------------------------------------------------------------------------- */
int centerDistance[_64_], centerTaxiDistance[_64_];
int attackPoints[16];
Bitboard weakOutpostSquareCandidates[2];
Bitboard butterflySquares[_64_];
Bitboard lateralSquares[_64_];
Bitboard companionFiles[_64_];
Bitboard passedPawnRectangle[2][_64_];
Bitboard passedPawnCorridor[2][_64_];
int passedPawnDefenderMalus[2][2][_64_][_64_];
Bitboard candidateDefenders[2][_64_]; /* excludes squares of rank */
Bitboard candidateSupporters[2][_64_]; /* includes squares of rank */
Bitboard pawnOpponents[2][_64_];
Bitboard rookTraps[2];
Bitboard rookBlockers[_64_];
Bitboard centralFiles;
Bitboard kingRealm[2][_64_][_64_];
Bitboard attackingRealm[2];
Bitboard homeland[2];
Bitboard troitzkyArea[2];
Bitboard krprkDrawFiles;
Bitboard A1C1, F1H1, A1B1, G1H1;
Bitboard filesBCFG;
KingAttacks kingAttacks[_64_];
int kingChaseMalus[3][_64_];
INT32 sliderAttackPoints[16][16];
INT32 piecePieceAttackBonus[16][16];
MaterialInfo materialInfo[MATERIALINFO_TABLE_SIZE];
/* *INDENT-OFF* */
static const int MALUS_PAWN_SQUARE_TYPE_HR[64] = {
0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 2, 2, 2, 2, 1, 1,
1, 2, 3, 3, 3, 3, 2, 1,
1, 2, 3, 5, 5, 3, 2, 1,
1, 2, 3, 5, 5, 3, 2, 1,
1, 2, 3, 3, 3, 3, 2, 1,
1, 1, 2, 2, 2, 2, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0
};
static const int MALUS_KING_SQUARE_HR[64] = {
15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15,
7, 10, 12, 12, 12, 12, 10, 7,
2, 2, 4, 8, 8, 4, 2, 2,
2, 0, 2, 5, 5, 2, 0, 2,
};
/* *INDENT-ON* */
static int MALUS_PAWN_SQUARE_TYPE[64];
static int MALUS_KING_SQUARE[64];
#ifdef GENERATE_TABLES
UINT64 kpkpTempTable[KPKP_TABLESIZE];
#endif
#ifndef NDEBUG
bool debugEval = FALSE;
#endif
#ifndef INLINE_IN_HEADERS
#include "evaluationInline.h"
#endif
static int getWhiteKingTableIndex(const Square whiteKingSquare)
{
const File fileCount = file(whiteKingSquare);
const Rank rankCount = rank(whiteKingSquare);
return 4 * rankCount + fileCount;
}
static INLINE unsigned int getKpkpIndexFromSquares(const Square wk,
const Square bk,
const Square wp,
const Square bp)
{
const unsigned int M1 = 2;
const unsigned int M2 = 32 * M1;
const unsigned int M3 = 64 * M2;
const unsigned int M4 = 49 * M3;
unsigned int index;
index = getWhiteKingTableIndex(wk) * M1 + (bk * M2) +
((wp - A2) * M3) + ((bp - A2) * M4);
assert((wp - A2) >= 0);
assert((bp - A2) >= 0);
assert((wp - A2) < 49);
assert((bp - A2) < 49);
assert(index < (KPKP_TABLESIZE << 6));
return index;
}
static INLINE unsigned int getKpkpIndex(const Position * position)
{
Square wk = position->king[WHITE];
Square bk = position->king[BLACK];
Square wp = A8, bp = A8;
if (position->piecesOfType[WHITE_PAWN] != EMPTY_BITBOARD)
{
Bitboard whitePawns = position->piecesOfType[WHITE_PAWN];
wp = getLastSquare(&whitePawns);
}
if (position->piecesOfType[BLACK_PAWN] != EMPTY_BITBOARD)
{
Bitboard blackPawns = position->piecesOfType[BLACK_PAWN];
bp = getLastSquare(&blackPawns);
}
if (position->activeColor == BLACK)
{
const Square tmpWk = wk;
const Square tmpWp = wp;
#ifndef NDEBUG
if (debugEval)
{
logDebug("before vertical flip\n");
logDebug("wk=");
dumpSquare(wk);
logDebug("bk=");
dumpSquare(bk);
logDebug("wp=");
dumpSquare(wp);
logDebug("bp=");
dumpSquare(bp);
logPosition(position);
}
#endif
wk = getFlippedSquare(bk);
bk = getFlippedSquare(tmpWk);
wp = (bp == A8 ? bp : getFlippedSquare(bp));
bp = (tmpWp == A8 ? tmpWp : getFlippedSquare(tmpWp));
#ifndef NDEBUG
if (debugEval)
{
logDebug("after vertical flip\n");
logDebug("wk=");
dumpSquare(wk);
logDebug("bk=");
dumpSquare(bk);
logDebug("wp=");
dumpSquare(wp);
logDebug("bp=");
dumpSquare(bp);
logPosition(position);
}
#endif
}
if (file(wk) >= FILE_E)
{
#ifndef NDEBUG
if (debugEval)
{
logDebug("before horizontal flip\n");
logDebug("wk=");
dumpSquare(wk);
logDebug("bk=");
dumpSquare(bk);
logDebug("wp=");
dumpSquare(wp);
logDebug("bp=");
dumpSquare(bp);
logPosition(position);
}
#endif
wk = getHflippedSquare(wk);
bk = getHflippedSquare(bk);
wp = (wp == A8 ? wp : getHflippedSquare(wp));
bp = (bp == A8 ? bp : getHflippedSquare(bp));
#ifndef NDEBUG
if (debugEval)
{
logDebug("after horizontal flip\n");
logDebug("wk=");
dumpSquare(wk);
logDebug("bk=");
dumpSquare(bk);
logDebug("wp=");
dumpSquare(wp);
logDebug("bp=");
dumpSquare(bp);
logPosition(position);
}
#endif
}
return getKpkpIndexFromSquares(wk, bk, wp, bp);
}
#ifndef NDEBUG
static void dumpTableAccess(const Position * position, const int egtbValue,
const int internalValue)
{
int index;
debugEval = TRUE;
index = getKpkpIndex(position);
logDebug("\n### egtbValue=%d internalValue=%d\n\n", egtbValue,
internalValue);
dumpPosition(position);
}
#endif
/**
* Return a tablebase value for a kpkp position.
*
* return 0 for draw, 1 for white winning, 2 for black winning
*/
static INLINE int getKpkpValue(const Position * position)
{
const int WIN_VALUE = 800;
const unsigned int index = getKpkpIndex(position);
const unsigned int bucketIndex = index >> 6;
const unsigned int shiftIndex = index - 64 * bucketIndex;
const int value = (int) (3 & (kpkpTable[bucketIndex] >> shiftIndex));
assert((shiftIndex % 2) == 0);
assert(value >= 0 && value <= 2);
#ifdef INCLUDE_TABLEBASE_ACCESS
#ifndef NDEBUG
if (tbAvailable != FALSE)
{
const int tbValue = probeTablebase(position);
if (tbValue == 0)
{
if (value != 0)
{
dumpTableAccess(position, tbValue, value);
}
/* assert(value == 0); */
}
if (tbValue > 0 && tbValue != TABLEBASE_ERROR)
{
if (value != 1)
{
dumpTableAccess(position, tbValue, value);
}
/* assert(value == 1); */
}
if (tbValue < 0)
{
if (value != 2)
{
dumpTableAccess(position, tbValue, value);
}
/* assert(value == 2); */
}
}
#endif
#endif
if (value != 0)
{
#ifndef NDEBUG
if (debugEval)
{
logDebug("tablevalue=%d\n", value);
dumpPosition(position);
}
#endif
return (value == 1 ? WIN_VALUE : -WIN_VALUE);
}
else
{
return value;
}
}
#ifdef GENERATE_TABLES
void cleanPosition(Position * position)
{
Square square;
ITERATE(square)
{
position->piece[square] = NO_PIECE;
}
position->activeColor = WHITE;
position->enPassantSquare = NO_SQUARE;
}
INLINE static UINT64 getTableValue(int dtmValue)
{
if (dtmValue == 0)
{
return 0;
}
return (dtmValue > 0 ? 1 : 2);
}
void updateKpkpValue(const Position * position)
{
const UINT64 tableValue = getTableValue(probeTablebase(position));
const unsigned int index = getKpkpIndex(position);
const unsigned int bucketIndex = index >> 6;
const unsigned int shiftIndex = index - 64 * bucketIndex;
const UINT64 mask = ~(((UINT64) 3) << shiftIndex);
const UINT64 oldBucket = kpkpTempTable[bucketIndex];
const UINT64 newBucket = (oldBucket & mask) | (tableValue << shiftIndex);
assert((shiftIndex % 2) == 0);
assert(tableValue >= 0 && tableValue <= 2);
assert(bucketIndex < KPKP_TABLESIZE);
assert(shiftIndex <= 62);
kpkpTempTable[bucketIndex] = newBucket;
}
void generateKpkpTable()
{
int i;
Square wk, bk, wp, bp;
Position position;
long count = 0;
for (i = 0; i < KPKP_TABLESIZE; i++)
{
kpkpTempTable[i] = ULONG_ZERO;
}
for (wk = A1; wk <= H8; wk++)
{
if (file(wk) >= FILE_E)
{
continue; /* assume wk 2b at the queenside */
}
for (bk = A1; bk <= H8; bk++)
{
if (distance(bk, wk) < 2)
{
continue;
}
for (wp = A2; wp <= A8; wp++)
{
if (wp != A8)
{
if (wp == wk || wp == bk)
{
continue;
}
}
for (bp = A2; bp <= A8; bp++)
{
if (bp != A8)
{
if (bp == wk || bp == bk || bp == wp)
{
continue;
}
}
cleanPosition(&position);
position.piece[wk] = WHITE_KING;
position.piece[bk] = BLACK_KING;
if (wp >= A2 && wp <= H7)
{
position.piece[wp] = WHITE_PAWN;
}
if (bp >= A2 && bp <= H7)
{
position.piece[bp] = BLACK_PAWN;
}
initializePosition(&position);
updateKpkpValue(&position);
count++;
if ((count & 0xffff) == 0)
{
logDebug("%ld done.\n", count);
}
}
}
}
}
writeTableToFile(&kpkpTempTable[0], KPKP_TABLESIZE, "kpkp.c", "kpkpTable");
}
#endif
INLINE static int quad(int y_min, int y_max, int rank)
{
const int bonusPerRank[8] = { 0, 0, 0, 26, 77, 154, 256, 0 };
return y_min + ((y_max - y_min) * bonusPerRank[rank] + 128) / 256;
}
INLINE static int getHomeSecurityWeight(const Position * position)
{
const int count = getPieceCount(position, WHITE_KNIGHT) +
getPieceCount(position, WHITE_BISHOP) +
getPieceCount(position, BLACK_KNIGHT) +
getPieceCount(position, BLACK_BISHOP);
return count * count;
}
INLINE static bool squareIsPawnSafe(const EvaluationBase * base,
const Color color, const Square square)
{
return testSquare(base->pawnAttackableSquares[opponent(color)],
square) == FALSE;
}
INLINE static bool hasAttackingBishop(const Position * position,
const Color attackingColor,
const Square square)
{
const Bitboard attackers =
((lightSquares & minValue[square]) != EMPTY_BITBOARD ?
lightSquares : darkSquares);
return (bool)
((attackers & position->piecesOfType[BISHOP | attackingColor]) !=
EMPTY_BITBOARD);
}
/*
INLINE static bool pieceIsPinnedByBishop(const Position * position,
const Square pinnedPiece,
const Square pinningPiece,
const Bitboard targets)
{
return (bool)
((getDiaSquaresBehind(position, pinnedPiece, pinningPiece) & targets) !=
EMPTY_BITBOARD);
}
INLINE static bool pieceIsPinnedByRook(const Position * position,
const Square pinnedPiece,
const Square pinningPiece,
const Bitboard targets)
{
return (bool)
((getOrthoSquaresBehind(position, pinnedPiece, pinningPiece) & targets)
!= EMPTY_BITBOARD);
}
*/
#ifdef BONUS_PINS
static INLINE Piece getPinningOrthoPiece(const Position * position,
const Color pieceColor,
const Square pinnedPieceSquare,
const Square targetSquare,
const bool targetUnprotected,
const bool pinnedPiecePawnProtected)
{
const Bitboard candidates = (pinnedPiecePawnProtected ?
position->piecesOfType[ROOK | pieceColor] :
position->piecesOfType[ROOK | pieceColor] |
position->piecesOfType[QUEEN | pieceColor]);
Bitboard pinningCandidate =
getMagicRookMoves(pinnedPieceSquare, position->allPieces) &
squaresBehind[pinnedPieceSquare][targetSquare] & candidates;
if (pinningCandidate != EMPTY_BITBOARD)
{
const Square pinningPieceSquare = getLastSquare(&pinningCandidate);
const Piece pinningPiece = position->piece[pinningPieceSquare];
if (targetUnprotected)
{
return pinningPiece;
}
if (pieceType(pinningPiece) == ROOK &&
pieceType(position->piece[targetSquare]) == QUEEN)
{
return pinningPiece;
}
}
return NO_PIECE;
}
static INLINE Piece getPinningDiaPiece(const Position * position,
const Color pieceColor,
const Square pinnedPieceSquare,
const Square targetSquare,
const bool targetUnprotected,
const bool pinnedPiecePawnProtected)
{
const Bitboard candidates = (pinnedPiecePawnProtected ?
position->piecesOfType[BISHOP | pieceColor] :
position->piecesOfType[BISHOP | pieceColor] |
position->piecesOfType[QUEEN | pieceColor]);
Bitboard pinningCandidate =
getMagicBishopMoves(pinnedPieceSquare, position->allPieces) &
squaresBehind[pinnedPieceSquare][targetSquare] & candidates;
if (pinningCandidate != EMPTY_BITBOARD)
{
const Square pinningPieceSquare = getLastSquare(&pinningCandidate);
const Piece pinningPiece = position->piece[pinningPieceSquare];
if (targetUnprotected)
{
return pinningPiece;
}
if (pieceType(pinningPiece) == BISHOP &&
pieceType(position->piece[targetSquare]) == QUEEN)
{
const PieceType targetPieceType =
pieceType(position->piece[targetSquare]);
if (targetPieceType == QUEEN || targetPieceType == ROOK)
{
return pinningPiece;
}
}
}
return NO_PIECE;
}
#endif
INLINE static void getPawnInfo(const Position * position,
EvaluationBase * base)
{
const Bitboard white = position->piecesOfType[WHITE_PAWN];
const Bitboard black = position->piecesOfType[BLACK_PAWN];
Bitboard whiteLateralSquares, blackLateralSquares;
Bitboard whiteSwamp, blackSwamp;
Bitboard pawnAttackableSquaresWhite, pawnAttackableSquaresBlack;
register Bitboard tmp1, tmp2;
Bitboard blocked, free;
Square square;
/* Calculate upward and downward realms */
tmp1 = (white << 8) | (white << 16) | (white << 24);
tmp1 |= (tmp1 << 24);
tmp2 = (white >> 8) | (white >> 16) | (white >> 24);
tmp2 |= (tmp2 >> 24);
base->doubledPawns[WHITE] = white & tmp2;
base->upwardRealm[WHITE] = (tmp1 = tmp1 | white);
pawnAttackableSquaresWhite = ((tmp1 & nonA) << 7) | ((tmp1 & nonH) << 9);
base->downwardRealm[WHITE] = tmp2;
/* Calculate upward and downward realms */
tmp1 = (black >> 8) | (black >> 16) | (black >> 24);
tmp1 |= (tmp1 >> 24);
tmp2 = (black << 8) | (black << 16) | (black << 24);
tmp2 |= (tmp2 << 24);
base->doubledPawns[BLACK] = black & tmp2;
base->upwardRealm[BLACK] = (tmp1 = tmp1 | black);
pawnAttackableSquaresBlack = ((tmp1 & nonA) >> 9) | ((tmp1 & nonH) >> 7);
base->downwardRealm[BLACK] = tmp2;
/* Calculate the squares protected by a pawn */
whiteLateralSquares = ((white & nonA) >> 1) | ((white & nonH) << 1);
base->pawnProtectedSquares[WHITE] = whiteLateralSquares << 8;
blackLateralSquares = ((black & nonA) >> 1) | ((black & nonH) << 1);
base->pawnProtectedSquares[BLACK] = blackLateralSquares >> 8;
/* Identify the passed pawns */
whiteSwamp = base->downwardRealm[BLACK] | base->upwardRealm[WHITE] |
pawnAttackableSquaresWhite;
blackSwamp = base->downwardRealm[WHITE] | base->upwardRealm[BLACK] |
pawnAttackableSquaresBlack;
base->passedPawns[WHITE] = white & ~blackSwamp;
base->passedPawns[BLACK] = black & ~whiteSwamp;
/* Calculate the weak pawns */
tmp2 = ~(white | black | base->pawnProtectedSquares[BLACK]);
tmp1 = (whiteLateralSquares & tmp2) >> 8;
tmp1 |= (tmp1 & squaresOfRank[RANK_3] & tmp2) >> 8;
base->weakPawns[WHITE] =
(white & ~(pawnAttackableSquaresWhite | whiteLateralSquares | tmp1));
tmp2 = ~(white | black | base->pawnProtectedSquares[WHITE]);
tmp1 = (blackLateralSquares & tmp2) << 8;
tmp1 |= (tmp1 & squaresOfRank[RANK_6] & tmp2) << 8;
base->weakPawns[BLACK] =
(black & ~(pawnAttackableSquaresBlack | blackLateralSquares | tmp1));
base->weakOutpostSquares[WHITE] = base->upwardRealm[WHITE] &
~(pawnAttackableSquaresWhite |
base->downwardRealm[BLACK] | white | black) &
weakOutpostSquareCandidates[WHITE];
base->weakOutpostSquares[BLACK] = base->upwardRealm[BLACK] &
~(pawnAttackableSquaresBlack |
base->downwardRealm[WHITE] | white | black) &
weakOutpostSquareCandidates[BLACK];
/* Calculate the candidates */
base->candidatePawns[WHITE] = white & ~base->passedPawns[WHITE] &
(pawnAttackableSquaresWhite | whiteLateralSquares) &
~(base->upwardRealm[BLACK] | base->downwardRealm[WHITE]);
base->candidatePawns[BLACK] = black & ~base->passedPawns[BLACK] &
(pawnAttackableSquaresBlack | blackLateralSquares) &
~(base->upwardRealm[WHITE] | base->downwardRealm[BLACK]);
#ifdef BONUS_HIDDEN_PASSER
/* Calculate the hidden candidates */
base->hiddenCandidatePawns[WHITE] = white & (black >> 8) &
~pawnAttackableSquaresBlack & ~(blackLateralSquares) &
(squaresOfRank[RANK_5] | squaresOfRank[RANK_6]) &
base->pawnProtectedSquares[WHITE];
base->hiddenCandidatePawns[BLACK] = black & (white << 8) &
~pawnAttackableSquaresWhite & ~(whiteLateralSquares) &
(squaresOfRank[RANK_4] | squaresOfRank[RANK_3]) &
base->pawnProtectedSquares[BLACK];
#endif
tmp1 = black & base->pawnProtectedSquares[BLACK];
tmp2 = ((tmp1 & nonA) >> 9) & ((tmp1 & nonH) >> 7);
tmp2 &= ~pawnAttackableSquaresWhite;
tmp1 = tmp2 | (tmp2 >> 8);
base->fixedPawns[WHITE] = tmp1 | (tmp1 >> 16) | (tmp1 >> 32);
tmp1 = white & base->pawnProtectedSquares[WHITE];
tmp2 = ((tmp1 & nonA) << 7) & ((tmp1 & nonH) << 9);
tmp2 &= ~pawnAttackableSquaresBlack;
tmp1 = tmp2 | (tmp2 << 8);
base->fixedPawns[BLACK] = tmp1 | (tmp1 << 16) | (tmp1 << 32);
#ifdef BONUS_HIDDEN_PASSER
base->hasPassersOrCandidates[WHITE] = (bool)
(base->passedPawns[WHITE] != EMPTY_BITBOARD ||
base->candidatePawns[WHITE] != EMPTY_BITBOARD ||
base->hiddenCandidatePawns[WHITE] != EMPTY_BITBOARD);
base->hasPassersOrCandidates[BLACK] = (bool)
(base->passedPawns[BLACK] != EMPTY_BITBOARD ||
base->candidatePawns[BLACK] != EMPTY_BITBOARD ||
base->hiddenCandidatePawns[BLACK] != EMPTY_BITBOARD);
#endif
tmp1 = (white << 8) & ~(white | black);
tmp2 = white | (tmp1 & ~base->pawnProtectedSquares[BLACK]);
tmp2 |= tmp1 & base->pawnProtectedSquares[WHITE];
tmp1 &= squaresOfRank[RANK_3] & ~base->pawnProtectedSquares[BLACK];
tmp1 = (tmp1 << 8) & ~(white | black);
tmp2 |= tmp1 & ~base->pawnProtectedSquares[BLACK];
tmp2 |= tmp1 & base->pawnProtectedSquares[WHITE];
base->pawnAttackableSquares[WHITE] =
((tmp2 & nonA) << 7) | ((tmp2 & nonH) << 9);
/*dumpBitboard(base->pawnAttackableSquares[WHITE], "pawnAttackable white");
dumpPosition(position); */
tmp1 = (black >> 8) & ~(white | black);
tmp2 = black | (tmp1 & ~base->pawnProtectedSquares[WHITE]);
tmp2 |= tmp1 & base->pawnProtectedSquares[BLACK];
tmp1 &= squaresOfRank[RANK_6] & ~base->pawnProtectedSquares[WHITE];
tmp1 = (tmp1 >> 8) & ~(white | black);
tmp2 |= tmp1 & ~base->pawnProtectedSquares[WHITE];
tmp2 |= tmp1 & base->pawnProtectedSquares[BLACK];
base->pawnAttackableSquares[BLACK] =
((tmp2 & nonA) >> 9) | ((tmp2 & nonH) >> 7);
base->pawnLightSquareMalus[WHITE] = base->pawnLightSquareMalus[BLACK] = 0;
base->pawnDarkSquareMalus[WHITE] = base->pawnDarkSquareMalus[BLACK] = 0;
blocked = white & (black >> 8);
free = white & ~blocked;
ITERATE_BITBOARD(&blocked, square)
{
const int malus =
MALUS_PAWN_SQUARE_TYPE[square] + MALUS_PAWN_SQUARE_TYPE[square];
if (testSquare(lightSquares, square))
{
base->pawnLightSquareMalus[WHITE] += malus;
}
else
{
base->pawnDarkSquareMalus[WHITE] += malus;
}
}
ITERATE_BITBOARD(&free, square)
{
const int malus = MALUS_PAWN_SQUARE_TYPE[square];
if (testSquare(lightSquares, square))
{
base->pawnLightSquareMalus[WHITE] += malus;
}
else
{
base->pawnDarkSquareMalus[WHITE] += malus;
}
}
blocked = black & (white << 8);
free = black & ~blocked;
ITERATE_BITBOARD(&blocked, square)
{
const int malus =
MALUS_PAWN_SQUARE_TYPE[square] + MALUS_PAWN_SQUARE_TYPE[square];
if (testSquare(lightSquares, square))
{
base->pawnLightSquareMalus[BLACK] += malus;
}
else
{
base->pawnDarkSquareMalus[BLACK] += malus;
}
}
ITERATE_BITBOARD(&free, square)
{
const int malus = MALUS_PAWN_SQUARE_TYPE[square];
if (testSquare(lightSquares, square))
{
base->pawnLightSquareMalus[BLACK] += malus;
}
else
{
base->pawnDarkSquareMalus[BLACK] += malus;
}
}
base->chainPawns[WHITE] = white &
(base->pawnProtectedSquares[WHITE] | whiteLateralSquares);
base->chainPawns[BLACK] = black &
(base->pawnProtectedSquares[BLACK] | blackLateralSquares);
}
bool pawnIsPassed(const Position * position, const Square pawnSquare,
const Color pawnColor)
{
const Color defenderColor = opponent(pawnColor);
const Bitboard blockers = position->piecesOfType[PAWN | defenderColor] &
(candidateDefenders[pawnColor][pawnSquare] |
passedPawnCorridor[pawnColor][pawnSquare]);
return (bool) (blockers == EMPTY_BITBOARD);
}
static int getPassedPawnDefenderMalus(const Color pawnColor,
const Color activeColor,
const Square passedPawnSquare,
const Square defenderSquare)
{
const int pawnDirection = (pawnColor == WHITE ? 8 : -8);
const Square stopSquare = (Square) (passedPawnSquare + pawnDirection);
const Square rectangleSquare =
(pawnColor == activeColor ?
passedPawnSquare : (Square) (passedPawnSquare - pawnDirection));
const bool kingInRectangle =
testSquare(passedPawnRectangle[pawnColor][rectangleSquare],
defenderSquare);
const int defenderDistWeight =
(kingInRectangle ? (2 * PASSED_PAWN_DEFENDERDIST_WEIGHT) / 3 :
PASSED_PAWN_DEFENDERDIST_WEIGHT);
return distance(stopSquare, defenderSquare) * defenderDistWeight;
}
static INLINE bool passerWalks(const Position * position,
const Square passerSquare,
const Color passerColor)
{
const Square attackerKingSquare = position->king[passerColor];
const Square defenderKingSquare = position->king[opponent(passerColor)];
const int attackerDistance = distance(attackerKingSquare, passerSquare);
const Rank kingRank = colorRank(passerColor, attackerKingSquare);
const File passerFile = file(passerSquare);
if (passerFile >= FILE_B && passerFile <= FILE_G)
{
if ((kingRank == RANK_6 || kingRank == RANK_7) &&
kingRank > colorRank(passerColor, passerSquare) &&
abs(file(attackerKingSquare) - passerFile) <= 1 &&
attackerDistance <= 2)
{
if (position->activeColor == passerColor ||
attackerDistance == 1 ||
distance(defenderKingSquare, passerSquare) > 1)
{
return TRUE;
}
}
/*
if (kingRank == colorRank(passerColor, passerSquare) + 2 &&
abs(file(attackerKingSquare) - passerFile) <= 1 &&
attackerDistance <= 2)
{
if (position->activeColor == passerColor ||
attackerDistance == 1 ||
distance(defenderKingSquare, passerSquare) > 1)
{
return TRUE;
}
}
*/
}
else if ((kingRank == RANK_7 || kingRank == RANK_8) &&
abs(file(attackerKingSquare) - passerFile) == 1 &&
attackerDistance <= 2)
{
if (position->activeColor == passerColor ||
attackerDistance == 1 ||
distance(defenderKingSquare, passerSquare) > 1)
{
return TRUE;
}
}
return FALSE;
}
/*
static INLINE bool isBlockingSquare(const Position * position,
const EvaluationBase * base, const Square square,
const Color blockingColor)
{
const Square blockedSquare = (Square)
(blockingColor == WHITE ? square + 8 : square - 8);
const Piece blockedPawn = (Piece) (PAWN | opponent(blockingColor));
return (bool) (position->piece[blockedSquare] == blockedPawn &&
squareIsPawnSafe(base, blockingColor, square));
}
*/
/*
static INLINE int pawnDefenderDistance(const Square defenderSquare,
const Color defenderColor,
const Square pawnSquare)
{
const int defenderRank = rank(defenderSquare);
const int pawnRank = rank(pawnSquare);
if (defenderColor == WHITE)
{
return (defenderRank <= pawnRank ?
abs(file(defenderSquare) - file(pawnSquare)) :
distance(defenderSquare, pawnSquare));
}
else
{
return (defenderRank >= pawnRank ?
abs(file(defenderSquare) - file(pawnSquare)) :
distance(defenderSquare, pawnSquare));
}
}
*/
/*
INLINE static int getMobilityCount(const EvaluationBase * base,
const Bitboard moves, const Color color)
{
return getNumberOfSetSquares(moves & base->countedSquares[color]);
}
*/
INLINE static Piece getOrthoBatteryPiece(const Position * position,
const Bitboard moves,
const Square attackerSquare,
const Color kingColor)
{
const Square kingSquare = position->king[kingColor];
Bitboard middlePiece = EMPTY_BITBOARD;
if (testSquare(generalMoves[ROOK][kingSquare], attackerSquare))
{
middlePiece = generalMoves[ROOK][attackerSquare] &
moves & getMagicRookMoves(kingSquare, position->allPieces);
if (middlePiece != EMPTY_BITBOARD)
{
const Square pieceSquare = getLastSquare(&middlePiece);
return position->piece[pieceSquare];
}
}
return NO_PIECE;
}
INLINE static Piece getDiaBatteryPiece(const Position * position,
const Bitboard moves,
const Square attackerSquare,
const Color kingColor)
{
const Square kingSquare = position->king[kingColor];
Bitboard middlePiece = EMPTY_BITBOARD;
if (testSquare(generalMoves[BISHOP][kingSquare], attackerSquare))
{
middlePiece = generalMoves[BISHOP][attackerSquare] &
moves & getMagicBishopMoves(kingSquare, position->allPieces);
if (middlePiece != EMPTY_BITBOARD)
{
const Square pieceSquare = getLastSquare(&middlePiece);
return position->piece[pieceSquare];
}
}
return NO_PIECE;
}
INLINE static bool grantSeventhRankBonus(const Position * position,
const Color color,
const Color oppColor,
const Square pieceSquare)
{
if (colorRank(color, pieceSquare) == RANK_7)
{
const static Rank seventhRankByColor[2] = { RANK_7, RANK_2 };
const Bitboard seventhRank = squaresOfRank[seventhRankByColor[color]];
if ((seventhRank & position->piecesOfType[PAWN | oppColor]) ||
(colorRank(color, position->king[oppColor]) >= RANK_7))
{
return TRUE;
}
}
return FALSE;
}
#define PERSPECTIVE_WHITE
#include "evaluationc.c"
#undef PERSPECTIVE_WHITE
#include "evaluationc.c"
INLINE static void evaluatePawns(const Position * position,
EvaluationBase * base)
{
#ifdef REDUCED_PAWN_EVAL
const static INT32 isolatedMalusPerFile[8] = {
V(9, 9), V(13, 11), V(14, 11), V(14, 11),
V(14, 11), V(14, 11), V(13, 11), V(9, 9)
};
const static INT32 isolatedMalusPerOpenFile[8] = {
V(13, 14), V(19, 16), V(21, 16), V(21, 16),
V(21, 16), V(21, 16), V(19, 16), V(13, 14)
};
const static INT32 backwardMalusPerFile[8] = {
V(7, 9), V(10, 10), V(12, 10), V(12, 10),
V(12, 10), V(12, 10), V(10, 10), V(7, 9)
};
const static INT32 backwardMalusPerOpenFile[8] = {
V(11, 13), V(15, 14), V(18, 14), V(18, 14),
V(18, 14), V(18, 14), V(15, 14), V(11, 13)
};
const static INT32 candidateBonusPerRank[8] = {
V(0, 0), V(2, 5), V(2, 5), V(5, 11),
V(13, 26), V(32, 64), V(0, 0), V(0, 0)
};
/*
const static INT32 candidateBonusPerRank[8] = {
V(0, 0), V(2, 4), V(2, 4), V(5, 9),
V(12, 21), V(30, 51), V(0, 0), V(0, 0)
};
*/
#else
const static INT32 isolatedMalusPerFile[8] = {
V(10, 12), V(14, 14), V(16, 14), V(16, 14),
V(16, 14), V(16, 14), V(14, 14), V(10, 12)
};
const static INT32 isolatedMalusPerOpenFile[8] = {
V(15, 18), V(21, 21), V(24, 21), V(24, 21),
V(24, 21), V(24, 21), V(21, 21), V(15, 18)
};
const static INT32 backwardMalusPerFile[8] = {
V(8, 11), V(11, 12), V(13, 12), V(13, 12),
V(13, 12), V(13, 12), V(11, 12), V(8, 11)
};
const static INT32 backwardMalusPerOpenFile[8] = {
V(12, 16), V(16, 18), V(19, 18), V(19, 18),
V(19, 18), V(19, 18), V(16, 18), V(12, 16)
};
const static INT32 candidateBonusPerRank[8] = {
V(0, 0), V(2, 5), V(2, 5), V(5, 11),
V(13, 26), V(32, 64), V(0, 0), V(0, 0)
};
#endif
Square square;
Bitboard pieces = (base->weakPawns[WHITE] | base->weakPawns[BLACK]);
ITERATE_BITBOARD(&pieces, square)
{
const Color pawnColor = pieceColor(position->piece[square]);
const Color oppColor = opponent(pawnColor);
const File pawnfile = file(square);
const bool isolated = (bool)
((companionFiles[square] &
position->piecesOfType[position->piece[square]]) ==
EMPTY_BITBOARD);
const bool onOpenFile = (bool)
(testSquare(base->upwardRealm[oppColor], square) == FALSE &&
testSquare(base->doubledPawns[pawnColor], square) == FALSE);
if (isolated)
{
if (onOpenFile)
{
addEvalMalusForColor(base, pawnColor,
isolatedMalusPerOpenFile[pawnfile]);
}
else
{
addEvalMalusForColor(base, pawnColor,
isolatedMalusPerFile[pawnfile]);
}
if (testSquare(base->fixedPawns[pawnColor], square))
{
addEvalMalusForColor(base, pawnColor, V(2, 3));
}
}
else /* backward */
{
if (onOpenFile)
{
addEvalMalusForColor(base, pawnColor,
backwardMalusPerOpenFile[pawnfile]);
}
else
{
addEvalMalusForColor(base, pawnColor,
backwardMalusPerFile[pawnfile]);
}
if (testSquare(base->fixedPawns[pawnColor], square))
{
addEvalMalusForColor(base, pawnColor, V(2, 3));
}
}
}
pieces = (base->candidatePawns[WHITE] | base->candidatePawns[BLACK]);
ITERATE_BITBOARD(&pieces, square)
{
const Color pawnColor = pieceColor(position->piece[square]);
const Bitboard supporters = candidateSupporters[pawnColor][square] &
position->piecesOfType[PAWN | pawnColor];
const Bitboard defenders = candidateDefenders[pawnColor][square] &
position->piecesOfType[PAWN | opponent(pawnColor)];
if (getNumberOfSetSquares(supporters) >=
getNumberOfSetSquares(defenders))
{
const Bitboard ownDefenders =
generalMoves[PAWN | opponent(pawnColor)][square] &
position->piecesOfType[PAWN | pawnColor];
const Bitboard attackers =
generalMoves[PAWN | pawnColor][square] &
position->piecesOfType[PAWN | opponent(pawnColor)];
if (getNumberOfSetSquares(ownDefenders) >=
getNumberOfSetSquares(attackers))
{
const Rank pawnRank = colorRank(pawnColor, square);
addEvalBonusForColor(base, pawnColor,
candidateBonusPerRank[pawnRank]);
}
}
}
evaluateWhitePawns(base);
evaluateBlackPawns(base);
}
INLINE static void evaluatePassedPawns(const Position * position,
EvaluationBase * base)
{
Square square;
Bitboard pieces = base->passedPawns[WHITE];
ITERATE_BITBOARD(&pieces, square)
{
evaluateWhitePasser(position, base, square);
}
pieces = base->passedPawns[BLACK];
ITERATE_BITBOARD(&pieces, square)
{
evaluateBlackPasser(position, base, square);
}
}
INLINE static void evaluateWhiteTrappedBishops(const Position * position,
EvaluationBase * base)
{
if ((position->piece[A7] == WHITE_BISHOP &&
position->piece[B6] == BLACK_PAWN) ||
(position->piece[B8] == WHITE_BISHOP &&
position->piece[C7] == BLACK_PAWN) ||
(position->piece[H7] == WHITE_BISHOP &&
position->piece[G6] == BLACK_PAWN) ||
(position->piece[G8] == WHITE_BISHOP &&
position->piece[F7] == BLACK_PAWN))
{
base->balance -= V(BISHOP_MALUS_TRAPPED, BISHOP_MALUS_TRAPPED);
}
if ((position->piece[A6] == WHITE_BISHOP &&
position->piece[B5] == BLACK_PAWN) ||
(position->piece[H6] == WHITE_BISHOP &&
position->piece[G5] == BLACK_PAWN))
{
base->balance -= V(BISHOP_MALUS_TRAPPED / 2, BISHOP_MALUS_TRAPPED / 2);
}
if ((position->piece[C1] == WHITE_BISHOP &&
position->piece[D2] == WHITE_PAWN &&
position->piece[D3] != NO_PIECE) ||
(position->piece[F1] == WHITE_BISHOP &&
position->piece[E2] == WHITE_PAWN && position->piece[E3] != NO_PIECE))
{
base->balance -= V(BISHOP_MALUS_BLOCKED, BISHOP_MALUS_BLOCKED);
}
}
INLINE static void evaluateBlackTrappedBishops(const Position * position,
EvaluationBase * base)
{
if ((position->piece[A2] == BLACK_BISHOP &&
position->piece[B3] == WHITE_PAWN) ||
(position->piece[B1] == BLACK_BISHOP &&
position->piece[C2] == WHITE_PAWN) ||
(position->piece[H2] == BLACK_BISHOP &&
position->piece[G3] == WHITE_PAWN) ||
(position->piece[G1] == BLACK_BISHOP &&
position->piece[F2] == WHITE_PAWN))
{
base->balance += V(BISHOP_MALUS_TRAPPED, BISHOP_MALUS_TRAPPED);
}
if ((position->piece[A3] == BLACK_BISHOP &&
position->piece[B4] == WHITE_PAWN) ||
(position->piece[H3] == BLACK_BISHOP &&
position->piece[G4] == WHITE_PAWN))
{
base->balance += V(BISHOP_MALUS_TRAPPED / 2, BISHOP_MALUS_TRAPPED / 2);
}
if ((position->piece[C8] == BLACK_BISHOP &&
position->piece[D7] == BLACK_PAWN &&
position->piece[D6] != NO_PIECE) ||
(position->piece[F8] == BLACK_BISHOP &&
position->piece[E7] == BLACK_PAWN && position->piece[E6] != NO_PIECE))
{
base->balance += V(BISHOP_MALUS_BLOCKED, BISHOP_MALUS_BLOCKED);
}
}
INLINE static int getSafetyMalusOfKingFile(const Position * position,
const int file,
const Square kingSquare,
const int fileType,
const Color color)
{
return (color == WHITE ?
getPawnSafetyMalusOfWhiteKingFile(position, file, kingSquare,
fileType) :
getPawnSafetyMalusOfBlackKingFile(position, file, kingSquare,
fileType));
}
INLINE static int getSafetyMalusOfKingSquare(const Position * position,
const Square kingSquare,
const Color color)
{
const int kingFile = file(kingSquare);
int malus =
getSafetyMalusOfKingFile(position, kingFile, kingSquare, 1, color);
if (kingFile > FILE_A)
{
const int fileType = (kingFile <= FILE_D ? 0 : 2);
malus += getSafetyMalusOfKingFile(position, kingFile - 1, kingSquare,
fileType, color);
}
if (kingFile < FILE_H)
{
const int fileType = (kingFile <= FILE_D ? 2 : 0);
malus += getSafetyMalusOfKingFile(position, kingFile + 1, kingSquare,
fileType, color);
}
if (malus == 0)
{
malus = 10; /* malus for weak back rank */
}
return malus;
}
static int getPawnShelterMalus(const Position * position, const Color color,
KingSafetyHashInfo * kingSafetyHashtable)
{
const Bitboard hashValue = getKingPawnSafetyHashValue(position, color);
KingSafetyHashInfo *kingSafetyHashInfo =
&kingSafetyHashtable[hashValue & KINGSAFETY_HASHTABLE_MASK];
if (kingSafetyHashInfo->hashValue == hashValue &&
kingSafetyHashInfo->hashValue != 0)
{
return kingSafetyHashInfo->safetyMalus;
}
else
{
const static int rankByColor[2] = { RANK_1, RANK_8 };
int cr00, cr000;
const Square kingSquare = position->king[color];
int pawnShelterMalus = 0, castlingShelterMalus = 0;
if (color == WHITE)
{
cr00 = WHITE_00, cr000 = WHITE_000;
}
else
{
cr00 = BLACK_00, cr000 = BLACK_000;
}
pawnShelterMalus = castlingShelterMalus =
getSafetyMalusOfKingSquare(position, kingSquare, color);
if (position->castlingRights & cr00)
{
const Square kingSquare = getSquare(FILE_G, rankByColor[color]);
const int malus00 =
getSafetyMalusOfKingSquare(position, kingSquare, color);
castlingShelterMalus = min(malus00, castlingShelterMalus);
}
if (position->castlingRights & cr000)
{
const Square kingSquare = getSquare(FILE_B, rankByColor[color]);
const int malus000 =
getSafetyMalusOfKingSquare(position, kingSquare, color);
castlingShelterMalus = min(malus000, castlingShelterMalus);
}
pawnShelterMalus = (pawnShelterMalus + castlingShelterMalus) / 2;
kingSafetyHashInfo->hashValue = hashValue;
kingSafetyHashInfo->safetyMalus = pawnShelterMalus;
return pawnShelterMalus;
}
}
static int getKingSafetyMalus(const Position * position,
EvaluationBase * base, const Color color)
{
const int pawnShelterMalus =
getPawnShelterMalus(position, color, base->kingsafetyHashtable);
const Color oppColor = opponent(color);
const Square kingSquare = position->king[color];
const Bitboard corona = getKingMoves(kingSquare);
const Bitboard protectingPawn = corona &
passedPawnCorridor[color][kingSquare];
const Bitboard pawnAttackers =
position->piecesOfType[PAWN | oppColor] & kingAttacks[kingSquare].
pawnAttackers[oppColor] & ~protectingPawn;
const int numAttackers = getEndgameValue(base->attackInfo[oppColor]) +
getNumberOfSetSquares(pawnAttackers) / 2;
int attackUnits = 0;
if (base->evaluateKingSafety[color] && numAttackers >= 2 &&
base->kingSquaresAttackCount[oppColor] > 0)
{
const int kingSquareWeight = 12 + getPieceWeight(position, oppColor);
const Square relativeKingSquare =
(color == WHITE ? kingSquare : getFlippedSquare(kingSquare));
const int kingSquareMalus =
(MALUS_KING_SQUARE[relativeKingSquare] * kingSquareWeight) / 24;
const int attackersWeight = getOpeningValue(base->attackInfo[oppColor]);
const Bitboard oppQueenAttacks = base->queenAttackedSquares[oppColor];
const Bitboard oppAttacks = base->attackedSquares[oppColor] |
getKingMoves(position->king[oppColor]);
const Bitboard attackedSquares =
corona & (oppAttacks | oppQueenAttacks);
const Bitboard defendedSquares =
base->attackedSquares[color] | base->queenAttackedSquares[color];
const Bitboard undefendedSquares = attackedSquares & ~defendedSquares;
const Bitboard safeQueenChecks =
oppQueenAttacks & oppAttacks & undefendedSquares;
const int squareAttackCount =
(base->kingSquaresAttackCount[oppColor] +
getNumberOfSetSquares(undefendedSquares));
const Bitboard safeChecks =
~(position->piecesOfColor[oppColor] | defendedSquares);
const Bitboard safeOrthoChecks = safeChecks &
getMagicRookMoves(kingSquare, position->allPieces);
const Bitboard safeDiaChecks = safeChecks &
getMagicBishopMoves(kingSquare, position->allPieces);
const Bitboard safeKnightChecks = safeChecks &
getKnightMoves(kingSquare);
const Bitboard batteryAttackers = safeChecks &
base->batteryAttackers[oppColor];
#ifdef MALUS_QUEEN_DEFENDER_DISTANCE
Piece queens = (Piece) (QUEEN | color);
const int queenDistance =
getMinimalTaxiDistance(position, kingSquare, queens);
#endif
attackUnits =
min(25, numAttackers * attackersWeight / 2) +
3 * squareAttackCount + kingSquareMalus + pawnShelterMalus / 16;
if (batteryAttackers != EMPTY_BITBOARD)
{
const int numAttackers = getNumberOfSetSquares(batteryAttackers);
const int activeColorFactor =
(oppColor == position->activeColor ? 2 : 1);
attackUnits += numAttackers * activeColorFactor;
}
if (safeQueenChecks != EMPTY_BITBOARD)
{
const int numChecks = getNumberOfSetSquares(safeQueenChecks);
const int activeColorFactor =
(oppColor == position->activeColor ? 6 : 3);
attackUnits += numChecks * activeColorFactor;
}
if (safeOrthoChecks != EMPTY_BITBOARD)
{
const Bitboard queenChecks =
safeOrthoChecks & base->queenAttackedSquares[oppColor];
const Bitboard rookChecks =
safeOrthoChecks & base->rookAttackedSquares[oppColor];
if (queenChecks != EMPTY_BITBOARD)
{
attackUnits += getNumberOfSetSquares(queenChecks);
}
if (rookChecks != EMPTY_BITBOARD)
{
attackUnits += getNumberOfSetSquares(rookChecks);
}
}
if (safeDiaChecks != EMPTY_BITBOARD)
{
const Bitboard queenChecks =
safeDiaChecks & base->queenAttackedSquares[oppColor];
const Bitboard bishopChecks =
safeDiaChecks & base->bishopAttackedSquares[oppColor];
if (queenChecks != EMPTY_BITBOARD)
{
attackUnits += getNumberOfSetSquares(queenChecks);
}
if (bishopChecks != EMPTY_BITBOARD)
{
attackUnits += getNumberOfSetSquares(bishopChecks);
}
}
if (safeKnightChecks != EMPTY_BITBOARD)
{
const Bitboard knightChecks =
safeKnightChecks & base->knightAttackedSquares[oppColor];
if (knightChecks != EMPTY_BITBOARD)
{
attackUnits += getNumberOfSetSquares(knightChecks);
}
}
#ifdef MALUS_QUEEN_DEFENDER_DISTANCE
attackUnits += queenDistance / 2;
#endif
if (attackUnits >= KING_SAFETY_MALUS_DIM)
{
attackUnits = KING_SAFETY_MALUS_DIM - 1;
}
}
return KING_SAFETY_MALUS[attackUnits] + pawnShelterMalus;
}
INLINE static bool kingSafetyEvalRequired(const Position * position,
const Color color)
{
const Color oppColor = opponent(color);
return (bool) (numberOfNonPawnPieces(position, oppColor) >= 3 &&
position->piecesOfType[QUEEN | oppColor] != EMPTY_BITBOARD);
}
#ifndef NDEBUG
static Bitboard randomBitboard()
{
Bitboard tmp1 = rand();
Bitboard tmp2 = rand();
Bitboard tmp3 = rand();
Bitboard tmp4 = rand();
return tmp1 + (tmp2 << 16) + (tmp3 << 32) + (tmp4 << 48);
}
#endif
INLINE static void initializeEvaluationBase(EvaluationBase * base,
KingSafetyHashInfo *
kingsafetyHashtable)
{
#ifndef NDEBUG
base->attackedSquares[WHITE] = randomBitboard();
base->attackedSquares[BLACK] = randomBitboard();
base->queenAttackedSquares[WHITE] = randomBitboard();
base->queenAttackedSquares[BLACK] = randomBitboard();
base->balance = rand();
base->candidatePawns[WHITE] = randomBitboard();
base->candidatePawns[BLACK] = randomBitboard();
base->countedSquares[WHITE] = randomBitboard();
base->countedSquares[BLACK] = randomBitboard();
base->doubledPawns[WHITE] = randomBitboard();
base->doubledPawns[BLACK] = randomBitboard();
base->downwardRealm[WHITE] = randomBitboard();
base->downwardRealm[BLACK] = randomBitboard();
base->evaluateKingSafety[WHITE] = (bool) rand();
base->evaluateKingSafety[BLACK] = (bool) rand();
base->fixedPawns[WHITE] = randomBitboard();
base->fixedPawns[BLACK] = randomBitboard();
base->hasPassersOrCandidates[WHITE] = (bool) rand();
base->hasPassersOrCandidates[BLACK] = (bool) rand();
base->hiddenCandidatePawns[WHITE] = randomBitboard();
base->hiddenCandidatePawns[BLACK] = randomBitboard();
base->kingAttackSquares[WHITE] = randomBitboard();
base->kingAttackSquares[BLACK] = randomBitboard();
base->numPieceAttackers[WHITE] = rand();
base->numPieceAttackers[BLACK] = rand();
base->passedPawns[WHITE] = randomBitboard();
base->passedPawns[BLACK] = randomBitboard();
base->pawnAttackableSquares[WHITE] = randomBitboard();
base->pawnAttackableSquares[BLACK] = randomBitboard();
base->pawnDarkSquareMalus[WHITE] = rand();
base->pawnDarkSquareMalus[BLACK] = rand();
base->pawnLightSquareMalus[WHITE] = rand();
base->pawnLightSquareMalus[BLACK] = rand();
base->pawnProtectedSquares[WHITE] = randomBitboard();
base->pawnProtectedSquares[BLACK] = randomBitboard();
base->spaceAttackPoints[WHITE] = rand();
base->spaceAttackPoints[BLACK] = rand();
base->unprotectedPieces[WHITE] = randomBitboard();
base->unprotectedPieces[BLACK] = randomBitboard();
base->upwardRealm[WHITE] = randomBitboard();
base->upwardRealm[BLACK] = randomBitboard();
base->weakOutpostSquares[WHITE] = randomBitboard();
base->weakOutpostSquares[BLACK] = randomBitboard();
base->weakPawns[WHITE] = randomBitboard();
base->weakPawns[BLACK] = randomBitboard();
base->kingSquaresAttackCount[WHITE] = rand();
base->kingSquaresAttackCount[BLACK] = rand();
base->attackInfo[WHITE] = rand();
base->attackInfo[BLACK] = rand();
#endif
base->balance = 0;
base->kingsafetyHashtable = kingsafetyHashtable;
base->futilityMargin[WHITE] = base->futilityMargin[BLACK] = 0;
}
INLINE static void evaluatePieces(const Position * position,
EvaluationBase * base)
{
const Bitboard exclude = position->piecesOfType[WHITE_PAWN] |
position->piecesOfType[BLACK_PAWN] |
minValue[position->king[WHITE]] | minValue[position->king[BLACK]];
Bitboard pieces = position->allPieces & (~exclude);
Square square;
#ifndef NDEBUG
if (debugEval)
{
logDebug("\nStart of piece evaluation\n");
}
#endif
ITERATE_BITBOARD(&pieces, square)
{
#ifndef NDEBUG
if (debugEval)
{
dumpSquare(square);
logDebug("op=%d eg=%d\n", getOpeningValue(base->balance),
getEndgameValue(base->balance));
}
#endif
switch (position->piece[square])
{
case WHITE_QUEEN:
evaluateWhiteQueen(position, base, square);
break;
case BLACK_QUEEN:
evaluateBlackQueen(position, base, square);
break;
case WHITE_ROOK:
evaluateWhiteRook(position, base, square);
break;
case BLACK_ROOK:
evaluateBlackRook(position, base, square);
break;
case WHITE_BISHOP:
evaluateWhiteBishop(position, base, square);
break;
case BLACK_BISHOP:
evaluateBlackBishop(position, base, square);
break;
case WHITE_KNIGHT:
evaluateWhiteKnight(position, base, square);
break;
case BLACK_KNIGHT:
evaluateBlackKnight(position, base, square);
break;
default:
break;
}
#ifndef NDEBUG
if (debugEval)
{
logDebug("op=%d eg=%d\n", getOpeningValue(base->balance),
getEndgameValue(base->balance));
}
#endif
}
if (position->piecesOfType[WHITE_BISHOP] != EMPTY_BITBOARD)
{
evaluateWhiteTrappedBishops(position, base);
}
if (position->piecesOfType[BLACK_BISHOP] != EMPTY_BITBOARD)
{
evaluateBlackTrappedBishops(position, base);
}
#ifndef NDEBUG
if (debugEval)
{
logDebug("Values after piece evaluation\n");
logDebug("op=%d eg=%d\n", getOpeningValue(base->balance),
getEndgameValue(base->balance));
logDebug("End of piece evaluation\n");
}
#endif
}
/*
static INLINE Bitboard getFixedPawns(const Position * position,
const EvaluationBase * base, const Color color)
{
const Color oppColor = opponent(color);
const Bitboard candidates = position->piecesOfType[PAWN | color] &
~base->pawnProtectedSquares[color];
const Bitboard blockers = position->piecesOfType[PAWN | color] |
position->piecesOfColor[oppColor] |
base->pawnProtectedSquares[oppColor];
return candidates & (color == WHITE ? blockers >> 8 : blockers << 8);
}
*/
static INLINE bool evaluateKingChase(const Position * position,
const Color kingColor)
{
if (position->numberOfPawns[WHITE] == 0 &&
position->numberOfPawns[BLACK] == 0 &&
numberOfNonPawnPieces(position, kingColor) <= 2)
{
return (bool) (getPieceWeight(position, kingColor) <
getPieceWeight(position, opponent(kingColor)));
}
return FALSE;
}
static INLINE int getKingChaseMalus(const Position * position,
const Color huntedKingColor)
{
const Color attackingColor = opponent(huntedKingColor);
const Square huntedKingSquare = position->king[huntedKingColor];
const Square attackingKingSquare = position->king[attackingColor];
const int mutualDistance =
distance(huntedKingSquare, attackingKingSquare) - 2;
int cornerDistanceMalus = kingChaseMalus[ALL][huntedKingSquare];
if (hasOrthoPieces(position, attackingColor) == FALSE &&
getPieceCount(position, (Piece) (BISHOP | attackingColor)) > 0)
{
const Bitboard attackingBishops =
position->piecesOfType[BISHOP | attackingColor];
if ((lightSquares & attackingBishops) == EMPTY_BITBOARD)
{
cornerDistanceMalus = kingChaseMalus[DARK][huntedKingSquare];
}
if ((darkSquares & attackingBishops) == EMPTY_BITBOARD)
{
cornerDistanceMalus = kingChaseMalus[LIGHT][huntedKingSquare];
}
}
return 5 * (5 - mutualDistance) + 15 * cornerDistanceMalus;
}
#ifdef HOMELAND_SECURITY_BONUS
static int getHomelandSecurityCount(const Position * position,
EvaluationBase * base, const Color color)
{
const Color oppColor = opponent(color);
const Bitboard ownPawns = position->piecesOfType[PAWN | color];
const Bitboard exclude = ownPawns |
base->pawnProtectedSquares[oppColor] |
(base->attackedSquares[oppColor] & ~base->attackedSquares[color]);
const Bitboard safeSquares = homeland[color] & ~exclude;
const Bitboard superSafeSquares =
safeSquares & (color == WHITE ? (ownPawns >> 8) | (ownPawns >> 16) :
(ownPawns << 8) | (ownPawns << 16));
return getNumberOfSetSquares(safeSquares) +
getNumberOfSetSquares(superSafeSquares);
}
#endif
INLINE static void evaluatePawnMobility(const Position * position,
EvaluationBase * base)
{
const int malus = V(3, 10);
const Bitboard whiteBlocked = (position->allPieces >> 8) &
position->piecesOfType[WHITE_PAWN];
const Bitboard blackBlocked = (position->allPieces << 8) &
position->piecesOfType[BLACK_PAWN];
base->balance -= (getNumberOfSetSquares(whiteBlocked) -
getNumberOfSetSquares(blackBlocked)) * malus;
}
INLINE static void getPositionalValue(const Position * position,
EvaluationBase * base)
{
const Bitboard whiteCorona = getKingMoves(position->king[WHITE]);
const Bitboard blackCorona = getKingMoves(position->king[BLACK]);
base->countedSquares[WHITE] = ~(position->piecesOfColor[WHITE] |
base->pawnProtectedSquares[BLACK]);
base->unprotectedPieces[WHITE] = position->piecesOfColor[WHITE] &
~base->pawnProtectedSquares[WHITE];
base->countedSquares[BLACK] = ~(position->piecesOfColor[BLACK] |
base->pawnProtectedSquares[WHITE]);
base->unprotectedPieces[BLACK] = position->piecesOfColor[BLACK] &
~base->pawnProtectedSquares[BLACK];
base->numPieceAttackers[WHITE] = base->numPieceAttackers[BLACK] = 0;
base->spaceAttackPoints[WHITE] = base->spaceAttackPoints[BLACK] = 0;
base->attackedSquares[WHITE] = base->pawnProtectedSquares[WHITE];
base->attackedSquares[BLACK] = base->pawnProtectedSquares[BLACK];
base->batteryAttackers[WHITE] = EMPTY_BITBOARD;
base->batteryAttackers[BLACK] = EMPTY_BITBOARD;
base->knightAttackedSquares[WHITE] = EMPTY_BITBOARD;
base->knightAttackedSquares[BLACK] = EMPTY_BITBOARD;
base->bishopAttackedSquares[WHITE] = EMPTY_BITBOARD;
base->bishopAttackedSquares[BLACK] = EMPTY_BITBOARD;
base->rookAttackedSquares[WHITE] = EMPTY_BITBOARD;
base->rookAttackedSquares[BLACK] = EMPTY_BITBOARD;
base->queenAttackedSquares[WHITE] = EMPTY_BITBOARD;
base->queenAttackedSquares[BLACK] = EMPTY_BITBOARD;
base->kingAttackSquares[WHITE] = whiteCorona | (whiteCorona << 8);
base->kingAttackSquares[BLACK] = blackCorona | (blackCorona >> 8);
base->evaluateKingSafety[WHITE] = kingSafetyEvalRequired(position, WHITE);
base->evaluateKingSafety[BLACK] = kingSafetyEvalRequired(position, BLACK);
base->kingSquaresAttackCount[WHITE] =
base->kingSquaresAttackCount[BLACK] = 0;
base->attackInfo[WHITE] = base->attackInfo[BLACK] = 0;
evaluatePieces(position, base);
base->attackedSquares[WHITE] |= base->knightAttackedSquares[WHITE] |
base->bishopAttackedSquares[WHITE] | base->rookAttackedSquares[WHITE];
base->attackedSquares[BLACK] |= base->knightAttackedSquares[BLACK] |
base->bishopAttackedSquares[BLACK] | base->rookAttackedSquares[BLACK];
#ifndef NDEBUG
if (debugEval)
{
logDebug("\nEval values before king safety eval:\n");
logDebug("op=%d eg=%d\n", getOpeningValue(base->balance),
getEndgameValue(base->balance));
}
#endif
{
const int malus = getKingSafetyMalus(position, base, WHITE);
base->balance -= V(malus, 0);
base->futilityMargin[WHITE] = max(base->futilityMargin[WHITE], malus);
}
{
const int malus = getKingSafetyMalus(position, base, BLACK);
base->balance += V(malus, 0);
base->futilityMargin[BLACK] = max(base->futilityMargin[BLACK], malus);
}
base->attackedSquares[WHITE] |= base->queenAttackedSquares[WHITE];
base->attackedSquares[BLACK] |= base->queenAttackedSquares[BLACK];
#ifdef MALUS_PAWN_MOBILITY
evaluatePawnMobility(position, base);
#endif
#ifndef NDEBUG
if (debugEval)
{
logDebug("\nEval values before passed pawn eval:\n");
logDebug("op=%d eg=%d\n", getOpeningValue(base->balance),
getEndgameValue(base->balance));
}
#endif
if (base->passedPawns[WHITE] != EMPTY_BITBOARD ||
base->passedPawns[BLACK] != EMPTY_BITBOARD)
{
#ifndef NDEBUG
if (debugEval)
{
dumpBitboard(base->passedPawns[WHITE], "white passers");
dumpBitboard(base->passedPawns[BLACK], "black passers");
}
#endif
evaluatePassedPawns(position, base);
}
if (evaluateKingChase(position, WHITE))
{
const int kingChaseMalus = getKingChaseMalus(position, WHITE);
base->balance -= V(kingChaseMalus, kingChaseMalus);
}
else if (evaluateKingChase(position, BLACK))
{
const int kingChaseMalus = getKingChaseMalus(position, BLACK);
base->balance += V(kingChaseMalus, kingChaseMalus);
}
#ifndef NDEBUG
if (debugEval)
{
logDebug("\nEval values before space attack eval:\n");
logDebug("op=%d eg=%d\n", getOpeningValue(base->balance),
getEndgameValue(base->balance));
}
#endif
#ifdef BONUS_SPACE_ATTACKS
{
const Bitboard whiteAttackers = position->piecesOfColor[WHITE] &
attackingRealm[WHITE];
const Bitboard blackAttackers = position->piecesOfColor[BLACK] &
attackingRealm[BLACK];
const int numWhiteAttackers = getNumberOfSetSquares(whiteAttackers);
const int numBlackAttackers = getNumberOfSetSquares(blackAttackers);
const int bonus =
SPACE_BONUS_WEIGHT[numWhiteAttackers] *
(base->spaceAttackPoints[WHITE] + numWhiteAttackers) -
SPACE_BONUS_WEIGHT[numBlackAttackers] *
(base->spaceAttackPoints[BLACK] + numBlackAttackers);
base->balance += V(bonus, 0);
}
#endif
#ifdef MALUS_KING_TRAPPED
if (whiteKingIsTrapped(position, base))
{
base->balance -= KING_MALUS_TRAPPED;
}
if (blackKingIsTrapped(position, base))
{
base->balance += KING_MALUS_TRAPPED;
}
#endif
#ifdef HOMELAND_SECURITY_BONUS
{
const int weight = getHomeSecurityWeight(position);
if (weight > 0)
{
const int countWhite =
getHomelandSecurityCount(position, base, WHITE);
const int countBlack =
getHomelandSecurityCount(position, base, BLACK);
base->balance += V(((countWhite - countBlack) * weight) / 4, 0);
}
}
#endif
evaluateWhiteAttackers(base);
evaluateBlackAttackers(base);
#ifdef BONUS_PINS
evaluateWhitePins(position, base);
evaluateBlackPins(position, base);
#endif
#ifndef NDEBUG
if (debugEval)
{
logDebug("\nFinal eval values:\n");
logDebug("op=%d eg=%d\n", getOpeningValue(base->balance),
getEndgameValue(base->balance));
}
#endif
}
int getValue(const Position * position,
EvaluationBase * base,
PawnHashInfo * pawnHashtable,
KingSafetyHashInfo * kingsafetyHashtable)
{
PawnHashInfo *pawnHashInfo =
&pawnHashtable[position->pawnHashValue & PAWN_HASHTABLE_MASK];
initializeEvaluationBase(base, kingsafetyHashtable);
if (pawnHashInfo->hashValue == position->pawnHashValue &&
pawnHashInfo->hashValue != 0)
{
#ifndef NDEBUG
getPawnInfo(position, base);
evaluatePawns(position, base);
assert(base->balance == pawnHashInfo->balance);
assert(base->pawnProtectedSquares[WHITE] ==
pawnHashInfo->pawnProtectedSquares[WHITE]);
assert(base->pawnProtectedSquares[BLACK] ==
pawnHashInfo->pawnProtectedSquares[BLACK]);
assert(base->passedPawns[WHITE] == pawnHashInfo->passedPawns[WHITE]);
assert(base->passedPawns[BLACK] == pawnHashInfo->passedPawns[BLACK]);
#endif
base->balance = pawnHashInfo->balance;
base->passedPawns[WHITE] = pawnHashInfo->passedPawns[WHITE];
base->passedPawns[BLACK] = pawnHashInfo->passedPawns[BLACK];
base->pawnProtectedSquares[WHITE] =
pawnHashInfo->pawnProtectedSquares[WHITE];
base->pawnProtectedSquares[BLACK] =
pawnHashInfo->pawnProtectedSquares[BLACK];
base->weakOutpostSquares[WHITE] =
pawnHashInfo->weakOutpostSquares[WHITE];
base->weakOutpostSquares[BLACK] =
pawnHashInfo->weakOutpostSquares[BLACK];
base->pawnAttackableSquares[WHITE] =
pawnHashInfo->pawnAttackableSquares[WHITE];
base->pawnAttackableSquares[BLACK] =
pawnHashInfo->pawnAttackableSquares[BLACK];
base->pawnLightSquareMalus[WHITE] =
pawnHashInfo->pawnLightSquareMalus[WHITE];
base->pawnLightSquareMalus[BLACK] =
pawnHashInfo->pawnLightSquareMalus[BLACK];
base->pawnDarkSquareMalus[WHITE] =
pawnHashInfo->pawnDarkSquareMalus[WHITE];
base->pawnDarkSquareMalus[BLACK] =
pawnHashInfo->pawnDarkSquareMalus[BLACK];
#ifdef BONUS_HIDDEN_PASSER
base->hasPassersOrCandidates[WHITE] =
pawnHashInfo->hasPassersOrCandidates[WHITE];
base->hasPassersOrCandidates[BLACK] =
pawnHashInfo->hasPassersOrCandidates[BLACK];
#endif
}
else
{
getPawnInfo(position, base);
evaluatePawns(position, base);
pawnHashInfo->hashValue = position->pawnHashValue;
pawnHashInfo->balance = base->balance;
pawnHashInfo->pawnProtectedSquares[WHITE] =
base->pawnProtectedSquares[WHITE];
pawnHashInfo->pawnProtectedSquares[BLACK] =
base->pawnProtectedSquares[BLACK];
pawnHashInfo->passedPawns[WHITE] = base->passedPawns[WHITE];
pawnHashInfo->passedPawns[BLACK] = base->passedPawns[BLACK];
pawnHashInfo->weakOutpostSquares[WHITE] =
base->weakOutpostSquares[WHITE];
pawnHashInfo->weakOutpostSquares[BLACK] =
base->weakOutpostSquares[BLACK];
pawnHashInfo->pawnAttackableSquares[WHITE] =
base->pawnAttackableSquares[WHITE];
pawnHashInfo->pawnAttackableSquares[BLACK] =
base->pawnAttackableSquares[BLACK];
pawnHashInfo->pawnLightSquareMalus[WHITE] =
base->pawnLightSquareMalus[WHITE];
pawnHashInfo->pawnLightSquareMalus[BLACK] =
base->pawnLightSquareMalus[BLACK];
pawnHashInfo->pawnDarkSquareMalus[WHITE] =
base->pawnDarkSquareMalus[WHITE];
pawnHashInfo->pawnDarkSquareMalus[BLACK] =
base->pawnDarkSquareMalus[BLACK];
#ifdef BONUS_HIDDEN_PASSER
pawnHashInfo->hasPassersOrCandidates[WHITE] =
base->hasPassersOrCandidates[WHITE];
pawnHashInfo->hasPassersOrCandidates[BLACK] =
base->hasPassersOrCandidates[BLACK];
#endif
}
#ifdef TRACE_EVAL
logDebug("\nStarting evaluation.\n");
logDebug("phaseIndex = %d\n", phaseIndex(position));
logDebug("opvWhite = %d egvWhite = %d\n",
position->openingValue[WHITE], position->endgameValue[WHITE]);
logDebug("opvBlack = %d egvBlack = %d\n",
position->openingValue[BLACK], position->endgameValue[BLACK]);
logDebug("basicValue = %d\n\n", basicValue);
logPosition(position);
logDebug("\n");
#endif
if (kpkpValueAvailable(position))
{
int currentPositionalValue = getKpkpValue(position);
if (currentPositionalValue == 0)
{
return 0;
}
getPositionalValue(position, base);
}
else
{
getPositionalValue(position, base);
}
return positionalBalance(position, base);
}
static void transposeMatrix(const int human[], int machine[])
{
int file, rank, i = 0;
for (rank = RANK_8; rank >= RANK_1; rank--)
{
for (file = FILE_A; file <= FILE_H; file++)
{
const Square machineSquare = getSquare(file, rank);
machine[machineSquare] = human[i++];
}
}
}
#define PSV(piece,square,stage) pieceSquareValue[(piece)][(square)][(stage)]
static void initializePieceSquareValues()
{
Square sq;
ITERATE(sq)
{
int ov, ev;
ov = PAWN_DEFAULTVALUE_OPENING + getOpeningValue(PstPawn[sq]);
ev = PAWN_DEFAULTVALUE_ENDGAME + getEndgameValue(PstPawn[sq]);
pieceSquareBonus[WHITE_PAWN][sq] =
pieceSquareBonus[BLACK_PAWN][getFlippedSquare(sq)] = V(ov, ev);
ov = VALUE_KNIGHT_OPENING + getOpeningValue(PstKnight[sq]);
ev = VALUE_KNIGHT_ENDGAME + getEndgameValue(PstKnight[sq]);
pieceSquareBonus[WHITE_KNIGHT][sq] =
pieceSquareBonus[BLACK_KNIGHT][getFlippedSquare(sq)] = V(ov, ev);
ov = VALUE_BISHOP_OPENING + getOpeningValue(PstBishop[sq]);
ev = VALUE_BISHOP_ENDGAME + getEndgameValue(PstBishop[sq]);
pieceSquareBonus[WHITE_BISHOP][sq] =
pieceSquareBonus[BLACK_BISHOP][getFlippedSquare(sq)] = V(ov, ev);
ov = VALUE_ROOK_OPENING + getOpeningValue(PstRook[sq]);
ev = VALUE_ROOK_ENDGAME + getEndgameValue(PstRook[sq]);
pieceSquareBonus[WHITE_ROOK][sq] =
pieceSquareBonus[BLACK_ROOK][getFlippedSquare(sq)] = V(ov, ev);
ov = VALUE_QUEEN_OPENING + getOpeningValue(PstQueen[sq]);
ev = VALUE_QUEEN_ENDGAME + getEndgameValue(PstQueen[sq]);
pieceSquareBonus[WHITE_QUEEN][sq] =
pieceSquareBonus[BLACK_QUEEN][getFlippedSquare(sq)] = V(ov, ev);
ov = getOpeningValue(PstKing[sq]);
ev = getEndgameValue(PstKing[sq]);
pieceSquareBonus[WHITE_KING][sq] =
pieceSquareBonus[BLACK_KING][getFlippedSquare(sq)] = V(ov, ev);
}
}
static void initializeKingAttacks()
{
Square square;
ITERATE(square)
{
const Bitboard corona = getKingMoves(square);
KingAttacks *attackInfo = &kingAttacks[square];
Square attackerSquare;
attackInfo->diaAttackers = attackInfo->orthoAttackers =
attackInfo->knightAttackers = attackInfo->pawnAttackers[WHITE] =
attackInfo->pawnAttackers[WHITE] = EMPTY_BITBOARD;
ITERATE(attackerSquare)
{
attackInfo->attackedByDia[attackerSquare] =
attackInfo->attackedByOrtho[attackerSquare] = NO_SQUARE;
}
ITERATE(attackerSquare)
{
Bitboard dia, ortho;
const Bitboard knight =
corona & generalMoves[WHITE_KNIGHT][attackerSquare];
const Bitboard whitePawn =
corona & generalMoves[WHITE_PAWN][attackerSquare];
const Bitboard blackPawn =
corona & generalMoves[BLACK_PAWN][attackerSquare];
dia = corona & generalMoves[WHITE_BISHOP][attackerSquare];
ortho = corona & generalMoves[WHITE_ROOK][attackerSquare];
if (dia != EMPTY_BITBOARD)
{
Square attackedSquare;
int dist = 8;
setSquare(attackInfo->diaAttackers, attackerSquare);
ITERATE_BITBOARD(&dia, attackedSquare)
{
const int currentDistance =
distance(attackerSquare, attackedSquare);
if (currentDistance < dist)
{
attackInfo->attackedByDia[attackerSquare] = attackedSquare;
dist = currentDistance;
}
}
}
if (ortho != EMPTY_BITBOARD)
{
Square attackedSquare;
int dist = 8;
setSquare(attackInfo->orthoAttackers, attackerSquare);
ITERATE_BITBOARD(&ortho, attackedSquare)
{
const int currentDistance =
distance(attackerSquare, attackedSquare);
if (currentDistance < dist)
{
attackInfo->attackedByOrtho[attackerSquare] =
attackedSquare;
dist = currentDistance;
}
}
}
if (knight != EMPTY_BITBOARD)
{
setSquare(attackInfo->knightAttackers, attackerSquare);
}
if (whitePawn != EMPTY_BITBOARD)
{
setSquare(attackInfo->pawnAttackers[WHITE], attackerSquare);
}
if (blackPawn != EMPTY_BITBOARD)
{
setSquare(attackInfo->pawnAttackers[BLACK], attackerSquare);
}
}
}
}
#define AVOID_TRADES_WITH_TWO_KNIGHTS /* */
static void getPieceTradeSignatures(UINT32 * materialSignatureWhite,
UINT32 * materialSignatureBlack)
{
int numWhiteQueens, numWhiteRooks, numWhiteLightSquareBishops;
int numWhiteDarkSquareBishops, numWhiteKnights, numWhitePawns;
int numBlackQueens, numBlackRooks, numBlackLightSquareBishops;
int numBlackDarkSquareBishops, numBlackKnights, numBlackPawns;
bool finished = TRUE;
bool whiteKnightTradesOnly = FALSE, blackKnightTradesOnly = FALSE;
bool knightTradesOnly = FALSE;
#ifdef AVOID_TRADES_WITH_TWO_KNIGHTS
int numWhiteNonPawns, numBlackNonPawns;
#endif
getPieceCounters(*materialSignatureWhite, &numWhiteQueens, &numWhiteRooks,
&numWhiteLightSquareBishops, &numWhiteDarkSquareBishops,
&numWhiteKnights, &numWhitePawns);
getPieceCounters(*materialSignatureBlack, &numBlackQueens, &numBlackRooks,
&numBlackLightSquareBishops, &numBlackDarkSquareBishops,
&numBlackKnights, &numBlackPawns);
#ifdef AVOID_TRADES_WITH_TWO_KNIGHTS
numWhiteNonPawns =
numWhiteQueens + numWhiteRooks + numWhiteLightSquareBishops +
numWhiteDarkSquareBishops + numWhiteKnights;
numBlackNonPawns =
numBlackQueens + numBlackRooks + numBlackLightSquareBishops +
numBlackDarkSquareBishops + numBlackKnights;
if (numWhitePawns + numBlackPawns == 0 && numWhiteKnights == 2 &&
numWhiteNonPawns == 3 && numWhiteNonPawns - numBlackNonPawns >= 2)
{
whiteKnightTradesOnly = TRUE; /* white will avoid to trade pieces */
}
if (numBlackPawns + numWhitePawns == 0 && numBlackKnights == 2 &&
numBlackNonPawns == 3 && numBlackNonPawns - numWhiteNonPawns >= 2)
{
blackKnightTradesOnly = TRUE; /* black will avoid to trade pieces */
}
knightTradesOnly = whiteKnightTradesOnly || blackKnightTradesOnly;
#endif
if (knightTradesOnly == FALSE && numWhiteQueens > 0 && numBlackQueens > 0)
{
numWhiteQueens--;
numBlackQueens--;
finished = FALSE;
goto calculateSignature;
}
if (knightTradesOnly == FALSE && numWhiteRooks > 0 && numBlackRooks > 0)
{
numWhiteRooks--;
numBlackRooks--;
finished = FALSE;
goto calculateSignature;
}
if (knightTradesOnly == FALSE &&
numWhiteLightSquareBishops > 0 && numBlackLightSquareBishops > 0)
{
numWhiteLightSquareBishops--;
numBlackLightSquareBishops--;
finished = FALSE;
goto calculateSignature;
}
if (knightTradesOnly == FALSE &&
numWhiteDarkSquareBishops > 0 && numBlackDarkSquareBishops > 0)
{
numWhiteDarkSquareBishops--;
numBlackDarkSquareBishops--;
finished = FALSE;
goto calculateSignature;
}
if (knightTradesOnly == FALSE &&
numWhiteLightSquareBishops > 0 && numBlackDarkSquareBishops > 0)
{
numWhiteLightSquareBishops--;
numBlackDarkSquareBishops--;
finished = FALSE;
goto calculateSignature;
}
if (knightTradesOnly == FALSE &&
numWhiteDarkSquareBishops > 0 && numBlackLightSquareBishops > 0)
{
numWhiteDarkSquareBishops--;
numBlackLightSquareBishops--;
finished = FALSE;
goto calculateSignature;
}
if (numWhiteKnights > 0 && numBlackKnights > 0)
{
numWhiteKnights--;
numBlackKnights--;
finished = FALSE;
goto calculateSignature;
}
if (whiteKnightTradesOnly == FALSE &&
numWhiteLightSquareBishops > 0 && numBlackKnights > 0 &&
numWhiteDarkSquareBishops == 0)
{
numWhiteLightSquareBishops--;
numBlackKnights--;
finished = FALSE;
goto calculateSignature;
}
if (whiteKnightTradesOnly == FALSE &&
numWhiteDarkSquareBishops > 0 && numBlackKnights > 0 &&
numWhiteLightSquareBishops == 0)
{
numWhiteDarkSquareBishops--;
numBlackKnights--;
finished = FALSE;
goto calculateSignature;
}
if (blackKnightTradesOnly == FALSE &&
numWhiteKnights > 0 && numBlackLightSquareBishops > 0 &&
numBlackDarkSquareBishops == 0)
{
numWhiteKnights--;
numBlackLightSquareBishops--;
finished = FALSE;
goto calculateSignature;
}
if (blackKnightTradesOnly == FALSE &&
numWhiteKnights > 0 && numBlackDarkSquareBishops > 0 &&
numBlackLightSquareBishops == 0)
{
numWhiteKnights--;
numBlackDarkSquareBishops--;
finished = FALSE;
goto calculateSignature;
}
calculateSignature:
*materialSignatureWhite =
materialSignature(numWhiteQueens, numWhiteRooks,
numWhiteLightSquareBishops, numWhiteDarkSquareBishops,
numWhiteKnights, numWhitePawns);
*materialSignatureBlack =
materialSignature(numBlackQueens, numBlackRooks,
numBlackLightSquareBishops, numBlackDarkSquareBishops,
numBlackKnights, numBlackPawns);
if (finished == FALSE)
{
getPieceTradeSignatures(materialSignatureWhite, materialSignatureBlack);
}
}
static bool hasMaterialForMate(const UINT32 materialSignature,
const UINT32 oppMaterialSignature,
SpecialEvalType * specialEval,
const bool tradePieces)
{
int numQueens, numRooks, numLightSquareBishops, numDarkSquareBishops;
int numKnights, numPawns;
int numOppQueens, numOppRooks, numOppLightSquareBishops;
int numOppDarkSquareBishops, numOppKnights, numOppPawns;
int numBishops, numOppBishops;
if (tradePieces)
{
UINT32 ms = materialSignature, mso = oppMaterialSignature;
SpecialEvalType dummy;
getPieceTradeSignatures(&ms, &mso);
return hasMaterialForMate(ms, mso, &dummy, FALSE);
}
getPieceCounters(materialSignature, &numQueens, &numRooks,
&numLightSquareBishops, &numDarkSquareBishops,
&numKnights, &numPawns);
getPieceCounters(oppMaterialSignature, &numOppQueens, &numOppRooks,
&numOppLightSquareBishops, &numOppDarkSquareBishops,
&numOppKnights, &numOppPawns);
numBishops = numLightSquareBishops + numDarkSquareBishops;
numOppBishops = numOppLightSquareBishops + numOppDarkSquareBishops;
if (numQueens + numRooks + numLightSquareBishops + numDarkSquareBishops +
numKnights == 0 && numPawns > 0)
{
*specialEval = Se_KpK;
return TRUE;
}
if (numQueens + numRooks + numLightSquareBishops + numDarkSquareBishops +
numPawns == 0 && numKnights == 2)
{
if (numOppQueens + numOppRooks + numOppLightSquareBishops +
numOppDarkSquareBishops + numOppKnights == 0 && numOppPawns > 0)
{
*specialEval = Se_KnnKp;
return TRUE;
}
}
if (numQueens + numRooks + numKnights == 0 &&
numLightSquareBishops + numDarkSquareBishops == 1 && numPawns > 0)
{
*specialEval = Se_KbpK;
return TRUE;
}
if (numQueens + numBishops + numKnights == 0 && numRooks == 1 &&
numPawns == 1 && numOppBishops >= 1)
{
*specialEval = Se_KrpKb;
return TRUE;
}
if (numQueens + numBishops + numKnights == 0 && numRooks == 1 &&
numPawns == 1 && numOppRooks >= 1)
{
*specialEval = Se_KrpKr;
return TRUE;
}
if (numQueens + numBishops + numKnights == 0 && numRooks == 1 &&
numPawns == 2 && numOppRooks >= 1)
{
*specialEval = Se_KrppKr;
return TRUE;
}
if (numRooks + numBishops + numKnights == 0 && numQueens == 1 &&
numPawns == 1 && numOppQueens >= 1)
{
*specialEval = Se_KqpKq;
return TRUE;
}
if (numRooks + numBishops + numKnights == 0 && numQueens == 1 &&
numPawns == 2 && numOppQueens >= 1)
{
*specialEval = Se_KqppKq;
return TRUE;
}
if (numQueens + numRooks + numPawns > 0 || numKnights >= 3)
{
return TRUE;
}
if (numLightSquareBishops > 0 && numDarkSquareBishops > 0)
{
return TRUE;
}
if (numKnights > 0 && numLightSquareBishops + numDarkSquareBishops > 0)
{
return TRUE;
}
return FALSE;
}
static PieceType getKamikazePiece(const UINT32 ownMaterialSignature,
const UINT32 oppMaterialSignature)
{
int numQueens, numRooks, numLightSquareBishops;
int numDarkSquareBishops, numKnights, numPawns;
int numOppQueens, numOppRooks, numOppLightSquareBishops;
int numOppDarkSquareBishops, numOppKnights, numOppPawns;
int ownSignature;
getPieceCounters(ownMaterialSignature, &numQueens, &numRooks,
&numLightSquareBishops, &numDarkSquareBishops,
&numKnights, &numPawns);
getPieceCounters(oppMaterialSignature, &numOppQueens, &numOppRooks,
&numOppLightSquareBishops, &numOppDarkSquareBishops,
&numOppKnights, &numOppPawns);
ownSignature =
materialSignature(numQueens, numRooks,
numLightSquareBishops,
numDarkSquareBishops, numKnights, numPawns - 1);
if (numOppRooks > 0)
{
const int oppSignature =
materialSignature(numOppQueens, numOppRooks - 1,
numOppLightSquareBishops,
numOppDarkSquareBishops,
numOppKnights, numOppPawns);
if (hasMaterialForMate(ownSignature, oppSignature, 0, TRUE) == FALSE)
{
return ROOK;
}
}
if (numOppLightSquareBishops > 0)
{
const int oppSignature = materialSignature(numOppQueens, numOppRooks,
numOppLightSquareBishops - 1,
numOppDarkSquareBishops,
numOppKnights, numOppPawns);
if (hasMaterialForMate(ownSignature, oppSignature, 0, TRUE) == FALSE)
{
return BISHOP;
}
}
if (numOppDarkSquareBishops > 0)
{
const int oppSignature = materialSignature(numOppQueens, numOppRooks,
numOppLightSquareBishops,
numOppDarkSquareBishops - 1,
numOppKnights, numOppPawns);
if (hasMaterialForMate(ownSignature, oppSignature, 0, TRUE) == FALSE)
{
return BISHOP;
}
}
if (numOppKnights > 0)
{
const int oppSignature = materialSignature(numOppQueens, numOppRooks,
numOppLightSquareBishops,
numOppDarkSquareBishops,
numOppKnights - 1,
numOppPawns);
if (hasMaterialForMate(ownSignature, oppSignature, 0, TRUE) == FALSE)
{
return KNIGHT;
}
}
return NO_PIECETYPE;
}
static UINT8 getWinningChances(const UINT32 materialSignature,
const UINT32 oppMaterialSignature)
{
int numQueens, numRooks, numLightSquareBishops;
int numDarkSquareBishops, numKnights, numPawns;
int numOppQueens, numOppRooks, numOppLightSquareBishops;
int numOppDarkSquareBishops, numOppKnights, numOppPawns;
int numPieces, numOppPieces;
int numOppBishops, numOppMinors, numOppSliders;
bool oppositeColoredBishops;
PieceType kamikazePiece = getKamikazePiece(materialSignature,
oppMaterialSignature);
getPieceCounters(materialSignature, &numQueens, &numRooks,
&numLightSquareBishops, &numDarkSquareBishops,
&numKnights, &numPawns);
getPieceCounters(oppMaterialSignature, &numOppQueens, &numOppRooks,
&numOppLightSquareBishops, &numOppDarkSquareBishops,
&numOppKnights, &numOppPawns);
numPieces = numQueens + numRooks + numLightSquareBishops +
numDarkSquareBishops + numKnights;
numOppBishops = numOppLightSquareBishops + numOppDarkSquareBishops;
numOppMinors = numOppBishops + numOppKnights;
numOppSliders = numOppQueens + numOppRooks + numOppBishops;
numOppPieces = numOppSliders + numOppKnights;
oppositeColoredBishops = (bool)
(numLightSquareBishops + numDarkSquareBishops > 0 &&
((numOppLightSquareBishops > 0 && numLightSquareBishops == 0) ||
(numOppDarkSquareBishops > 0 && numDarkSquareBishops == 0)));
if (numPieces == 0)
{
if (numPawns <= 1 && numOppSliders > 0)
{
return 0;
}
if (numPawns <= 1 && numOppKnights > 0)
{
return 4;
}
if (numPawns == 2)
{
return (numOppSliders >= 2 ? 2 : 8);
}
}
if (numPieces == 1)
{
if (oppositeColoredBishops)
{
return (numPawns > 1 ? 8 : 0);
}
if (numPawns == 1) /* One piece, one pawn: */
{
if (numQueens > 0 && numOppRooks >= 2)
{
return 1;
}
if (numQueens > 0 && numOppRooks + numOppMinors >= 2)
{
return 12; /* usually won, but difficult */
}
if (kamikazePiece != NO_PIECETYPE)
{
switch (kamikazePiece)
{
case ROOK:
return 1;
case BISHOP:
return 2;
case KNIGHT:
return 4;
default:
break;
}
}
}
}
else if (numPieces == 2) /* has more than one piece: */
{
if (numPawns <= 1)
{
if (numRooks == 2 && numOppQueens > 0)
{
return (numPawns == 0 ? 1 : 2);
}
if (kamikazePiece != NO_PIECETYPE)
{
switch (kamikazePiece)
{
case ROOK:
return 1;
case BISHOP:
return 2;
case KNIGHT:
return 4;
default:
break;
}
}
}
if (numQueens == 0 && numRooks <= 1 && numRooks == numOppRooks &&
oppositeColoredBishops)
{
return 12;
}
}
return 16;
}
static UINT8 getWinningChancesWithoutPawn(UINT32 materialSignature,
UINT32 oppMaterialSignature)
{
int numQueens, numRooks, numLightSquareBishops;
int numDarkSquareBishops, numKnights, numPawns;
int numOppQueens, numOppRooks, numOppLightSquareBishops;
int numOppDarkSquareBishops, numOppKnights, numOppPawns;
int numPieces, numOppPieces;
int numOppBishops, numOppMinors, numOppSliders;
bool oppositeColoredBishops;
getPieceTradeSignatures(&materialSignature, &oppMaterialSignature);
getPieceCounters(materialSignature, &numQueens, &numRooks,
&numLightSquareBishops, &numDarkSquareBishops,
&numKnights, &numPawns);
getPieceCounters(oppMaterialSignature, &numOppQueens, &numOppRooks,
&numOppLightSquareBishops, &numOppDarkSquareBishops,
&numOppKnights, &numOppPawns);
numPieces = numQueens + numRooks + numLightSquareBishops +
numDarkSquareBishops + numKnights;
numOppBishops = numOppLightSquareBishops + numOppDarkSquareBishops;
numOppMinors = numOppBishops + numOppKnights;
numOppSliders = numOppQueens + numOppRooks + numOppBishops;
numOppPieces = numOppSliders + numOppKnights;
oppositeColoredBishops = (bool)
(numLightSquareBishops + numDarkSquareBishops > 0 &&
((numOppLightSquareBishops > 0 && numLightSquareBishops == 0) ||
(numOppDarkSquareBishops > 0 && numDarkSquareBishops == 0)));
if (numPieces == 0)
{
return 0;
}
if (numPieces == 1)
{
if (numQueens > 0 && numOppRooks > 0 && numOppRooks + numOppMinors >= 2)
{
return 1;
}
if (numQueens > 0 && numOppKnights >= 2)
{
return 1;
}
if (numRooks > 0 && numOppQueens + numOppRooks > 0)
{
return 1;
}
if (numRooks > 0 && numOppMinors > 0)
{
return (numOppMinors == 1 ? 2 : 1);
}
if (numLightSquareBishops + numDarkSquareBishops + numKnights > 0)
{
return 0;
}
}
else if (numPieces <= 3)
{
if (numQueens == 0 && numOppQueens > 0)
{
if (numRooks <= 1)
{
return 1;
}
else
{
return 8; /* hard to win */
}
}
if (numRooks + numQueens == 0 &&
numLightSquareBishops + numDarkSquareBishops <= 1 &&
numOppRooks + numOppQueens >= 1)
{
return (numOppQueens >= 1 ? 1 : 2);
}
}
if (numLightSquareBishops == 1 && numDarkSquareBishops == 1)
{
if (numOppPieces == 1 && numOppRooks == 1)
{
return (numPieces == 2 ? 1 : 12);
}
if (numOppKnights > 0)
{
return 8; /* hard to win sometimes */
}
}
return 16;
}
static void initializeMaterialInfoTableCore1(const UINT32 signatureWhite,
const UINT32 signatureBlack)
{
const int index = signatureWhite + (signatureBlack << 9);
SpecialEvalType specialEvalWhite = Se_None;
SpecialEvalType specialEvalBlack = Se_None;
const bool whiteMateMat =
hasMaterialForMate(signatureWhite, signatureBlack, &specialEvalWhite,
FALSE);
const bool blackMateMat =
hasMaterialForMate(signatureBlack, signatureWhite, &specialEvalBlack,
FALSE);
int numWhiteQueens, numWhiteRooks, numWhiteLightSquareBishops;
int numWhiteDarkSquareBishops, numWhiteKnights, numWhitePawns;
int numBlackQueens, numBlackRooks, numBlackLightSquareBishops;
int numBlackDarkSquareBishops, numBlackKnights, numBlackPawns;
int numWhitePieces, numBlackPieces;
getPieceCounters(signatureWhite, &numWhiteQueens, &numWhiteRooks,
&numWhiteLightSquareBishops, &numWhiteDarkSquareBishops,
&numWhiteKnights, &numWhitePawns);
getPieceCounters(signatureBlack, &numBlackQueens, &numBlackRooks,
&numBlackLightSquareBishops, &numBlackDarkSquareBishops,
&numBlackKnights, &numBlackPawns);
numWhitePieces =
numWhiteQueens + numWhiteRooks + numWhiteLightSquareBishops +
numWhiteDarkSquareBishops + numWhiteKnights;
numBlackPieces =
numBlackQueens + numBlackRooks + numBlackLightSquareBishops +
numBlackDarkSquareBishops + numBlackKnights;
materialInfo[index].chancesWhite = (whiteMateMat == FALSE ? 0 : 16);
materialInfo[index].chancesBlack = (blackMateMat == FALSE ? 0 : 16);
materialInfo[index].specialEvalWhite = specialEvalWhite;
materialInfo[index].specialEvalBlack = specialEvalBlack;
if (whiteMateMat != FALSE)
{
if (numWhitePawns == 0)
{
if (hasMaterialForMate(signatureWhite, signatureBlack, 0, TRUE) ==
FALSE)
{
materialInfo[index].chancesWhite = 1;
}
else
{
materialInfo[index].chancesWhite =
getWinningChancesWithoutPawn(signatureWhite, signatureBlack);
}
}
else
{
materialInfo[index].chancesWhite =
getWinningChances(signatureWhite, signatureBlack);
}
}
if (blackMateMat != FALSE)
{
if (numBlackPawns == 0)
{
if (hasMaterialForMate(signatureBlack, signatureWhite, 0, TRUE) ==
FALSE)
{
materialInfo[index].chancesBlack = 1;
}
else
{
materialInfo[index].chancesBlack =
getWinningChancesWithoutPawn(signatureBlack, signatureWhite);
}
}
else
{
materialInfo[index].chancesBlack =
getWinningChances(signatureBlack, signatureWhite);
}
}
}
static void initializeMaterialInfoTable(const UINT32 signatureWhite,
const UINT32 signatureBlack,
int stage)
{
int numQueens, numRooks, numLightSquareBishops, numDarkSquareBishops;
int numKnights, numPawns;
if (stage < 2)
{
for (numQueens = 0; numQueens <= 1; numQueens++)
{
for (numRooks = 0; numRooks <= 3; numRooks++)
{
for (numLightSquareBishops = 0; numLightSquareBishops <= 1;
numLightSquareBishops++)
{
for (numDarkSquareBishops = 0; numDarkSquareBishops <= 1;
numDarkSquareBishops++)
{
for (numKnights = 0; numKnights <= 3; numKnights++)
{
for (numPawns = 0; numPawns <= 3; numPawns++)
{
UINT32 signature =
materialSignature(numQueens, numRooks,
numLightSquareBishops,
numDarkSquareBishops,
numKnights,
numPawns);
if (stage == 0)
{
initializeMaterialInfoTable(signature, 0, 1);
}
else
{
initializeMaterialInfoTable(signatureWhite,
signature, 2);
}
}
}
}
}
}
}
}
else
{
initializeMaterialInfoTableCore1(signatureWhite, signatureBlack);
}
}
static int initializeKingSafetyTable()
{
const int MAX_MALUS = 500;
const int MAX_STEP = 12;
int i;
#ifdef TEST_SETUP
const int factor = 12;
#else
const int factor = 12;
#endif
for (i = 0; i < KING_SAFETY_MALUS_DIM; i++)
{
KING_SAFETY_MALUS[i] = factor * (i * i) / 100;
if (i > 0 && KING_SAFETY_MALUS[i] - KING_SAFETY_MALUS[i - 1] > MAX_STEP)
{
KING_SAFETY_MALUS[i] = KING_SAFETY_MALUS[i - 1] + MAX_STEP;
}
KING_SAFETY_MALUS[i] = min(KING_SAFETY_MALUS[i], MAX_MALUS);
}
return 0;
}
static int opSw(const int value)
{
return (value * 100) / 100;
}
static int egSw(const int value)
{
return (value * 100) / 100;
}
#ifdef HIGH_ATTACK_BONUS
static int opAw(const int value)
{
return (value * 100) / 256;
}
static int egAw(const int value)
{
return (value * 100) / 256;
}
#else
static int opAw(const int value)
{
return (value * 125) / 100;
}
static int egAw(const int value)
{
return (value * 125) / 100;
}
#endif
int initializeModuleEvaluation()
{
int i;
Square square, kingsquare, catchersquare;
centralFiles = squaresOfFile[FILE_D] | squaresOfFile[FILE_E];
attackingRealm[WHITE] = squaresOfRank[RANK_5] | squaresOfRank[RANK_6] |
squaresOfRank[RANK_7] | squaresOfRank[RANK_8];
attackingRealm[BLACK] = squaresOfRank[RANK_4] | squaresOfRank[RANK_3] |
squaresOfRank[RANK_2] | squaresOfRank[RANK_1];
filesBCFG = squaresOfFileRange[FILE_B][FILE_C] |
squaresOfFileRange[FILE_F][FILE_G];
rookTraps[WHITE] = rookTraps[BLACK] = EMPTY_BITBOARD;
setSquare(rookTraps[WHITE], A1);
setSquare(rookTraps[WHITE], B1);
setSquare(rookTraps[WHITE], C1);
setSquare(rookTraps[WHITE], A2);
setSquare(rookTraps[WHITE], B2);
setSquare(rookTraps[WHITE], F1);
setSquare(rookTraps[WHITE], G1);
setSquare(rookTraps[WHITE], H1);
setSquare(rookTraps[WHITE], G2);
setSquare(rookTraps[WHITE], H2);
ITERATE(square)
{
Color color;
Square kingSquare;
for (color = WHITE; color <= BLACK; color++)
{
passedPawnRectangle[color][square] =
passedPawnCorridor[color][square] =
candidateDefenders[color][square] =
candidateSupporters[color][square] =
pawnOpponents[color][square] = EMPTY_BITBOARD;
}
if (testSquare(rookTraps[WHITE], square))
{
setSquare(rookTraps[BLACK], getFlippedSquare(square));
}
ITERATE(kingSquare)
{
kingRealm[WHITE][square][kingSquare] =
kingRealm[BLACK][square][kingSquare] = EMPTY_BITBOARD;
}
}
ITERATE(square)
{
const int squarefile = file(square);
const int squarerank = rank(square);
int d1 = min(distance(square, D4), distance(square, E4));
int d2 = min(distance(square, D5), distance(square, E5));
int td1 = min(taxiDistance(square, D4), taxiDistance(square, E4));
int td2 = min(taxiDistance(square, D5), taxiDistance(square, E5));
centerDistance[square] = min(d1, d2);
centerTaxiDistance[square] = min(td1, td2);
butterflySquares[square] =
generalMoves[KING][square] & ~squaresOfFile[squarefile];
lateralSquares[square] =
generalMoves[KING][square] & squaresOfRank[squarerank];
companionFiles[square] =
((squaresOfFile[squarefile] & nonA) >> 1) |
((squaresOfFile[squarefile] & nonH) << 1);
rookBlockers[square] = EMPTY_BITBOARD;
ITERATE(kingsquare)
{
const int kingsquarefile = file(kingsquare);
const int kingsquarerank = rank(kingsquare);
Square targetSquare;
if (kingsquarerank >= squarerank &&
distance(square, kingsquare) <= 7 - squarerank)
{
setSquare(passedPawnRectangle[WHITE][square], kingsquare);
}
if (kingsquarerank <= squarerank &&
distance(square, kingsquare) <= squarerank)
{
setSquare(passedPawnRectangle[BLACK][square], kingsquare);
}
if (kingsquarefile == squarefile)
{
if (kingsquarerank > squarerank)
{
setSquare(passedPawnCorridor[WHITE][square], kingsquare);
}
if (kingsquarerank < squarerank)
{
setSquare(passedPawnCorridor[BLACK][square], kingsquare);
}
}
if (squarerank == kingsquarerank)
{
if (squarefile <= FILE_C && kingsquarefile <= FILE_C &&
kingsquarefile > squarefile)
{
setSquare(rookBlockers[square], kingsquare);
}
if (squarefile >= FILE_F && kingsquarefile >= FILE_F &&
kingsquarefile < squarefile)
{
setSquare(rookBlockers[square], kingsquare);
}
}
ITERATE(targetSquare)
{
if (distance(square, targetSquare) <
distance(kingsquare, targetSquare))
{
const Rank targetrank = rank(targetSquare);
if (targetrank <= squarerank + 1)
{
setSquare(kingRealm[WHITE][square][kingsquare],
targetSquare);
}
if (targetrank >= squarerank - 1)
{
setSquare(kingRealm[BLACK][square][kingsquare],
targetSquare);
}
}
}
}
ITERATE(catchersquare)
{
if (abs(file(catchersquare) - squarefile) == 1)
{
if (rank(catchersquare) > squarerank)
{
setSquare(candidateDefenders[WHITE][square], catchersquare);
}
if (rank(catchersquare) <= squarerank)
{
setSquare(candidateSupporters[WHITE][square], catchersquare);
}
if (rank(catchersquare) < squarerank)
{
setSquare(candidateDefenders[BLACK][square], catchersquare);
}
if (rank(catchersquare) >= squarerank)
{
setSquare(candidateSupporters[BLACK][square], catchersquare);
}
}
if (abs(file(catchersquare) - squarefile) <= 1)
{
if (rank(catchersquare) >= squarerank)
{
setSquare(pawnOpponents[WHITE][square], catchersquare);
}
if (rank(catchersquare) <= squarerank)
{
setSquare(pawnOpponents[BLACK][square], catchersquare);
}
}
}
}
ITERATE(square)
{
const int squarerank = rank(square);
ITERATE(kingsquare)
{
if (squarerank >= RANK_2 && squarerank <= RANK_7)
{
passedPawnDefenderMalus[WHITE][WHITE][square][kingsquare] =
getPassedPawnDefenderMalus(WHITE, WHITE, square, kingsquare);
passedPawnDefenderMalus[WHITE][BLACK][square][kingsquare] =
getPassedPawnDefenderMalus(WHITE, BLACK, square, kingsquare);
passedPawnDefenderMalus[BLACK][WHITE][square][kingsquare] =
getPassedPawnDefenderMalus(BLACK, WHITE, square, kingsquare);
passedPawnDefenderMalus[BLACK][BLACK][square][kingsquare] =
getPassedPawnDefenderMalus(BLACK, BLACK, square, kingsquare);
}
else
{
passedPawnDefenderMalus[WHITE][WHITE][square][kingsquare] =
passedPawnDefenderMalus[WHITE][BLACK][square][kingsquare] =
passedPawnDefenderMalus[BLACK][WHITE][square][kingsquare] =
passedPawnDefenderMalus[BLACK][BLACK][square][kingsquare] = 0;
}
}
}
ITERATE(square)
{
const int dDark =
min(taxiDistance(square, A1), taxiDistance(square, H8));
const int dLight =
min(taxiDistance(square, A8), taxiDistance(square, H1));
const int dStandard = centerDistance[square];
kingChaseMalus[DARK][square] = 3 * (7 - dDark) + dStandard;
kingChaseMalus[LIGHT][square] = 3 * (7 - dLight) + dStandard;
kingChaseMalus[ALL][square] = 6 - min(dDark, dLight) +
centerDistance[square];
}
/*
dumpBoardValues(kingChaseMalus[DARK]);
dumpBoardValues(kingChaseMalus[LIGHT]);
dumpBoardValues(kingChaseMalus[ALL]);
getKeyStroke();
*/
initializePieceSquareValues();
initializeKingAttacks();
initializeKingSafetyTable();
attackPoints[WHITE_KING] = 0;
attackPoints[WHITE_QUEEN] = QUEEN_BONUS_ATTACK;
attackPoints[WHITE_ROOK] = ROOK_BONUS_ATTACK;
attackPoints[WHITE_BISHOP] = BISHOP_BONUS_ATTACK;
attackPoints[WHITE_KNIGHT] = KNIGHT_BONUS_ATTACK;
attackPoints[WHITE_PAWN] = 0;
attackPoints[BLACK_KING] = 0;
attackPoints[BLACK_QUEEN] = QUEEN_BONUS_ATTACK;
attackPoints[BLACK_ROOK] = ROOK_BONUS_ATTACK;
attackPoints[BLACK_BISHOP] = BISHOP_BONUS_ATTACK;
attackPoints[BLACK_KNIGHT] = KNIGHT_BONUS_ATTACK;
attackPoints[BLACK_PAWN] = 0;
weakOutpostSquareCandidates[WHITE] = weakOutpostSquareCandidates[BLACK] =
EMPTY_BITBOARD;
setSquare(weakOutpostSquareCandidates[WHITE], C4);
setSquare(weakOutpostSquareCandidates[WHITE], D4);
setSquare(weakOutpostSquareCandidates[WHITE], E4);
setSquare(weakOutpostSquareCandidates[WHITE], F4);
setSquare(weakOutpostSquareCandidates[WHITE], C3);
setSquare(weakOutpostSquareCandidates[WHITE], D3);
setSquare(weakOutpostSquareCandidates[WHITE], E3);
setSquare(weakOutpostSquareCandidates[WHITE], F3);
setSquare(weakOutpostSquareCandidates[BLACK], C5);
setSquare(weakOutpostSquareCandidates[BLACK], D5);
setSquare(weakOutpostSquareCandidates[BLACK], E5);
setSquare(weakOutpostSquareCandidates[BLACK], F5);
setSquare(weakOutpostSquareCandidates[BLACK], C6);
setSquare(weakOutpostSquareCandidates[BLACK], D6);
setSquare(weakOutpostSquareCandidates[BLACK], E6);
setSquare(weakOutpostSquareCandidates[BLACK], F6);
homeland[WHITE] = ( /* squaresOfRank[RANK_1] | */ squaresOfRank[RANK_2] |
squaresOfRank[RANK_3] | squaresOfRank[RANK_4]) &
(squaresOfFile[FILE_C] | squaresOfFile[FILE_D] |
squaresOfFile[FILE_E] | squaresOfFile[FILE_F]);
/*
homeland[WHITE] |= (squaresOfRank[RANK_1] |
squaresOfRank[RANK_2] | squaresOfRank[RANK_3]) &
(squaresOfFile[FILE_A] | squaresOfFile[FILE_B] |
squaresOfFile[FILE_G] | squaresOfFile[FILE_H]);
*/
homeland[BLACK] = getFlippedBitboard(homeland[WHITE]);
#ifdef GENERATE_TABLES
generateKpkpTable();
#endif
for (i = 0; i < 16; i++)
{
int j;
for (j = 0; j < 16; j++)
{
sliderAttackPoints[i][j] = 0;
piecePieceAttackBonus[i][j] = 0;
}
}
sliderAttackPoints[WHITE_BISHOP][WHITE_PAWN] = V(opSw(3), egSw(5));
sliderAttackPoints[WHITE_BISHOP][WHITE_KNIGHT] = V(opSw(3), egSw(5));
sliderAttackPoints[WHITE_BISHOP][WHITE_ROOK] = V(opSw(3), egSw(5));
sliderAttackPoints[WHITE_BISHOP][WHITE_KING] = V(opSw(3), egSw(5));
sliderAttackPoints[WHITE_BISHOP][BLACK_PAWN] = V(opSw(2), egSw(5));
sliderAttackPoints[WHITE_BISHOP][BLACK_KNIGHT] = V(opSw(2), egSw(5));
sliderAttackPoints[WHITE_BISHOP][BLACK_ROOK] = V(opSw(15), egSw(25));
sliderAttackPoints[WHITE_BISHOP][BLACK_QUEEN] = V(opSw(10), egSw(20));
sliderAttackPoints[WHITE_ROOK][WHITE_KNIGHT] = V(opSw(3), egSw(5));
sliderAttackPoints[WHITE_ROOK][WHITE_BISHOP] = V(opSw(3), egSw(5));
sliderAttackPoints[WHITE_ROOK][WHITE_KING] = V(opSw(3), egSw(5));
sliderAttackPoints[WHITE_ROOK][BLACK_PAWN] = V(opSw(2), egSw(5));
sliderAttackPoints[WHITE_ROOK][BLACK_KNIGHT] = V(opSw(2), egSw(5));
sliderAttackPoints[WHITE_ROOK][BLACK_BISHOP] = V(opSw(2), egSw(5));
sliderAttackPoints[WHITE_ROOK][BLACK_QUEEN] = V(opSw(10), egSw(20));
sliderAttackPoints[WHITE_QUEEN][WHITE_PAWN] = V(opSw(1), egSw(2));
sliderAttackPoints[WHITE_QUEEN][WHITE_KNIGHT] = V(opSw(2), egSw(4));
sliderAttackPoints[WHITE_QUEEN][WHITE_BISHOP] = V(opSw(2), egSw(4));
sliderAttackPoints[WHITE_QUEEN][WHITE_ROOK] = V(opSw(2), egSw(4));
sliderAttackPoints[WHITE_QUEEN][WHITE_KING] = V(opSw(2), egSw(4));
sliderAttackPoints[WHITE_QUEEN][BLACK_KNIGHT] = V(opSw(2), egSw(5));
sliderAttackPoints[WHITE_QUEEN][BLACK_BISHOP] = V(opSw(2), egSw(5));
sliderAttackPoints[WHITE_QUEEN][BLACK_ROOK] = V(opSw(2), egSw(5));
#ifdef HIGH_ATTACK_BONUS
piecePieceAttackBonus[WHITE_PAWN][BLACK_KNIGHT] = V(opAw(-56), egAw(-70));
piecePieceAttackBonus[WHITE_PAWN][BLACK_BISHOP] = V(opAw(-56), egAw(-70));
piecePieceAttackBonus[WHITE_PAWN][BLACK_ROOK] = V(opAw(-76), egAw(-99));
piecePieceAttackBonus[WHITE_PAWN][BLACK_QUEEN] = V(opAw(-86), egAw(-118));
piecePieceAttackBonus[WHITE_KNIGHT][BLACK_PAWN] = V(opAw(7), egAw(39));
piecePieceAttackBonus[WHITE_KNIGHT][BLACK_BISHOP] = V(opAw(24), egAw(49));
piecePieceAttackBonus[WHITE_KNIGHT][BLACK_ROOK] = V(opAw(41), egAw(100));
piecePieceAttackBonus[WHITE_KNIGHT][BLACK_QUEEN] = V(opAw(41), egAw(100));
piecePieceAttackBonus[WHITE_BISHOP][BLACK_PAWN] = V(opAw(7), egAw(39));
piecePieceAttackBonus[WHITE_BISHOP][BLACK_KNIGHT] = V(opAw(24), egAw(49));
piecePieceAttackBonus[WHITE_BISHOP][BLACK_ROOK] = V(opAw(41), egAw(100));
piecePieceAttackBonus[WHITE_BISHOP][BLACK_QUEEN] = V(opAw(41), egAw(100));
piecePieceAttackBonus[WHITE_ROOK][BLACK_PAWN] = V(opAw(5), egAw(29));
piecePieceAttackBonus[WHITE_ROOK][BLACK_KNIGHT] = V(opAw(15), egAw(49));
piecePieceAttackBonus[WHITE_ROOK][BLACK_BISHOP] = V(opAw(15), egAw(49));
piecePieceAttackBonus[WHITE_ROOK][BLACK_QUEEN] = V(opAw(24), egAw(49));
piecePieceAttackBonus[WHITE_QUEEN][BLACK_PAWN] = V(opAw(15), egAw(39));
piecePieceAttackBonus[WHITE_QUEEN][BLACK_KNIGHT] = V(opAw(15), egAw(39));
piecePieceAttackBonus[WHITE_QUEEN][BLACK_BISHOP] = V(opAw(15), egAw(39));
piecePieceAttackBonus[WHITE_QUEEN][BLACK_ROOK] = V(opAw(15), egAw(39));
#else
piecePieceAttackBonus[WHITE_PAWN][BLACK_KNIGHT] = V(opAw(-5), egAw(-7));
piecePieceAttackBonus[WHITE_PAWN][BLACK_BISHOP] = V(opAw(-5), egAw(-7));
piecePieceAttackBonus[WHITE_PAWN][BLACK_ROOK] = V(opAw(-8), egAw(-10));
piecePieceAttackBonus[WHITE_PAWN][BLACK_QUEEN] = V(opAw(-8), egAw(-10));
piecePieceAttackBonus[WHITE_KNIGHT][BLACK_PAWN] = V(opAw(3), egAw(4));
piecePieceAttackBonus[WHITE_KNIGHT][BLACK_BISHOP] = V(opAw(4), egAw(5));
piecePieceAttackBonus[WHITE_KNIGHT][BLACK_ROOK] = V(opAw(8), egAw(10));
piecePieceAttackBonus[WHITE_KNIGHT][BLACK_QUEEN] = V(opAw(8), egAw(10));
piecePieceAttackBonus[WHITE_BISHOP][BLACK_PAWN] = V(opAw(3), egAw(4));
piecePieceAttackBonus[WHITE_BISHOP][BLACK_KNIGHT] = V(opAw(5), egAw(5));
piecePieceAttackBonus[WHITE_BISHOP][BLACK_ROOK] = V(opAw(8), egAw(10));
piecePieceAttackBonus[WHITE_BISHOP][BLACK_QUEEN] = V(opAw(8), egAw(10));
piecePieceAttackBonus[WHITE_ROOK][BLACK_PAWN] = V(opAw(2), egAw(3));
piecePieceAttackBonus[WHITE_ROOK][BLACK_KNIGHT] = V(opAw(4), egAw(5));
piecePieceAttackBonus[WHITE_ROOK][BLACK_BISHOP] = V(opAw(4), egAw(5));
piecePieceAttackBonus[WHITE_ROOK][BLACK_QUEEN] = V(opAw(8), egAw(10));
piecePieceAttackBonus[WHITE_QUEEN][BLACK_PAWN] = V(opAw(1), egAw(1));
piecePieceAttackBonus[WHITE_QUEEN][BLACK_KNIGHT] = V(opAw(2), egAw(2));
piecePieceAttackBonus[WHITE_QUEEN][BLACK_BISHOP] = V(opAw(2), egAw(2));
piecePieceAttackBonus[WHITE_QUEEN][BLACK_ROOK] = V(opAw(2), egAw(2));
#endif
for (i = 0; i < 16; i++)
{
int j;
for (j = 0; j < 16; j++)
{
if (pieceColor(i) == BLACK)
{
const Color reversedColor = opponent(pieceColor(j));
PieceType attacker = (PieceType) (pieceType(i) | WHITE);
PieceType attackedPiece =
(PieceType) (pieceType(j) | reversedColor);
sliderAttackPoints[i][j] =
sliderAttackPoints[attacker][attackedPiece];
piecePieceAttackBonus[i][j] =
piecePieceAttackBonus[attacker][attackedPiece];
}
}
}
assert(sliderAttackPoints[BLACK_ROOK][WHITE_PAWN] ==
sliderAttackPoints[WHITE_ROOK][BLACK_PAWN]);
assert(sliderAttackPoints[BLACK_QUEEN][WHITE_BISHOP] ==
sliderAttackPoints[WHITE_QUEEN][BLACK_BISHOP]);
assert(sliderAttackPoints[BLACK_KNIGHT][WHITE_BISHOP] ==
sliderAttackPoints[WHITE_KNIGHT][BLACK_BISHOP]);
troitzkyArea[WHITE] =
passedPawnCorridor[WHITE][A3] | passedPawnCorridor[WHITE][B5] |
passedPawnCorridor[WHITE][C3] | passedPawnCorridor[WHITE][D3] |
passedPawnCorridor[WHITE][E3] | passedPawnCorridor[WHITE][F3] |
passedPawnCorridor[WHITE][G5] | passedPawnCorridor[WHITE][H3];
troitzkyArea[BLACK] = getFlippedBitboard(troitzkyArea[WHITE]);
krprkDrawFiles = squaresOfFile[FILE_A] | squaresOfFile[FILE_B] |
squaresOfFile[FILE_G] | squaresOfFile[FILE_H];
A1C1 = minValue[A1] | minValue[C1], F1H1 = minValue[F1] | minValue[H1];
A1B1 = minValue[A1] | minValue[B1], G1H1 = minValue[G1] | minValue[H1];
initializeMaterialInfoTable(0, 0, 0);
transposeMatrix(MALUS_PAWN_SQUARE_TYPE_HR, MALUS_PAWN_SQUARE_TYPE);
transposeMatrix(MALUS_KING_SQUARE_HR, MALUS_KING_SQUARE);
return 0;
}
#ifndef NDEBUG
bool flipTest(Position * position,
PawnHashInfo * pawnHashtable,
KingSafetyHashInfo * kingsafetyHashtable)
{
int v1, v2;
EvaluationBase base;
initializePosition(position);
v1 = getValue(position, &base, pawnHashtable, kingsafetyHashtable);
flipPosition(position);
initializePosition(position);
v2 = getValue(position, &base, pawnHashtable, kingsafetyHashtable);
flipPosition(position);
initializePosition(position);
if (v1 != v2)
{
const int debugFlag = debugOutput;
const bool debugEvalFlag = debugEval;
debugOutput = TRUE;
debugEval = TRUE;
logDebug("flip test failed: v1=%d v2=%d\n", v1, v2);
logPosition(position);
logDebug("hash: %llu\n", position->hashValue);
getValue(position, &base, pawnHashtable, kingsafetyHashtable);
flipPosition(position);
initializePosition(position);
logPosition(position);
getValue(position, &base, pawnHashtable, kingsafetyHashtable);
flipPosition(position);
initializePosition(position);
debugEval = debugEvalFlag;
debugOutput = debugFlag;
}
return (bool) (v1 == v2);
}
#endif
static int testPawnInfoGeneration()
{
Variation variation;
EvaluationBase base;
initializeVariation(&variation,
"8/7p/5k2/5p2/p1p2P2/Pr1pPK2/1P1R3P/8 b - - 0 1");
getPawnInfo(&variation.singlePosition, &base);
assert(getNumberOfSetSquares(base.pawnProtectedSquares[WHITE]) == 8);
assert(testSquare(base.pawnProtectedSquares[WHITE], B4));
assert(testSquare(base.pawnProtectedSquares[WHITE], A3));
assert(testSquare(base.pawnProtectedSquares[WHITE], C3));
assert(testSquare(base.pawnProtectedSquares[WHITE], D4));
assert(testSquare(base.pawnProtectedSquares[WHITE], F4));
assert(testSquare(base.pawnProtectedSquares[WHITE], E5));
assert(testSquare(base.pawnProtectedSquares[WHITE], G5));
assert(testSquare(base.pawnProtectedSquares[WHITE], G3));
assert(getNumberOfSetSquares(base.pawnProtectedSquares[BLACK]) == 7);
assert(testSquare(base.pawnProtectedSquares[BLACK], B3));
assert(testSquare(base.pawnProtectedSquares[BLACK], D3));
assert(testSquare(base.pawnProtectedSquares[BLACK], C2));
assert(testSquare(base.pawnProtectedSquares[BLACK], E2));
assert(testSquare(base.pawnProtectedSquares[BLACK], E4));
assert(testSquare(base.pawnProtectedSquares[BLACK], G4));
assert(testSquare(base.pawnProtectedSquares[BLACK], G6));
assert(getNumberOfSetSquares(base.passedPawns[WHITE]) == 0);
assert(getNumberOfSetSquares(base.passedPawns[BLACK]) == 1);
assert(testSquare(base.passedPawns[BLACK], D3));
assert(getNumberOfSetSquares(base.weakPawns[WHITE]) == 3);
assert(testSquare(base.weakPawns[WHITE], B2));
assert(testSquare(base.weakPawns[WHITE], E3));
assert(testSquare(base.weakPawns[WHITE], H2));
assert(getNumberOfSetSquares(base.weakPawns[BLACK]) == 4);
assert(testSquare(base.weakPawns[BLACK], A4));
assert(testSquare(base.weakPawns[BLACK], C4));
assert(testSquare(base.weakPawns[BLACK], F5));
assert(testSquare(base.weakPawns[BLACK], H7));
initializeVariation(&variation,
"4k3/2p5/p2p4/P2P4/1PP3p1/7p/7P/4K3 w - - 0 1");
getPawnInfo(&variation.singlePosition, &base);
assert(getNumberOfSetSquares(base.passedPawns[WHITE]) == 0);
assert(getNumberOfSetSquares(base.passedPawns[BLACK]) == 0);
assert(getNumberOfSetSquares(base.weakPawns[WHITE]) == 1);
assert(testSquare(base.weakPawns[WHITE], H2));
assert(getNumberOfSetSquares(base.weakPawns[BLACK]) == 3);
assert(testSquare(base.weakPawns[BLACK], A6));
assert(testSquare(base.weakPawns[BLACK], C7));
assert(testSquare(base.weakPawns[BLACK], G4));
return 0;
}
static int testWeakPawnDetection()
{
Position position;
Bitboard expectedResult = EMPTY_BITBOARD;
EvaluationBase base;
clearPosition(&position);
position.piece[E1] = WHITE_KING;
position.piece[E8] = BLACK_KING;
position.piece[A3] = WHITE_PAWN;
position.piece[B5] = WHITE_PAWN;
position.piece[B6] = WHITE_PAWN;
position.piece[C4] = WHITE_PAWN;
position.piece[E4] = WHITE_PAWN;
position.piece[G4] = WHITE_PAWN;
position.piece[H2] = WHITE_PAWN;
position.piece[A4] = BLACK_PAWN;
position.piece[B7] = BLACK_PAWN;
setSquare(expectedResult, A3);
setSquare(expectedResult, E4);
initializePosition(&position);
getPawnInfo(&position, &base);
assert(base.weakPawns[WHITE] == expectedResult);
expectedResult = EMPTY_BITBOARD;
setSquare(expectedResult, B7);
assert(base.weakPawns[BLACK] == expectedResult);
assert(base.candidatePawns[BLACK] == EMPTY_BITBOARD);
position.piece[C4] = NO_PIECE;
position.piece[C5] = WHITE_PAWN;
initializePosition(&position);
getPawnInfo(&position, &base);
expectedResult = EMPTY_BITBOARD;
setSquare(expectedResult, C5);
assert(base.candidatePawns[WHITE] == expectedResult);
clearPosition(&position);
position.piece[E1] = WHITE_KING;
position.piece[E8] = BLACK_KING;
position.piece[A3] = WHITE_PAWN;
position.piece[B5] = WHITE_PAWN;
position.piece[B6] = WHITE_PAWN;
position.piece[C4] = WHITE_PAWN;
position.piece[E4] = WHITE_PAWN;
position.piece[G4] = WHITE_PAWN;
position.piece[H2] = WHITE_PAWN;
position.piece[A4] = BLACK_PAWN;
position.piece[B7] = BLACK_PAWN;
position.piece[D6] = BLACK_PAWN;
expectedResult = EMPTY_BITBOARD;
setSquare(expectedResult, A3);
setSquare(expectedResult, E4);
setSquare(expectedResult, C4);
initializePosition(&position);
getPawnInfo(&position, &base);
assert(base.weakPawns[WHITE] == expectedResult);
assert(base.candidatePawns[WHITE] == EMPTY_BITBOARD);
expectedResult = EMPTY_BITBOARD;
setSquare(expectedResult, B7);
setSquare(expectedResult, D6);
assert(base.weakPawns[BLACK] == expectedResult);
assert(base.candidatePawns[BLACK] == EMPTY_BITBOARD);
position.piece[G5] = BLACK_PAWN;
expectedResult = EMPTY_BITBOARD;
setSquare(expectedResult, A3);
setSquare(expectedResult, E4);
setSquare(expectedResult, C4);
setSquare(expectedResult, H2);
initializePosition(&position);
getPawnInfo(&position, &base);
assert(base.weakPawns[WHITE] == expectedResult);
assert(base.candidatePawns[WHITE] == EMPTY_BITBOARD);
expectedResult = EMPTY_BITBOARD;
setSquare(expectedResult, B7);
setSquare(expectedResult, D6);
setSquare(expectedResult, G5);
assert(base.weakPawns[BLACK] == expectedResult);
assert(base.candidatePawns[BLACK] == EMPTY_BITBOARD);
return 0;
}
static int testBaseInitialization()
{
Variation variation;
initializeVariation(&variation, FEN_GAMESTART);
assert(testSquare(passedPawnCorridor[WHITE][B4], B6));
assert(testSquare(passedPawnCorridor[BLACK][B4], B6) == FALSE);
assert(testSquare(passedPawnCorridor[WHITE][C2], H7) == FALSE);
assert(testSquare(passedPawnCorridor[BLACK][G6], G2));
#ifndef NDEBUG
{
INT32 testBonus = evalBonus(-1, -1);
assert(getOpeningValue(testBonus) == -1);
assert(getEndgameValue(testBonus) == -1);
}
#endif
return 0;
}
/*
static int testFlippings()
{
const char fen1[] =
"2rr2k1/1b3ppp/pb2p3/1p2P3/1P2BPnq/P1N3P1/1B2Q2P/R4R1K b - - 0 1";
const char fen2[] = "4k3/2p5/p2p4/P2P4/1PP3p1/7p/7P/4K3 w - - 0 1";
const char fen3[] = "8/7p/5k2/5p2/p1p2P2/Pr1pPK2/1P1R3P/8 b - - 0 1";
const char fen4[] =
"6r1/Q2Pn2k/p1p1P2p/5p2/2PqR1r1/1P6/P6P/5R1K b - - 5 4";
const char fen5[] =
"Q4rk1/2bb1ppp/4pn2/pQ5q/3P4/N4N2/5PPP/R1B2RK1 w - a6 0 4";
Variation variation;
initializeVariation(&variation, fen1);
assert(flipTest(&variation.singlePosition) != FALSE);
initializeVariation(&variation, fen2);
assert(flipTest(&variation.singlePosition) != FALSE);
initializeVariation(&variation, fen3);
assert(flipTest(&variation.singlePosition) != FALSE);
initializeVariation(&variation, fen4);
assert(flipTest(&variation.singlePosition) != FALSE);
initializeVariation(&variation, fen5);
assert(flipTest(&variation.singlePosition) != FALSE);
return 0;
}
*/
int testModuleEvaluation()
{
int result;
if ((result = testPawnInfoGeneration()) != 0)
{
return result;
}
if ((result = testWeakPawnDetection()) != 0)
{
return result;
}
if ((result = testBaseInitialization()) != 0)
{
return result;
}
/*
if ((result = testFlippings()) != 0)
{
return result;
}
*/
return 0;
}