/*
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/>.
*/
#define dumpPos dumpPosition(position);
#include <assert.h>
#include <stdlib.h>
#include <math.h>
#include "position.h"
#include "fen.h"
#include "io.h"
#include "evaluation.h"
#include "tools.h"
#ifdef INCLUDE_TABLEBASE_ACCESS
#include "tablebase.h"
#endif
#ifndef NDEBUG
PawnHashInfo localPawnHashtable[PAWN_HASHTABLE_SIZE];
KingSafetyHashInfo localKingSafetyHashtable[KINGSAFETY_HASHTABLE_SIZE];
#endif
KingSafetyHashInfo
kingSafetyHashtable[MAX_THREADS][KINGSAFETY_HASHTABLE_SIZE];
#define MAX_MOVES_KNIGHT 8
#define MAX_MOVES_BISHOP 13
#define MAX_MOVES_ROOK 14
#define MAX_MOVES_QUEEN 27
INT32 KnightMobilityBonus[MAX_MOVES_KNIGHT + 1];
INT32 BishopMobilityBonus[MAX_MOVES_BISHOP + 1];
INT32 RookMobilityBonus[MAX_MOVES_ROOK + 1];
INT32 QueenMobilityBonus[MAX_MOVES_QUEEN + 1];
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(-48, -42), V(-37, -32), V(-28, -22), V(-24, -17), V(-24, -17), V(-28, -22), V(-37, -32), V(-48, -42), /* rank 1 */
V(-33, -32), V(-24, -22), V(-13, -11), V(-8, -6), V(-8, -6), V(-13, -11), V(-24, -22), V(-33, -32), /* rank 2 */
V(-18, -22), V(-8, -11), V(0, -2), V(4, 1), V(4, 1), V(0, -2), V(-8, -11), V(-18, -22), /* rank 3 */
V(-8, -17), V(0, -6), V(9, 1), V(14, 7), V(14, 7), V(9, 1), V(0, -6), V(-8, -17), /* rank 4 */
V(-3, -17), V(4, -6), V(14, 1), V(19, 7), V(19, 7), V(14, 1), V(4, -6), V(-3, -17), /* rank 5 */
V(-3, -22), V(4, -11), V(14, -2), V(19, 1), V(19, 1), V(14, -2), V(4, -11), V(-3, -22), /* rank 6 */
V(-18, -32), V(-8, -22), V(0, -11), V(4, -6), V(4, -6), V(0, -11), V(-8, -22), V(-18, -32), /* rank 7 */
V(-70, -42), V(-24, -32), V(-13, -22), V(-8, -17), V(-8, -17), V(-13, -22), V(-24, -32), V(-70, -42) /* rank 8 */
};
const INT32 PstBishop[64] = {
V(-15, -21), V(-15, -15), V(-13, -12), V(-11, -9), V(-11, -9), V(-13, -12), V(-15, -15), V(-15, -21), /* rank 1 */
V(-6, -15), V(0, -9), V(-1, -6), V(0, -3), V(0, -3), V(-1, -6), V(0, -9), V(-6, -15), /* rank 2 */
V(-5, -12), V(-1, -6), V(3, -3), V(1, 0), V(1, 0), V(3, -3), V(-1, -6), V(-5, -12), /* rank 3 */
V(-3, -9), V(0, -3), V(1, 0), V(6, 0), V(6, 0), V(1, 0), V(0, -3), V(-3, -9), /* rank 4 */
V(-3, -9), V(0, -3), V(1, 0), V(6, 0), V(6, 0), V(1, 0), V(0, -3), V(-3, -9), /* rank 5 */
V(-5, -12), V(-1, -6), V(3, -3), V(1, 0), V(1, 0), V(3, -3), V(-1, -6), V(-5, -12), /* rank 6 */
V(-6, -15), V(0, -9), V(-1, -6), V(0, -3), V(0, -3), V(-1, -6), V(0, -9), V(-6, -15), /* rank 7 */
V(-6, -21), V(-6, -15), V(-5, -12), V(-3, -9), V(-3, -9), V(-5, -12), V(-6, -15), V(-6, -21) /* 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(106, 0), V(115, 23), V(96, 34), V(76, 46), V(76, 46), V(96, 34), V(115, 23), V(106, 0), /* rank 1 */
V(96, 23), V(106, 46), V(85, 58), V(67, 69), V(67, 69), V(85, 58), V(106, 46), V(96, 23), /* rank 2 */
V(76, 34), V(85, 58), V(67, 69), V(48, 81), V(48, 81), V(67, 69), V(85, 58), V(76, 34), /* rank 3 */
V(67, 46), V(76, 69), V(58, 81), V(38, 93), V(38, 93), V(58, 81), V(76, 69), V(67, 46), /* rank 4 */
V(58, 46), V(67, 69), V(48, 81), V(28, 93), V(28, 93), V(48, 81), V(67, 69), V(58, 46), /* rank 5 */
V(48, 34), V(58, 58), V(38, 69), V(18, 81), V(18, 81), V(38, 69), V(58, 58), V(48, 34), /* rank 6 */
V(38, 23), V(48, 46), V(28, 58), V(9, 69), V(9, 69), V(28, 58), V(48, 46), V(38, 23), /* rank 7 */
V(28, 0), V(38, 23), V(18, 34), V(0, 46), V(0, 46), V(18, 34), V(38, 23), V(28, 0) /* rank 8 */
};
/* -------------------------------------------------------------------------- */
static const int KNIGHT_BONUS_ATTACK = 17;
static const int BISHOP_BONUS_ATTACK = 16;
static const int ROOK_BONUS_ATTACK = 26;
static const int QUEEN_BONUS_ATTACK = 40;
static const int BISHOP_MALUS_BLOCKED = 51;
static const int BISHOP_MALUS_TRAPPED = 124;
INT32 mvImpact[16];
const int KINGSAFETY_PAWN_MALUS_DEFENDER[3][8] = {
{30, 0, 5, 15, 20, 25, 25, 25}, /* towards nearest border */
{55, 0, 15, 40, 50, 55, 55, 55},
{30, 0, 10, 20, 25, 30, 30, 30} /* towards center */
};
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}
};
const int KINGSAFETY_PAWN_BONUS_ATTACKER[3][8] = {
{5, 0, 40, 15, 5, 0, 0, 0}, /* towards nearest border */
{10, 0, 50, 20, 10, 0, 0, 0},
{10, 0, 50, 20, 10, 0, 0, 0} /* towards center */
};
#define OWN_COLOR_WEIGHT_DIV 256
#define OWN_COLOR_WEIGHT_KINGSAFETY 296
#define PAWN_EVAL_WEIGHT_OP 256
#define PAWN_EVAL_WEIGHT_EG 258
#define PASSED_PAWN_WEIGHT_OP 98
#define PASSED_PAWN_WEIGHT_EG 132
#define CHAIN_BONUS_WEIGHT_OP 86
#define CHAIN_BONUS_WEIGHT_EG 85
#define KS_PAWNSTRUCTURE_ATTACK_WEIGHT 14
#define KS_PAWNSTRUCTURE_WEIGHT 59
#define HOMELAND_SECURITY_WEIGHT 19
#define KING_SAFETY_MALUS_DIM (500)
#define BISHOP_PIN_OP_VAL 23
#define BISHOP_PIN_EG_VAL 5
int KING_SAFETY_MALUS[KING_SAFETY_MALUS_DIM];
/* -------------------------------------------------------------------------- */
int centerDistance[_64_], centerTaxiDistance[_64_];
int attackPoints[16];
Bitboard butterflySquares[_64_];
Bitboard lateralSquares[_64_];
Bitboard companionFiles[_64_];
Bitboard passedPawnRectangle[2][_64_];
Bitboard passedPawnCorridor[2][_64_];
Bitboard candidateDefenders[2][_64_]; /* excludes squares of rank */
Bitboard candidateSupporters[2][_64_]; /* includes squares of rank */
Bitboard pawnOpponents[2][_64_];
Bitboard kingTrapsRook[2][64];
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 piecePieceAttackBonus[16][16];
MaterialInfo materialInfo[MATERIALINFO_TABLE_SIZE];
/* *INDENT-OFF* */
static const int BONUS_KNIGHT_OUTPOST_HR[64] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 2, 7, 7, 7, 7, 2, 0,
0, 3, 10, 14, 14, 10, 3, 0,
0, 2, 7, 10, 10, 7, 2, 0,
0, 0, 2, 3, 3, 2, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
};
static const int BONUS_BISHOP_OUTPOST_HR[64] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 2, 3, 3, 3, 3, 2, 0,
0, 4, 8, 8, 8, 8, 4, 0,
0, 2, 4, 4, 4, 4, 2, 0,
0, 0, 2, 2, 2, 2, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
};
/* *INDENT-ON* */
static int BONUS_KNIGHT_OUTPOST[_64_];
static int BONUS_BISHOP_OUTPOST[_64_];
static INT32 PAWN_CHAIN_BONUS[_64_];
#ifndef NDEBUG
bool debugEval = FALSE;
#endif
int quad(int y_min, int y_max, int rank);
bool squareIsPawnSafe(const EvaluationBase * base,
const Color color, const Square square);
bool hasAttackingBishop(const Position * position,
const Color attackingColor, const Square square);
void getPawnInfo(const Position * position, EvaluationBase * base);
bool passerWalks(const Position * position,
const Square passerSquare, const Color passerColor);
Piece getDiaBatteryPiece(const Position * position,
const Bitboard moves,
const Square attackerSquare, const Color kingColor);
Square getPinningPiece(const Position * position,
const EvaluationBase * base,
const Square pieceSquare, const Color pieceColor);
void addEvalBonusForColor(EvaluationBase * base, const Color color,
const INT32 bonus)
{
if (color == WHITE)
{
base->balance += bonus;
}
else
{
base->balance -= bonus;
}
}
void addEvalMalusForColor(EvaluationBase * base, const Color color,
const INT32 bonus)
{
if (color == WHITE)
{
base->balance -= bonus;
}
else
{
base->balance += bonus;
}
}
Color getWinningColor(const Position * position, const int value)
{
if (position->activeColor == WHITE)
{
return (value >= 0 ? WHITE : BLACK);
}
else
{
return (value <= 0 ? WHITE : BLACK);
}
}
int getWhiteBishopBlockingIndex(const Position * position,
const Bitboard bishopSquares)
{
const Bitboard ownPawns =
position->piecesOfType[WHITE_PAWN] & bishopSquares;
const Bitboard blockingPieces = position->piecesOfColor[BLACK] | ownPawns;
const Bitboard blockedPawns = (blockingPieces >> 8) & ownPawns;
return getNumberOfSetSquares(ownPawns) +
getNumberOfSetSquares(ownPawns & extendedCenter) +
getNumberOfSetSquares(blockedPawns);
}
int getBlackBishopBlockingIndex(const Position * position,
const Bitboard bishopSquares)
{
const Bitboard ownPawns =
position->piecesOfType[BLACK_PAWN] & bishopSquares;
const Bitboard blockingPieces = position->piecesOfColor[WHITE] | ownPawns;
const Bitboard blockedPawns = (blockingPieces << 8) & ownPawns;
return getNumberOfSetSquares(ownPawns) +
getNumberOfSetSquares(ownPawns & extendedCenter) +
getNumberOfSetSquares(blockedPawns);
}
Bitboard getPromotablePawns(const Position * position, const Color color)
{
const Color oppColor = opponent(color);
const Square oppKing = position->king[oppColor];
const bool lightSquaredBishop = (bool)
(EMPTY_BITBOARD !=
(lightSquares & position->piecesOfType[BISHOP | color]));
const Bitboard pawns = position->piecesOfType[PAWN | color];
Bitboard supporters;
File excludeFile;
Rank promotionRank;
Square promotionSquare;
if (color == WHITE)
{
excludeFile = (lightSquaredBishop ? FILE_H : FILE_A);
promotionRank = RANK_8;
}
else
{
excludeFile = (lightSquaredBishop ? FILE_A : FILE_H);
promotionRank = RANK_1;
}
promotionSquare = getSquare(excludeFile, promotionRank);
supporters = companionFiles[promotionSquare] & pawns;
if (distance(oppKing, promotionSquare) <= 1 &&
supporters == EMPTY_BITBOARD)
{
return pawns & ~squaresOfFile[excludeFile];
}
else
{
return pawns;
}
}
bool oppositeColoredBishops(const Position * position)
{
if (getPieceCount(position, (Piece) WHITE_BISHOP_DARK) +
getPieceCount(position, (Piece) WHITE_BISHOP_LIGHT) == 1 &&
getPieceCount(position, (Piece) BLACK_BISHOP_DARK) +
getPieceCount(position, (Piece) BLACK_BISHOP_LIGHT) == 1)
{
const Bitboard bishops =
position->piecesOfType[WHITE_BISHOP] |
position->piecesOfType[BLACK_BISHOP];
return (bool) ((lightSquares & bishops) != EMPTY_BITBOARD &&
(darkSquares & bishops) != EMPTY_BITBOARD);
}
else
{
return FALSE;
}
}
bool passiveKingStopsPawn(const Square kingSquare,
const Square pawnSquare, const Color pawnColor)
{
return testSquare(pawnOpponents[pawnColor][pawnSquare], kingSquare);
}
bool passiveKingOnFileStopsPawn(const Square kingSquare,
const Square pawnSquare,
const Color pawnColor)
{
return file(kingSquare) == file(pawnSquare) &&
testSquare(pawnOpponents[pawnColor][pawnSquare], kingSquare);
}
int getKnnkpChances(const Position * position, const Color color)
{
Bitboard oppPawns = position->piecesOfType[PAWN | opponent(color)];
return ((oppPawns & troitzkyArea[color]) == EMPTY_BITBOARD ? 0 : 8);
}
int getKppxKxChances(const Position * position, const Color color)
{
Bitboard ownPawns = position->piecesOfType[PAWN | color];
File file;
int fileCount = 0;
for (file = FILE_A; file <= FILE_H; file++)
{
if ((squaresOfFile[file] & ownPawns) != EMPTY_BITBOARD)
{
if (++fileCount > 1)
{
return 16;
}
}
}
if (fileCount == 1)
{
const Square oppKing = position->king[opponent(color)];
Square square;
ITERATE_BITBOARD(&ownPawns, square)
{
if (passiveKingOnFileStopsPawn(oppKing, square, color) == FALSE)
{
return (distance(oppKing, square) <= 2 ? 14 : 16);
}
}
return (position->piecesOfType[KNIGHT | color] !=
EMPTY_BITBOARD ? 8 : 4);
}
return 16;
}
int getKpxKpxChances(const Position * position, const EvaluationBase * base,
const Color color)
{
if (base->passedPawns[WHITE] != EMPTY_BITBOARD ||
base->passedPawns[BLACK] != EMPTY_BITBOARD)
{
return 16;
}
else
{
const int chancesByPawnWidth[8] = { 0, 5, 9, 13, 15, 16, 16, 16 };
const int width = getWidth(position->piecesOfType[PAWN | color]);
const int chances = chancesByPawnWidth[width];
if (chances < 16)
{
const Color oppColor = opponent(color);
const int kingDistance =
getMinimumDistance(position->piecesOfType[PAWN | oppColor],
position->king[oppColor]);
return min(16, chances + 2 * (kingDistance - 1));
}
return chances;
}
}
int getKrppkrChances(const Position * position, const Color color)
{
const Color oppColor = opponent(color);
Bitboard pawns = position->piecesOfType[(Piece) (PAWN | color)];
const Square oppKing = position->king[oppColor];
Square square;
Bitboard files = EMPTY_BITBOARD;
assert(getNumberOfSetSquares
(pawns
) == 2);
if (colorRank(color, oppKing) == RANK_8)
{
return 16;
}
ITERATE_BITBOARD(&pawns, square)
{
const File pawnFile = file(square);
files |= minValue[getSquare(pawnFile, RANK_1)];
if (passiveKingStopsPawn(oppKing, square, color) == FALSE)
{
const int fileDiff
= abs(file
(oppKing
) - pawnFile
);
const int rankDiff =
colorRank(color, square) - colorRank(color, oppKing);
if ((fileDiff > 2) || (fileDiff == 2 && rankDiff >= 0))
{
return 16;
}
}
}
if (files == A1C1 || files == F1H1 || getNumberOfSetSquares(files) == 1)
{
return 4;
}
return 16;
}
int getKrpkrChances(const Position * position, const Color color)
{
const Color oppColor = opponent(color);
Bitboard pawns = position->piecesOfType[(Piece) (PAWN | color)];
const Square oppKing = position->king[oppColor];
Square square = getLastSquare(&pawns);
assert(getNumberOfSetSquares
(pawns
) == 0);
if (passiveKingStopsPawn(oppKing, square, color))
{
if (testSquare(krprkDrawFiles, square))
{
return 2;
}
else
{
const Square king = position->king[color];
const Rank kingRank = colorRank(color, king);
const Rank pawnRank = colorRank(color, square);
if (kingRank < RANK_6 || pawnRank < RANK_6)
{
return 2;
}
}
}
return 16;
}
int getKqppkqChances(const Position * position, const Color color)
{
const Color oppColor = opponent(color);
Bitboard pawns = position->piecesOfType[(Piece) (PAWN | color)];
const Square oppKing = position->king[oppColor];
Square square;
Bitboard files = EMPTY_BITBOARD;
assert(getNumberOfSetSquares
(pawns
) == 2);
ITERATE_BITBOARD(&pawns, square)
{
if (passiveKingStopsPawn(oppKing, square, color) == FALSE)
{
return 16;
}
files |= minValue[getSquare(file(square), RANK_1)];
}
if (files == A1B1 || files == G1H1 || getNumberOfSetSquares(files) == 1)
{
return 4;
}
return 16;
}
int getKqpkqChances(const Position * position, const Color color)
{
const Color oppColor = opponent(color);
Bitboard pawns = position->piecesOfType[(Piece) (PAWN | color)];
const Square oppKing = position->king[oppColor];
Square square = getLastSquare(&pawns);
const File pawnFile = file(square);
const Rank pawnRank = colorRank(color, square);
const int distDiff = distance(oppKing, square) -
distance(position->king[color], square);
const int distDiv = (distDiff <= 0 ? 2 : 1);
assert(getNumberOfSetSquares
(pawns
) == 0);
if (pawnRank <= RANK_6 && (pawnFile <= FILE_B || pawnFile >= FILE_G))
{
return (passiveKingStopsPawn(oppKing, square, color) ? 1 : 4 / distDiv);
}
else
{
return (passiveKingStopsPawn(oppKing, square, color) ?
4 : 16 / distDiv);
}
}
int getKpkChances(const Position * position, const Color color)
{
const Color oppColor = opponent(color);
Bitboard pawns = position->piecesOfType[(Piece) (PAWN | color)];
if ((pawns & nonA & nonH) != EMPTY_BITBOARD)
{
return 16;
}
else
{
const Square oppKing = position->king[oppColor];
Square square;
ITERATE_BITBOARD(&pawns, square)
{
if (passiveKingStopsPawn(oppKing, square, color) == FALSE)
{
return 16;
}
}
return 0; /* king holds pawn(s) */
}
}
int getKbpkChances(const Position * position, const Color color)
{
const Color oppColor = opponent(color);
const bool oppColors = oppositeColoredBishops(position);
const int max = (oppColors ? 8 : 16);
const Bitboard promotablePawns = getPromotablePawns(position, color);
const int numPromotablePawns = getNumberOfSetSquares(promotablePawns);
const int numDefenders =
(oppColors ?
getNumberOfSetSquares(position->piecesOfType[BISHOP | oppColor]) : 0);
return (numPromotablePawns > numDefenders ? max : 0);
}
int specialPositionChances(const Position * position,
const EvaluationBase * base,
const SpecialEvalType type, const Color color)
{
switch (type)
{
case Se_KpK:
return getKpkChances(position, color);
case Se_KbpK:
return getKbpkChances(position, color);
case Se_KrpKr:
return getKrpkrChances(position, color);
case Se_KrppKr:
return getKrppkrChances(position, color);
case Se_KqpKq:
return getKqpkqChances(position, color);
case Se_KqppKq:
return getKqppkqChances(position, color);
case Se_KnnKp:
return getKnnkpChances(position, color);
case Se_KppxKx:
return getKppxKxChances(position, color);
case Se_KpxKpx:
return getKpxKpxChances(position, base, color);
default:
return 16;
}
}
int getChances(const Position * position,
const EvaluationBase * base, const Color winningColor)
{
const MaterialInfo *mi = base->materialInfo;
int chances = 16;
if (numberOfNonPawnPieces(position, winningColor) <= 4 &&
getPieceCount(position, WHITE_QUEEN) <= 1 &&
getPieceCount(position, BLACK_QUEEN) <= 1)
{
if (winningColor == WHITE)
{
if (mi->specialEvalWhite != Se_None)
{
const int specialChances =
specialPositionChances(position, base, mi->specialEvalWhite,
WHITE);
chances = min(specialChances, mi->chancesWhite);
}
else
{
chances = mi->chancesWhite;
}
}
else
{
if (mi->specialEvalBlack != Se_None)
{
const int specialChances =
specialPositionChances(position, base, mi->specialEvalBlack,
BLACK);
chances = min(specialChances, mi->chancesBlack);
}
else
{
chances = mi->chancesBlack;
}
}
}
return chances;
}
bool hasBishopPair(const Position * position, const Color color)
{
const Bitboard *bishops =
&position->piecesOfType[(Piece) (BISHOP | color)];
return (bool) ((lightSquares & *bishops) != EMPTY_BITBOARD &&
(darkSquares & *bishops) != EMPTY_BITBOARD);
}
int phaseValue(const INT32 value, const Position * position,
EvaluationBase * base)
{
const INT32 materialValue = base->materialBalance +
base->materialInfo->materialBalance;
const int materialOpeningValue = getOpeningValue(materialValue);
const int materialEndgameValue = getEndgameValue(materialValue);
const int chancesWhite = getChances(position, base, WHITE);
const int chancesBlack = getChances(position, base, BLACK);
const int chances = max(chancesWhite, chancesBlack);
const int openingValue = materialOpeningValue + getOpeningValue(value);
const int endgameValue = (materialEndgameValue * chances) / 16 +
(getEndgameValue(value) * (16 + chances)) / 32;
return (openingValue * (256 - base->materialInfo->phaseIndex) +
endgameValue * base->materialInfo->phaseIndex) / 256;
}
INT32 materialBalance(const Position * position)
{
const INT32 bishopPairBonus =
V(VALUE_BISHOP_PAIR_OPENING, VALUE_BISHOP_PAIR_ENDGAME);
static const INT32 knightBonus = V(0, 5);
static const INT32 rookMalus = V(5, 0);
static const INT32 rookPairMalus = V(17, 25);
static const INT32 rookQueenMalus = V(8, 12);
static const INT32 pieceUpBonus =
V(DEFAULTVALUE_PIECE_UP_OPENING, DEFAULTVALUE_PIECE_UP_ENDGAME);
INT32 balance = 0;
const int pawnCountWhite = position->numberOfPawns[WHITE] - 5;
const int pawnCountBlack = position->numberOfPawns[BLACK] - 5;
const int numWhiteKnights = getPieceCount(position, WHITE_KNIGHT);
const int numBlackKnights = getPieceCount(position, BLACK_KNIGHT);
const int knightSaldo = pawnCountWhite * numWhiteKnights -
pawnCountBlack * numBlackKnights;
const int numWhiteRooks = getPieceCount(position, WHITE_ROOK);
const int numBlackRooks = getPieceCount(position, BLACK_ROOK);
const int rookSaldo = pawnCountWhite * numWhiteRooks -
pawnCountBlack * numBlackRooks;
const int pieceCountSaldo =
(numberOfNonPawnPieces(position, WHITE) - numWhiteRooks -
getPieceCount(position, WHITE_QUEEN)) -
(numberOfNonPawnPieces(position, BLACK) - numBlackRooks -
getPieceCount(position, BLACK_QUEEN));
if (hasBishopPair(position, WHITE))
{
balance += bishopPairBonus;
}
if (hasBishopPair(position, BLACK))
{
balance -= bishopPairBonus;
}
balance += knightSaldo * knightBonus - rookSaldo * rookMalus;
if (numWhiteRooks >= 2)
{
balance -= rookPairMalus + rookQueenMalus;
}
else if (numWhiteRooks + getPieceCount(position, WHITE_QUEEN) >= 2)
{
balance -= rookQueenMalus;
}
if (numBlackRooks >= 2)
{
balance += rookPairMalus + rookQueenMalus;
}
else if (numBlackRooks + getPieceCount(position, BLACK_QUEEN) >= 2)
{
balance += rookQueenMalus;
}
if (pieceCountSaldo > 0)
{
balance += pieceUpBonus;
}
else if (pieceCountSaldo < 0)
{
balance -= pieceUpBonus;
}
return balance;
}
/**
* Calculate a rough value of the specified position,
* based on the current pst-values and the specified evaluation base.
*
* @return the value of the specified position
*/
INT32 positionalBalance(const Position * position, EvaluationBase * base)
{
static const INT32 tempoBonus[2] = {
V(VALUE_TEMPO_OPENING, VALUE_TEMPO_ENDGAME),
V(-VALUE_TEMPO_OPENING, -VALUE_TEMPO_ENDGAME)
};
const INT32 balance = position->balance + base->balance +
tempoBonus[position->activeColor];
const int value = phaseValue(balance, position, base);
return (position->activeColor == WHITE ? value : -value);
}
/**
* Check if the specified color can win the specified position.
*
* @return FALSE if the specified color doesn't have sufficient material
* left to win the position
*/
bool hasWinningPotential(Position * position, Color color)
{
return (bool) (position->numberOfPieces[color] > 1);
}
/**
* Get the king safety hash value for the given king square.
*/
Bitboard calculateKingPawnSafetyHashKey(const Position * position,
const Color color)
{
const int mask[2] =
{ WHITE_00 | WHITE_000 | 16, BLACK_00 | BLACK_000 | 32 };
const int index = (position->castlingRights | 48) & mask[color];
return position->pawnHashKey ^
GENERATED_KEYTABLE[color][position->king[color]] ^
GENERATED_KEYTABLE[2][index];
}
int getPawnWidth(const Position * position, const Color color)
{
const Bitboard tmp = position->piecesOfType[(Piece) (PAWN | color)] |
minValue[position->king[opponent(color)]];
return getWidth(tmp);
}
int getPassedPawnWidth(const Position * position,
const EvaluationBase * base, const Color color)
{
const Bitboard tmp = base->passedPawns[color] |
minValue[position->king[opponent(color)]];
return getWidth(tmp);
}
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;
}
static int getHomeSecurityWeight(const Position * position)
{
const int count = getPieceCount(position, WHITE_KNIGHT) +
getPieceCount(position, (Piece) WHITE_BISHOP_DARK) +
getPieceCount(position, (Piece) WHITE_BISHOP_LIGHT) +
getPieceCount(position, BLACK_KNIGHT) +
getPieceCount(position, (Piece) BLACK_BISHOP_DARK) +
getPieceCount(position, (Piece) BLACK_BISHOP_LIGHT);
return count * count;
}
bool squareIsPawnSafe(const EvaluationBase * base,
const Color color, const Square square)
{
return testSquare(base->pawnAttackableSquares[opponent(color)],
square) == FALSE;
}
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);
}
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;
/* 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));
/* 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->chainPawns[WHITE] = white &
(base->pawnProtectedSquares[WHITE] | whiteLateralSquares);
base->chainPawns[BLACK] = black &
(base->pawnProtectedSquares[BLACK] | blackLateralSquares);
}
#define KP_DISTANCE_WEIGHT 6
#define KP_REDUCED_DISTANCE_WEIGHT 3
static int getKingWhitePawnDistance(const Square pawnSquare,
const Square kingSquare)
{
const int rankDiff = rank(pawnSquare) - rank(kingSquare);
const int fileDistance
= abs(file
(pawnSquare
) - file
(kingSquare
));
return (rankDiff < 0 ? KP_REDUCED_DISTANCE_WEIGHT :
KP_DISTANCE_WEIGHT
) * abs(rankDiff
) +
KP_DISTANCE_WEIGHT * fileDistance;
}
static int getKingBlackPawnDistance(const Square pawnSquare,
const Square kingSquare)
{
const int rankDiff = rank(pawnSquare) - rank(kingSquare);
const int fileDistance
= abs(file
(pawnSquare
) - file
(kingSquare
));
return (rankDiff > 0 ? KP_REDUCED_DISTANCE_WEIGHT :
KP_DISTANCE_WEIGHT
) * abs(rankDiff
) +
KP_DISTANCE_WEIGHT * fileDistance;
}
static int getKingPawnDistanceValue(const Position * position,
const Square kingSquare, Bitboard pawns)
{
Square square;
int value = 1024;
ITERATE_BITBOARD(&pawns, square)
{
int currentValue;
if (position->piece[square] == WHITE_PAWN)
{
currentValue = getKingWhitePawnDistance(square, kingSquare);
}
else
{
currentValue = getKingBlackPawnDistance(square, kingSquare);
}
if (currentValue < value)
{
value = currentValue;
}
}
return value;
}
static int getKingPawnDistance(const Position * position, const Color color)
{
const Bitboard pawns = position->piecesOfType[WHITE_PAWN] |
position->piecesOfType[BLACK_PAWN];
const Square kingSquare = position->king[color];
if (pawns != EMPTY_BITBOARD)
{
int distance = 1;
while (1)
{
Bitboard pid = pawns & squaresInDistance[distance][kingSquare];
if (pid != EMPTY_BITBOARD)
{
return getKingPawnDistanceValue(position, kingSquare, pid);
}
else
{
distance++;
}
}
}
return 0;
}
bool pawnIsPassed(const Position * position, const Square pawnSquare,
const Color pawnColor)
{
const Color defenderColor = opponent(pawnColor);
const Bitboard corridor = passedPawnCorridor[pawnColor][pawnSquare];
const Bitboard defenders = position->piecesOfType[PAWN | defenderColor] &
(candidateDefenders[pawnColor][pawnSquare] | corridor);
if (defenders == EMPTY_BITBOARD)
{
const Bitboard blockers = position->piecesOfType[PAWN | pawnColor] &
corridor;
return (bool) (blockers == EMPTY_BITBOARD);
}
return FALSE;
}
bool captureCreatesPasser(Position * position, const Square captureSquare,
const Piece capturingPiece)
{
const Piece captured = position->piece[captureSquare];
const Color capturedColor = pieceColor(captured);
const Color passerColor = opponent(capturedColor);
Bitboard candidates = (passedPawnCorridor[capturedColor][captureSquare] |
candidateDefenders[capturedColor][captureSquare]) &
position->piecesOfType[PAWN | passerColor];
bool result = FALSE;
if (pieceType(capturingPiece) == PAWN &&
pawnIsPassed(position, captureSquare, passerColor))
{
/* dumpSquare(captureSquare);
dumpPosition(position); */
return TRUE;
}
if (candidates != EMPTY_BITBOARD)
{
const Bitboard pawnsOriginal =
position->piecesOfType[PAWN | capturedColor];
Square square;
clearSquare(position->piecesOfType[PAWN | capturedColor],
captureSquare);
ITERATE_BITBOARD(&candidates, square)
{
if (pawnIsPassed(position, square, passerColor))
{
/*dumpSquare(captureSquare);
dumpSquare(square);
dumpBitboard(cc, "cd");
dumpPosition(position); */
result = TRUE;
candidates = EMPTY_BITBOARD; /* force loop exit */
}
}
position->piecesOfType[PAWN | capturedColor] = pawnsOriginal;
}
return result;
}
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;
}
#ifdef USE_ORTHO_BATTERY_PIECE
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;
}
#endif
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;
}
Square getPinningPiece(const Position * position,
const EvaluationBase * base,
const Square pieceSquare, const Color pieceColor)
{
if (testSquare(base->pinnedCandidatesDia[pieceColor], pieceSquare))
{
const Color oppColor = opponent(pieceColor);
Bitboard pinningCandidates = position->piecesOfType[BISHOP | oppColor] |
position->piecesOfType[QUEEN | oppColor];
if (pinningCandidates != EMPTY_BITBOARD)
{
pinningCandidates &=
generalMoves[BISHOP][position->king[pieceColor]];
if (pinningCandidates != EMPTY_BITBOARD)
{
pinningCandidates &=
getMagicBishopMoves(pieceSquare, position->allPieces);
if (pinningCandidates != EMPTY_BITBOARD)
{
return getFirstSquare(&pinningCandidates);
}
}
}
}
if (testSquare(base->pinnedCandidatesOrtho[pieceColor], pieceSquare))
{
const Color oppColor = opponent(pieceColor);
Bitboard pinningCandidates = position->piecesOfType[ROOK | oppColor] |
position->piecesOfType[QUEEN | oppColor];
if (pinningCandidates != EMPTY_BITBOARD)
{
pinningCandidates &= generalMoves[ROOK][position->king[pieceColor]];
if (pinningCandidates != EMPTY_BITBOARD)
{
pinningCandidates &=
getMagicRookMoves(pieceSquare, position->allPieces);
if (pinningCandidates != EMPTY_BITBOARD)
{
return getFirstSquare(&pinningCandidates);
}
}
}
}
return NO_SQUARE;
}
#ifdef USE_CAN_CASTLE
static bool canCastle(const Position * position, const Color color)
{
BYTE castlingRights[2] = { WHITE_00 | WHITE_000, BLACK_00 | BLACK_000 };
return (castlingRights[color] & position->castlingRights) != 0;
}
#endif
#define PERSPECTIVE_WHITE
#include "evaluationc.c"
#undef PERSPECTIVE_WHITE
#include "evaluationc.c"
static void evaluatePawns(const Position * position, EvaluationBase * base)
{
int opValue, egValue;
static const 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)
};
static const 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)
};
static const 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)
};
static const 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)
};
static const 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)
};
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]);
}
}
}
base->balance += V(0, 5 *
(getWidth(position->piecesOfType[WHITE_PAWN]) -
getWidth(position->piecesOfType[BLACK_PAWN])));
evaluateWhitePawns(base);
evaluateBlackPawns(base);
opValue = getOpeningValue(base->balance);
egValue = getEndgameValue(base->balance);
base->balance = V((opValue * PAWN_EVAL_WEIGHT_OP) / 256,
(egValue * PAWN_EVAL_WEIGHT_EG) / 256);
}
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);
}
}
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);
}
}
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);
}
}
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));
}
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 = 8; /* malus for weak back rank */
}
return malus;
}
static INT32 getPawnShelterMalus(const Position * position, const Color color,
KingSafetyHashInfo * kingSafetyHashtable)
{
const Bitboard hashKey = calculateKingPawnSafetyHashKey(position, color);
KingSafetyHashInfo *kingSafetyHashInfo =
&kingSafetyHashtable[hashKey & KINGSAFETY_HASHTABLE_MASK];
if (kingSafetyHashInfo->hashKey == hashKey &&
kingSafetyHashInfo->hashKey != 0)
{
return kingSafetyHashInfo->safetyMalus;
}
else
{
static const int rankByColor[2] = { RANK_1, RANK_8 };
int cr00, cr000;
const Square kingSquare = position->king[color];
int pawnShelterMalus = 0, castlingShelterMalus = 0;
INT32 malus;
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;
malus = V(pawnShelterMalus, getKingPawnDistance(position, color));
kingSafetyHashInfo->hashKey = hashKey;
kingSafetyHashInfo->safetyMalus = malus;
return malus;
}
}
static Bitboard getWellDefendedSquares(EvaluationBase * base,
const Color color)
{
return base->pawnProtectedSquares[color] |
base->knightAttackedSquares[color] | base->bishopAttackedSquares[color];
}
static INT32 getKingSafetyMalus(const Position * position,
EvaluationBase * base, const Color color)
{
const Color oppColor = opponent(color);
const INT32 pawnShelterMalus =
getPawnShelterMalus(position, color, base->kingsafetyHashtable);
const int openingShelterMalus = getOpeningValue(pawnShelterMalus);
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 opMalus = (KS_PAWNSTRUCTURE_WEIGHT * openingShelterMalus) / 64;
if (numAttackers > 0)
{
int attackUnits = 0;
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;
const Bitboard undefendedSquares =
attackedSquares & ~base->attackedSquares[color];
const Bitboard safeChecks =
~(position->piecesOfColor[oppColor] | base->attackedSquares[color]);
const Bitboard safeQueenChecks =
oppQueenAttacks & undefendedSquares & safeChecks &
(getWellDefendedSquares(base, oppColor) |
base->rookAttackedSquares[oppColor] |
base->queenSupportedSquares[oppColor] |
getKingMoves(position->king[oppColor]));
const Bitboard safeRookChecks =
base->rookAttackedSquares[oppColor] &
undefendedSquares & safeChecks &
generalMoves[ROOK][kingSquare] &
(getWellDefendedSquares(base, oppColor) |
base->rookDoubleAttackedSquares[oppColor] |
base->queenAttackedSquares[oppColor] |
base->queenSupportedSquares[oppColor]);
const Bitboard safeDistantChecks = safeChecks & ~corona;
const Bitboard safeOrthoChecks =
safeDistantChecks &
getMagicRookMoves(kingSquare, position->allPieces);
const Bitboard safeDiaChecks =
safeDistantChecks &
getMagicBishopMoves(kingSquare, position->allPieces);
const Bitboard safeKnightChecks =
safeDistantChecks & getKnightMoves(kingSquare);
attackUnits =
min(25, (numAttackers * attackersWeight) / 16) +
2 * base->kingSquaresAttackCount[oppColor] +
4 * getNumberOfSetSquares(undefendedSquares) +
(openingShelterMalus * KS_PAWNSTRUCTURE_ATTACK_WEIGHT) / 256;
if (base->pinnedPieces[color] != EMPTY_BITBOARD)
{
attackUnits += 2;
}
if (position->piecesOfType[QUEEN | oppColor] == EMPTY_BITBOARD)
{
attackUnits -= 19;
}
if (safeQueenChecks != EMPTY_BITBOARD)
{
const int numChecks = getNumberOfSetSquares(safeQueenChecks);
attackUnits += 23 * numChecks;
}
if (safeRookChecks != EMPTY_BITBOARD)
{
const int numChecks = getNumberOfSetSquares(safeRookChecks);
attackUnits += 12 * numChecks;
}
if (safeOrthoChecks != EMPTY_BITBOARD)
{
const Bitboard queenChecks =
safeOrthoChecks & base->queenAttackedSquares[oppColor];
const Bitboard rookChecks =
safeOrthoChecks & base->rookAttackedSquares[oppColor];
if (queenChecks != EMPTY_BITBOARD)
{
attackUnits += 12 * getNumberOfSetSquares(queenChecks);
}
if (rookChecks != EMPTY_BITBOARD)
{
attackUnits += 8 * 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 += 12 * getNumberOfSetSquares(queenChecks);
}
if (bishopChecks != EMPTY_BITBOARD)
{
attackUnits += 2 * getNumberOfSetSquares(bishopChecks);
}
}
if (safeKnightChecks != EMPTY_BITBOARD)
{
const Bitboard knightChecks =
safeKnightChecks & base->knightAttackedSquares[oppColor];
if (knightChecks != EMPTY_BITBOARD)
{
attackUnits += 3 * getNumberOfSetSquares(knightChecks);
}
}
if (attackUnits > 0)
{
const int numUnits =
min(KING_SAFETY_MALUS_DIM - 1, (715 * attackUnits) / 256);
opMalus += KING_SAFETY_MALUS[numUnits];
}
}
return V(opMalus, getEndgameValue(pawnShelterMalus));
}
static bool kingSafetyEvalRequired(const Position * position,
const Color color)
{
const Color oppColor = opponent(color);
return (bool)
(getPieceCount(position, (Piece) (QUEEN | oppColor)) > 0 &&
getPieceWeight(position,
oppColor) >= MIN_PIECE_WEIGHT_FOR_KING_ATTACK);
}
#ifndef NDEBUG
static Bitboard randomBitboard()
{
return tmp1 + (tmp2 << 16) + (tmp3 << 32) + (tmp4 << 48);
}
#endif
static void initializeEvaluationBase(EvaluationBase * base,
KingSafetyHashInfo *
kingsafetyHashtable,
const Position * position)
{
#ifndef NDEBUG
base->attackedSquares[WHITE] = randomBitboard();
base->attackedSquares[BLACK] = randomBitboard();
base->queenAttackedSquares[WHITE] = randomBitboard();
base->queenAttackedSquares[BLACK] = randomBitboard();
base->queenSupportedSquares[WHITE] = randomBitboard();
base->queenSupportedSquares[BLACK] = randomBitboard();
base->rookAttackedSquares[WHITE] = randomBitboard();
base->rookAttackedSquares[BLACK] = randomBitboard();
base->rookDoubleAttackedSquares[WHITE] = randomBitboard();
base->rookDoubleAttackedSquares[BLACK] = randomBitboard();
base->bishopAttackedSquares[WHITE] = randomBitboard();
base->bishopAttackedSquares[BLACK] = randomBitboard();
base->knightAttackedSquares[WHITE] = randomBitboard();
base->knightAttackedSquares[BLACK] = randomBitboard();
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->passedPawns[WHITE] = randomBitboard();
base->passedPawns[BLACK] = randomBitboard();
base->pinnedCandidatesDia[WHITE] = randomBitboard();
base->pinnedCandidatesDia[BLACK] = randomBitboard();
base->pinnedCandidatesOrtho[WHITE] = randomBitboard();
base->pinnedCandidatesOrtho[BLACK] = randomBitboard();
base->pinnedPieces[WHITE] = randomBitboard();
base->pinnedPieces[BLACK] = randomBitboard();
base->pawnAttackableSquares[WHITE] = randomBitboard();
base->pawnAttackableSquares[BLACK] = randomBitboard();
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->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->materialInfo = &materialInfo[calculateMaterialSignature(position)];
}
static void evaluatePieces(const Position * position, EvaluationBase * base)
{
Bitboard queens = position->piecesOfType[WHITE_QUEEN] |
position->piecesOfType[BLACK_QUEEN];
const Bitboard exclude = position->piecesOfType[WHITE_PAWN] |
position->piecesOfType[BLACK_PAWN] | queens |
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
base->materialBalance += mvImpact[position->piece[square]];
switch (position->piece[square])
{
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
}
ITERATE_BITBOARD(&queens, square)
{
#ifndef NDEBUG
if (debugEval)
{
dumpSquare(square);
logDebug("op=%d eg=%d\n", getOpeningValue(base->balance),
getEndgameValue(base->balance));
}
#endif
base->materialBalance += mvImpact[position->piece[square]];
switch (position->piece[square])
{
case WHITE_QUEEN:
evaluateWhiteQueen(position, base, square);
break;
case BLACK_QUEEN:
evaluateBlackQueen(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 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 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 &&
position->piecesOfType[(Piece) (BISHOP | attackingColor)] !=
EMPTY_BITBOARD)
{
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;
}
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);
}
static void setPinnedCandidates(const Position * position,
EvaluationBase * base, const Color color)
{
const Bitboard candidatePieces = getNonPawnPieces(position, color);
const Square kingSquare = position->king[color];
base->pinnedCandidatesDia[color] =
candidatePieces & getMagicBishopMoves(kingSquare, position->allPieces);
base->pinnedCandidatesOrtho[color] =
candidatePieces & getMagicRookMoves(kingSquare, position->allPieces);
}
static int getNumberOfUnprotectedMinors(const Position * position,
EvaluationBase * base,
const Color color)
{
const Bitboard candidatePieces = position->piecesOfType[KNIGHT | color] |
position->piecesOfType[BISHOP | color];
const Bitboard unprotectedMinors =
candidatePieces & ~base->attackedSquares[color];
return (unprotectedMinors == EMPTY_BITBOARD ? 0 :
getNumberOfSetSquares(unprotectedMinors));
}
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] = ~(minValue[position->king[WHITE]] |
position->piecesOfType[WHITE_PAWN] |
base->pawnProtectedSquares[BLACK]);
base->unprotectedPieces[WHITE] = position->piecesOfColor[WHITE] &
~base->pawnProtectedSquares[WHITE];
base->countedSquares[BLACK] = ~(minValue[position->king[BLACK]] |
position->piecesOfType[BLACK_PAWN] |
base->pawnProtectedSquares[WHITE]);
base->unprotectedPieces[BLACK] = position->piecesOfColor[BLACK] &
~base->pawnProtectedSquares[BLACK];
base->spaceAttackPoints[WHITE] = base->spaceAttackPoints[BLACK] = 0;
base->attackedSquares[WHITE] = base->pawnProtectedSquares[WHITE];
base->attackedSquares[BLACK] = base->pawnProtectedSquares[BLACK];
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->rookDoubleAttackedSquares[WHITE] = EMPTY_BITBOARD;
base->rookDoubleAttackedSquares[BLACK] = EMPTY_BITBOARD;
base->queenAttackedSquares[WHITE] = EMPTY_BITBOARD;
base->queenAttackedSquares[BLACK] = EMPTY_BITBOARD;
base->queenSupportedSquares[WHITE] = EMPTY_BITBOARD;
base->queenSupportedSquares[BLACK] = EMPTY_BITBOARD;
base->pinnedPieces[WHITE] = EMPTY_BITBOARD;
base->pinnedPieces[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;
base->materialBalance =
position->numberOfPawns[WHITE] * mvImpact[WHITE_PAWN] +
position->numberOfPawns[BLACK] * mvImpact[BLACK_PAWN];
setPinnedCandidates(position, base, WHITE);
setPinnedCandidates(position, base, BLACK);
evaluatePieces(position, base);
base->attackedSquares[WHITE] |= base->knightAttackedSquares[WHITE] |
base->bishopAttackedSquares[WHITE] | base->rookAttackedSquares[WHITE] |
base->queenAttackedSquares[WHITE];
base->attackedSquares[BLACK] |= base->knightAttackedSquares[BLACK] |
base->bishopAttackedSquares[BLACK] | base->rookAttackedSquares[BLACK] |
base->queenAttackedSquares[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));
}
{
Color color;
for (color = WHITE; color <= BLACK; color++)
{
Bitboard pawns = position->piecesOfType[PAWN | color];
Square pawnSquare;
ITERATE_BITBOARD(&pawns, pawnSquare)
{
if (testSquare(base->passedPawns[color], pawnSquare))
{
assert(pawnIsPassed
(position
, pawnSquare
, color
));
}
else
{
assert(pawnIsPassed
(position
, pawnSquare
, color
) == FALSE
);
}
}
}
}
#endif
{
INT32 malus = getKingSafetyMalus(position, base, WHITE);
#ifdef NDEBUG
if (base->ownColor == WHITE)
{
const int opValue =
(OWN_COLOR_WEIGHT_KINGSAFETY * getOpeningValue(malus)) /
OWN_COLOR_WEIGHT_DIV;
malus = V(opValue, getEndgameValue(malus));
}
#endif
base->balance -= malus;
}
{
INT32 malus = getKingSafetyMalus(position, base, BLACK);
#ifdef NDEBUG
if (base->ownColor == BLACK)
{
const int opValue =
(OWN_COLOR_WEIGHT_KINGSAFETY * getOpeningValue(malus)) /
OWN_COLOR_WEIGHT_DIV;
malus = V(opValue, getEndgameValue(malus));
}
#endif
base->balance += malus;
}
#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
base->attackedSquares[WHITE] |= getKingMoves(position->king[WHITE]);
base->attackedSquares[BLACK] |= getKingMoves(position->king[BLACK]);
{
const INT32 malus = V(15, 2);
const int unprotectedWhiteMinors =
getNumberOfUnprotectedMinors(position, base, WHITE);
const int unprotectedBlackMinors =
getNumberOfUnprotectedMinors(position, base, BLACK);
base->balance -=
malus * (unprotectedWhiteMinors - unprotectedBlackMinors);
}
{
const INT32 bonusPerMinor = V(4, 0);
const Bitboard whiteMinors = (position->piecesOfType[WHITE_PAWN] >> 8) &
(position->piecesOfType[WHITE_BISHOP] |
position->piecesOfType[WHITE_KNIGHT]) &
squaresOfRankRange[RANK_1][RANK_4];
const Bitboard blackMinors = (position->piecesOfType[BLACK_PAWN] << 8) &
(position->piecesOfType[BLACK_BISHOP] |
position->piecesOfType[BLACK_KNIGHT]) &
squaresOfRankRange[RANK_8][RANK_5];
const int delta = getNumberOfSetSquares(whiteMinors) -
getNumberOfSetSquares(blackMinors);
base->balance += delta * bonusPerMinor;
}
if (base->materialInfo->phaseIndex < PHASE_INDEX_MAX)
{
const int weight = getHomeSecurityWeight(position);
if (weight > 0)
{
const int countWhite =
getHomelandSecurityCount(position, base, WHITE);
const int countBlack =
getHomelandSecurityCount(position, base, BLACK);
const int baseValue = (countWhite - countBlack) * weight;
base->balance += V((baseValue * HOMELAND_SECURITY_WEIGHT) / 256, 0);
}
}
#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->pawnHashKey & PAWN_HASHTABLE_MASK];
initializeEvaluationBase(base, kingsafetyHashtable, position);
if (pawnHashInfo->hashKey == position->pawnHashKey &&
pawnHashInfo->hashKey != 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->pawnAttackableSquares[WHITE] =
pawnHashInfo->pawnAttackableSquares[WHITE];
base->pawnAttackableSquares[BLACK] =
pawnHashInfo->pawnAttackableSquares[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->hashKey = position->pawnHashKey;
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->pawnAttackableSquares[WHITE] =
base->pawnAttackableSquares[WHITE];
pawnHashInfo->pawnAttackableSquares[BLACK] =
base->pawnAttackableSquares[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
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++];
}
}
}
static int pstOpeningValue(INT32 value, const int weight)
{
return applyWeight(weight, getOpeningValue(value));
}
static int pstEndgameValue(INT32 value, const int weight)
{
return applyWeight(weight, getEndgameValue(value));
}
static void initializePieceSquareValues()
{
Square sq;
mvImpact[WHITE_QUEEN] = V(VALUE_QUEEN_OPENING, VALUE_QUEEN_ENDGAME);
mvImpact[BLACK_QUEEN] = V(-VALUE_QUEEN_OPENING, -VALUE_QUEEN_ENDGAME);
mvImpact[WHITE_ROOK] = V(VALUE_ROOK_OPENING, VALUE_ROOK_ENDGAME);
mvImpact[BLACK_ROOK] = V(-VALUE_ROOK_OPENING, -VALUE_ROOK_ENDGAME);
mvImpact[WHITE_BISHOP] = V(VALUE_BISHOP_OPENING, VALUE_BISHOP_ENDGAME);
mvImpact[BLACK_BISHOP] = V(-VALUE_BISHOP_OPENING, -VALUE_BISHOP_ENDGAME);
mvImpact[WHITE_KNIGHT] = V(VALUE_KNIGHT_OPENING, VALUE_KNIGHT_ENDGAME);
mvImpact[BLACK_KNIGHT] = V(-VALUE_KNIGHT_OPENING, -VALUE_KNIGHT_ENDGAME);
mvImpact[WHITE_PAWN] = V(VALUE_PAWN_OPENING, VALUE_PAWN_ENDGAME);
mvImpact[BLACK_PAWN] = V(-VALUE_PAWN_OPENING, -VALUE_PAWN_ENDGAME);
ITERATE(sq)
{
int ov, ev;
ov = pstOpeningValue(PstPawn[sq], 256);
ev = pstEndgameValue(PstPawn[sq], 250);
pieceSquareBonus[WHITE_PAWN][sq] =
pieceSquareBonus[BLACK_PAWN][getFlippedSquare(sq)] = V(ov, ev);
ov = pstOpeningValue(PstKnight[sq], 256);
ev = pstEndgameValue(PstKnight[sq], 256);
pieceSquareBonus[WHITE_KNIGHT][sq] =
pieceSquareBonus[BLACK_KNIGHT][getFlippedSquare(sq)] = V(ov, ev);
ov = pstOpeningValue(PstBishop[sq], 256);
ev = pstEndgameValue(PstBishop[sq], 256);
pieceSquareBonus[WHITE_BISHOP][sq] =
pieceSquareBonus[BLACK_BISHOP][getFlippedSquare(sq)] = V(ov, ev);
ov = pstOpeningValue(PstRook[sq], 256);
ev = pstEndgameValue(PstRook[sq], 256);
pieceSquareBonus[WHITE_ROOK][sq] =
pieceSquareBonus[BLACK_ROOK][getFlippedSquare(sq)] = V(ov, ev);
ov = pstOpeningValue(PstQueen[sq], 256);
ev = pstEndgameValue(PstQueen[sq], 322);
pieceSquareBonus[WHITE_QUEEN][sq] =
pieceSquareBonus[BLACK_QUEEN][getFlippedSquare(sq)] = V(ov, ev);
ov = pstOpeningValue(PstKing[sq], 247);
ev = pstEndgameValue(PstKing[sq], 244);
pieceSquareBonus[WHITE_KING][sq] =
pieceSquareBonus[BLACK_KING][getFlippedSquare(sq)] = V(ov, ev);
#ifdef LOG_ARRAY
logDebug("V(%d,%d),", ov, ev);
if ((sq + 1) % 8 == 0)
{
logDebug(" /* rank %d */\n", (sq + 1) / 8);
}
#endif
}
#ifdef LOG_ARRAY
getKeyStroke();
#endif
}
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[BLACK] = 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;
const UINT32 signature =
bilateralSignature(*materialSignatureWhite, *materialSignatureBlack);
#ifdef AVOID_TRADES_WITH_TWO_KNIGHTS
int numWhiteNonPawns, numBlackNonPawns;
#endif
getPieceCounters(signature, &numWhiteQueens, &numWhiteRooks,
&numWhiteLightSquareBishops,
&numWhiteDarkSquareBishops, &numWhiteKnights,
&numWhitePawns, &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 =
getSingleMaterialSignature(numWhiteQueens, numWhiteRooks,
numWhiteLightSquareBishops,
numWhiteDarkSquareBishops, numWhiteKnights,
numWhitePawns);
*materialSignatureBlack =
getSingleMaterialSignature(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,
const bool evaluateOppMaterial)
{
int numQueens, numRooks, numLightSquareBishops, numDarkSquareBishops;
int numKnights, numPawns;
int numOppQueens, numOppRooks, numOppLightSquareBishops;
int numOppDarkSquareBishops, numOppKnights, numOppPawns;
int numBishops, numOppBishops;
int numPieces, numOppPieces;
const UINT32 signature =
bilateralSignature(materialSignature, oppMaterialSignature);
if (tradePieces)
{
UINT32 ms = materialSignature, mso = oppMaterialSignature;
SpecialEvalType dummy;
getPieceTradeSignatures(&ms, &mso);
return hasMaterialForMate(ms, mso, &dummy, FALSE, evaluateOppMaterial);
}
getPieceCounters(signature, &numQueens, &numRooks,
&numLightSquareBishops, &numDarkSquareBishops,
&numKnights, &numPawns, &numOppQueens, &numOppRooks,
&numOppLightSquareBishops, &numOppDarkSquareBishops,
&numOppKnights, &numOppPawns);
numBishops = numLightSquareBishops + numDarkSquareBishops;
numOppBishops = numOppLightSquareBishops + numOppDarkSquareBishops;
numPieces = numQueens + numRooks + numBishops + numKnights;
numOppPieces = numOppQueens + numOppRooks + numOppBishops + numOppKnights;
if (evaluateOppMaterial && numPawns == 0)
{
if (numPieces == 1)
{
if (numRooks == 1 && numOppPieces > 0)
{
return FALSE;
}
if (numQueens == 1)
{
if (numOppQueens >= 1 || numOppKnights >= 2)
{
return FALSE;
}
if (numOppPieces >= 2 && numOppRooks >= 1)
{
return FALSE;
}
}
}
else if (numPieces == 2)
{
if (numBishops == 2 &&
numOppQueens + numOppRooks + numOppBishops > 0)
{
return FALSE;
}
if (numBishops == 1 && numKnights == 1 && numOppPieces > 0)
{
return FALSE;
}
}
}
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 (numPawns <= 3 && numPawns >= numOppPawns &&
numOppPawns >= numPawns - 1 && numQueens == 0 &&
numPieces == 1 && numPieces == numOppPieces &&
(numBishops + numKnights == numOppBishops + numOppKnights ||
numRooks == numOppRooks))
{
*specialEval = Se_KpxKpx;
return TRUE;
}
if (numPawns >= 2 && numOppPawns == 0 &&
numQueens == 0 && numOppQueens == 0 &&
numPieces == 1 && numPieces == numOppPieces)
{
if (numBishops == 1 ||
(numKnights == 1 && numOppBishops == 1) ||
(numRooks == 1 && numRooks == numOppRooks))
{
*specialEval = Se_KppxKx;
}
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;
const UINT32 signature =
bilateralSignature(ownMaterialSignature, oppMaterialSignature);
getPieceCounters(signature, &numQueens, &numRooks,
&numLightSquareBishops, &numDarkSquareBishops,
&numKnights, &numPawns, &numOppQueens, &numOppRooks,
&numOppLightSquareBishops, &numOppDarkSquareBishops,
&numOppKnights, &numOppPawns);
ownSignature =
getSingleMaterialSignature(numQueens, numRooks,
numLightSquareBishops,
numDarkSquareBishops, numKnights,
numPawns - 1);
if (numOppRooks > 0)
{
const int oppSignature =
getSingleMaterialSignature(numOppQueens, numOppRooks - 1,
numOppLightSquareBishops,
numOppDarkSquareBishops,
numOppKnights, numOppPawns);
if (hasMaterialForMate(ownSignature, oppSignature, 0, TRUE, FALSE) ==
FALSE)
{
return ROOK;
}
}
if (numOppLightSquareBishops > 0)
{
const int oppSignature =
getSingleMaterialSignature(numOppQueens, numOppRooks,
numOppLightSquareBishops - 1,
numOppDarkSquareBishops,
numOppKnights, numOppPawns);
if (hasMaterialForMate(ownSignature, oppSignature, 0, TRUE, FALSE) ==
FALSE)
{
return BISHOP;
}
}
if (numOppDarkSquareBishops > 0)
{
const int oppSignature =
getSingleMaterialSignature(numOppQueens, numOppRooks,
numOppLightSquareBishops,
numOppDarkSquareBishops - 1,
numOppKnights, numOppPawns);
if (hasMaterialForMate(ownSignature, oppSignature, 0, TRUE, FALSE) ==
FALSE)
{
return BISHOP;
}
}
if (numOppKnights > 0)
{
const int oppSignature =
getSingleMaterialSignature(numOppQueens, numOppRooks,
numOppLightSquareBishops,
numOppDarkSquareBishops,
numOppKnights - 1,
numOppPawns);
if (hasMaterialForMate(ownSignature, oppSignature, 0, TRUE, FALSE) ==
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;
int numOppBishops, numOppMinors, numOppSliders;
bool oppositeColoredBishops;
const UINT32 signature =
bilateralSignature(materialSignature, oppMaterialSignature);
PieceType kamikazePiece = getKamikazePiece(materialSignature,
oppMaterialSignature);
getPieceCounters(signature, &numQueens, &numRooks,
&numLightSquareBishops, &numDarkSquareBishops,
&numKnights, &numPawns, &numOppQueens, &numOppRooks,
&numOppLightSquareBishops, &numOppDarkSquareBishops,
&numOppKnights, &numOppPawns);
numPieces = numQueens + numRooks + numLightSquareBishops +
numDarkSquareBishops + numKnights;
numOppBishops = numOppLightSquareBishops + numOppDarkSquareBishops;
numOppMinors = numOppBishops + numOppKnights;
numOppSliders = numOppQueens + numOppRooks + numOppBishops;
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)
{
const int pawnDiff
= min
(3, abs(numPawns
- numOppPawns
));
return (UINT8) (numPawns > 1 ? 8 + 2 * pawnDiff : 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)
{
const int pawnDiff
= min
(3, abs(numPawns
- numOppPawns
));
return (UINT8) (12 + pawnDiff);
}
}
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;
const UINT32 signature =
bilateralSignature(materialSignature, oppMaterialSignature);
int pieceCountDiff;
getPieceCounters(signature, &numQueens, &numRooks,
&numLightSquareBishops, &numDarkSquareBishops,
&numKnights, &numPawns, &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;
pieceCountDiff = numPieces - numOppPieces;
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 == 2)
{
if (pieceCountDiff <= 1)
{
if (numOppRooks > 0 && numOppRooks >= numRooks)
{
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 testMaterialSignatureNew(const int numWhiteQueens,
const int numWhiteRooks,
const int numWhiteLightSquareBishops,
const int numWhiteDarkSquareBishops,
const int numWhiteKnights,
const int numWhitePawns,
const int numBlackQueens,
const int numBlackRooks,
const int numBlackLightSquareBishops,
const int numBlackDarkSquareBishops,
const int numBlackKnights,
const int numBlackPawns)
{
int calculatedNumWhiteQueens;
int calculatedNumWhiteRooks;
int calculatedNumWhiteLightSquareBishops;
int calculatedNumWhiteDarkSquareBishops;
int calculatedNumWhiteKnights;
int calculatedNumWhitePawns;
int calculatedNumBlackQueens;
int calculatedNumBlackRooks;
int calculatedNumBlackLightSquareBishops;
int calculatedNumBlackDarkSquareBishops;
int calculatedNumBlackKnights;
int calculatedNumBlackPawns;
if (numWhiteRooks <= 2 && numWhiteKnights <= 2 &&
numBlackRooks <= 2 && numBlackKnights <= 2)
{
const UINT32 signature = getMaterialSignature(numWhiteQueens,
numWhiteRooks,
numWhiteLightSquareBishops,
numWhiteDarkSquareBishops,
numWhiteKnights,
numWhitePawns,
numBlackQueens,
numBlackRooks,
numBlackLightSquareBishops,
numBlackDarkSquareBishops,
numBlackKnights,
numBlackPawns);
getPieceCounters(signature,
&calculatedNumWhiteQueens, &calculatedNumWhiteRooks,
&calculatedNumWhiteLightSquareBishops,
&calculatedNumWhiteDarkSquareBishops,
&calculatedNumWhiteKnights,
&calculatedNumWhitePawns, &calculatedNumBlackQueens,
&calculatedNumBlackRooks,
&calculatedNumBlackLightSquareBishops,
&calculatedNumBlackDarkSquareBishops,
&calculatedNumBlackKnights, &calculatedNumBlackPawns);
assert(calculatedNumWhiteQueens
== numWhiteQueens
);
assert(calculatedNumWhiteRooks
== numWhiteRooks
);
assert(calculatedNumWhiteLightSquareBishops
==
numWhiteLightSquareBishops);
assert(calculatedNumWhiteDarkSquareBishops
==
numWhiteDarkSquareBishops);
assert(calculatedNumWhiteKnights
== numWhiteKnights
);
assert(calculatedNumWhitePawns
== numWhitePawns
);
assert(calculatedNumBlackQueens
== numBlackQueens
);
assert(calculatedNumBlackRooks
== numBlackRooks
);
assert(calculatedNumBlackLightSquareBishops
==
numBlackLightSquareBishops);
assert(calculatedNumBlackDarkSquareBishops
==
numBlackDarkSquareBishops);
assert(calculatedNumBlackKnights
== numBlackKnights
);
assert(calculatedNumBlackPawns
== numBlackPawns
);
}
}
static int calculatePhase(UINT32 signature)
{
int numWhiteQueens;
int numWhiteRooks;
int numWhiteLightSquareBishops;
int numWhiteDarkSquareBishops;
int numWhiteKnights;
int numWhitePawns;
int numBlackQueens;
int numBlackRooks;
int numBlackLightSquareBishops;
int numBlackDarkSquareBishops;
int numBlackKnights;
int numBlackPawns;
int whiteWeight, blackWeight, basicPhase;
getPieceCounters(signature,
&numWhiteQueens, &numWhiteRooks,
&numWhiteLightSquareBishops,
&numWhiteDarkSquareBishops,
&numWhiteKnights, &numWhitePawns,
&numBlackQueens, &numBlackRooks,
&numBlackLightSquareBishops,
&numBlackDarkSquareBishops,
&numBlackKnights, &numBlackPawns);
whiteWeight =
9 * numWhiteQueens + 5 * numWhiteRooks +
3 * numWhiteLightSquareBishops + 3 * numWhiteDarkSquareBishops +
3 * numWhiteKnights;
blackWeight =
9 * numBlackQueens + 5 * numBlackRooks +
3 * numBlackLightSquareBishops + 3 * numBlackDarkSquareBishops +
3 * numBlackKnights;
basicPhase = (whiteWeight + blackWeight <= PIECE_WEIGHT_ENDGAME ?
PHASE_MAX : max(0, PHASE_MAX - whiteWeight - blackWeight));
return (basicPhase * 256 + (PHASE_MAX / 2)) / PHASE_MAX;
}
static INT32 calculateMaterialBalance(UINT32 signature)
{
const INT32 bishopPairBonus =
V(VALUE_BISHOP_PAIR_OPENING, VALUE_BISHOP_PAIR_ENDGAME);
static const INT32 knightBonus = V(0, 5);
static const INT32 rookMalus = V(5, 0);
static const INT32 rookPairMalus = V(17, 25);
static const INT32 rookQueenMalus = V(8, 12);
static const INT32 pieceUpBonus =
V(DEFAULTVALUE_PIECE_UP_OPENING, DEFAULTVALUE_PIECE_UP_ENDGAME);
int numWhiteQueens;
int numWhiteRooks;
int numWhiteLightSquareBishops;
int numWhiteDarkSquareBishops;
int numWhiteKnights;
int numWhitePawns;
int numBlackQueens;
int numBlackRooks;
int numBlackLightSquareBishops;
int numBlackDarkSquareBishops;
int numBlackKnights;
int numBlackPawns;
int pawnCountWhite, pawnCountBlack;
int knightSaldo, rookSaldo, pieceCountSaldo;
INT32 balance = 0;
getPieceCounters(signature,
&numWhiteQueens, &numWhiteRooks,
&numWhiteLightSquareBishops,
&numWhiteDarkSquareBishops,
&numWhiteKnights,
&numWhitePawns, &numBlackQueens,
&numBlackRooks,
&numBlackLightSquareBishops,
&numBlackDarkSquareBishops,
&numBlackKnights, &numBlackPawns);
pawnCountWhite = numWhitePawns - 5;
pawnCountBlack = numBlackPawns - 5;
knightSaldo = pawnCountWhite * numWhiteKnights -
pawnCountBlack * numBlackKnights;
rookSaldo = pawnCountWhite * numWhiteRooks -
pawnCountBlack * numBlackRooks;
pieceCountSaldo =
(numWhiteLightSquareBishops +
numWhiteDarkSquareBishops + numWhiteKnights) -
(numBlackLightSquareBishops +
numBlackDarkSquareBishops + numBlackKnights);
if (numWhiteLightSquareBishops > 0 && numWhiteDarkSquareBishops > 0)
{
balance += bishopPairBonus;
}
if (numBlackLightSquareBishops > 0 && numBlackDarkSquareBishops > 0)
{
balance -= bishopPairBonus;
}
balance += knightSaldo * knightBonus - rookSaldo * rookMalus;
if (numWhiteRooks >= 2)
{
balance -= rookPairMalus + rookQueenMalus;
}
else if (numWhiteRooks + numWhiteQueens >= 2)
{
balance -= rookQueenMalus;
}
if (numBlackRooks >= 2)
{
balance += rookPairMalus + rookQueenMalus;
}
else if (numBlackRooks + numBlackQueens >= 2)
{
balance += rookQueenMalus;
}
if (pieceCountSaldo > 0)
{
balance += pieceUpBonus;
}
else if (pieceCountSaldo < 0)
{
balance -= pieceUpBonus;
}
return balance;
}
static void initializeMaterialInfoTableCore1(const UINT32 signatureWhite,
const UINT32 signatureBlack)
{
const UINT32 signature =
bilateralSignature(signatureWhite, signatureBlack);
SpecialEvalType specialEvalWhite = Se_None;
SpecialEvalType specialEvalBlack = Se_None;
const bool whiteMateMat =
hasMaterialForMate(signatureWhite, signatureBlack, &specialEvalWhite,
FALSE, FALSE);
const bool blackMateMat =
hasMaterialForMate(signatureBlack, signatureWhite, &specialEvalBlack,
FALSE, FALSE);
int numWhiteQueens, numWhiteRooks, numWhiteLightSquareBishops;
int numWhiteDarkSquareBishops, numWhiteKnights, numWhitePawns;
int numBlackQueens, numBlackRooks, numBlackLightSquareBishops;
int numBlackDarkSquareBishops, numBlackKnights, numBlackPawns;
/*int criticalCase = FALSE; */
getPieceCounters(signature, &numWhiteQueens, &numWhiteRooks,
&numWhiteLightSquareBishops,
&numWhiteDarkSquareBishops, &numWhiteKnights,
&numWhitePawns, &numBlackQueens, &numBlackRooks,
&numBlackLightSquareBishops,
&numBlackDarkSquareBishops, &numBlackKnights,
&numBlackPawns);
testMaterialSignatureNew(numWhiteQueens,
numWhiteRooks,
numWhiteLightSquareBishops,
numWhiteDarkSquareBishops,
numWhiteKnights,
numWhitePawns,
numBlackQueens,
numBlackRooks,
numBlackLightSquareBishops,
numBlackDarkSquareBishops,
numBlackKnights, numBlackPawns);
materialInfo[signature].chancesWhite = (whiteMateMat == FALSE ? 0 : 16);
materialInfo[signature].chancesBlack = (blackMateMat == FALSE ? 0 : 16);
materialInfo[signature].specialEvalWhite = specialEvalWhite;
materialInfo[signature].specialEvalBlack = specialEvalBlack;
/*if (numWhiteQueens == 0 && numWhiteRooks == 0 &&
numWhiteLightSquareBishops == 0 &&
numWhiteDarkSquareBishops == 0 &&
numWhiteKnights == 0 && numWhitePawns == 1 &&
numBlackQueens == 0 && numBlackRooks == 0 &&
numBlackLightSquareBishops == 0 &&
numBlackDarkSquareBishops == 1 &&
numBlackKnights == 0 && numBlackPawns == 0)
{
criticalCase = TRUE;
} */
if (whiteMateMat != FALSE)
{
if (numWhitePawns == 0)
{
if (hasMaterialForMate(signatureWhite, signatureBlack, 0,
TRUE, TRUE) == FALSE)
{
materialInfo[signature].chancesWhite = 1;
}
else
{
materialInfo[signature].chancesWhite =
getWinningChancesWithoutPawn(signatureWhite, signatureBlack);
}
}
else
{
materialInfo[signature].chancesWhite =
getWinningChances(signatureWhite, signatureBlack);
}
}
if (blackMateMat != FALSE)
{
if (numBlackPawns == 0)
{
if (hasMaterialForMate(signatureBlack, signatureWhite, 0,
TRUE, TRUE) == FALSE)
{
materialInfo[signature].chancesBlack = 1;
}
else
{
materialInfo[signature].chancesBlack =
getWinningChancesWithoutPawn(signatureBlack, signatureWhite);
}
}
else
{
materialInfo[signature].chancesBlack =
getWinningChances(signatureBlack, signatureWhite);
}
/*if (criticalCase){
logDebug("wc=%d",materialInfo[signature].chancesBlack);
getKeyStroke();
materialInfo[signature].chancesBlack=0;
} */
}
materialInfo[signature].materialBalance =
calculateMaterialBalance(signature);
materialInfo[signature].phaseIndex = calculatePhase(signature);
}
static void initializeMaterialInfoTable()
{
int whiteSignature, blackSignature;
for (whiteSignature = 0; whiteSignature < 648; whiteSignature++)
{
for (blackSignature = 0; blackSignature < 648; blackSignature++)
{
initializeMaterialInfoTableCore1(whiteSignature, blackSignature);
}
}
}
/* #define DEBUG_KSTABLE 1 */
static int initializeKingSafetyTable()
{
const double MIN_SLOPE = 1.0;
const double MAX_SLOPE = 7.0;
const double MAX_VALUE = 1347.0;
double t = 0.0 - MIN_SLOPE;
int i;
for (i = 0; i < KING_SAFETY_MALUS_DIM; i++)
{
t = max(t + MIN_SLOPE,
min(MAX_VALUE, min(0.025 * i * i, t + MAX_SLOPE)));
KING_SAFETY_MALUS[i] = (int)((156 * t) / 256); // Pierre-Marie Baty -- added type cast
#ifdef DEBUG_KSTABLE
logDebug("ksm(%d)=%d\n", i, KING_SAFETY_MALUS[i]);
#endif
}
#ifdef DEBUG_KSTABLE
getKeyStroke();
#endif
return 0;
}
int getLogarithmicValue(const double minValue, const double maxValue,
const double numValues, const double valueCount)
{
const double offset = 1.0;
const double factor
= (maxValue
- minValue
) / log(numValues
+ offset
);
const double value
= factor
* log(valueCount
+ offset
) + minValue
;
return (int) value;
}
double wmbv(const double baseValue)
{
return baseValue * 1.075;
}
/* #define LOG_MOBILILITY_VALUES */
static void initializeMoveBonusValue()
{
int i, limit;
limit = MAX_MOVES_QUEEN;
for (i = 0; i <= limit; i++)
{
const int opValue =
getLogarithmicValue(wmbv(-21.0), wmbv(13.0), limit, i);
const int egValue =
getLogarithmicValue(wmbv(-20.0), wmbv(21.0), limit, i);
QueenMobilityBonus[i] = V(opValue, egValue);
#ifdef LOG_MOBILILITY_VALUES
logDebug("mQ(%d)=(%d/%d)\n", i, getOpeningValue(QueenMobilityBonus[i]),
getEndgameValue(QueenMobilityBonus[i]));
#endif
}
#ifdef LOG_MOBILILITY_VALUES
logDebug("\n");
#endif
limit = MAX_MOVES_ROOK;
for (i = 0; i <= limit; i++)
{
const int opValue =
getLogarithmicValue(wmbv(-24.0), wmbv(19.0), limit, i);
const int egValue =
getLogarithmicValue(wmbv(-27.0), wmbv(62.0), limit, i);
RookMobilityBonus[i] = V(opValue, egValue);
#ifdef LOG_MOBILILITY_VALUES
logDebug("mR(%d)=(%d/%d)\n", i, getOpeningValue(RookMobilityBonus[i]),
getEndgameValue(RookMobilityBonus[i]));
#endif
}
#ifdef LOG_MOBILILITY_VALUES
logDebug("\n");
#endif
limit = MAX_MOVES_BISHOP;
for (i = 0; i <= limit; i++)
{
const int opValue =
getLogarithmicValue(wmbv(-26.0), wmbv(43.0), limit, i);
const int egValue =
getLogarithmicValue(wmbv(-24.0), wmbv(40.0), limit, i);
BishopMobilityBonus[i] = V(opValue, egValue);
#ifdef LOG_MOBILILITY_VALUES
logDebug("mB(%d)=(%d/%d)\n", i, getOpeningValue(BishopMobilityBonus[i]),
getEndgameValue(BishopMobilityBonus[i]));
#endif
}
#ifdef LOG_MOBILILITY_VALUES
logDebug("\n");
#endif
limit = MAX_MOVES_KNIGHT;
for (i = 0; i <= limit; i++)
{
const int opValue =
getLogarithmicValue(wmbv(-33.0), wmbv(22.0), limit, i);
const int egValue =
getLogarithmicValue(wmbv(-25.0), wmbv(17.0), limit, i);
KnightMobilityBonus[i] = V(opValue, egValue);
#ifdef LOG_MOBILILITY_VALUES
logDebug("mN(%d)=(%d/%d)\n", i, getOpeningValue(KnightMobilityBonus[i]),
getEndgameValue(KnightMobilityBonus[i]));
#endif
}
#ifdef LOG_MOBILILITY_VALUES
getKeyStroke();
#endif
}
static INT32 PPAB(const int opv, const int egv)
{
const int wopv = (opv * 125) / 256;
const int wegv = (egv * 133) / 256;
return V(wopv, wegv);
}
static void initializePawnChainBonus()
{
const int bonusPerFile[8] = { 1, 3, 3, 4, 4, 3, 3, 1 };
Square square;
ITERATE(square)
{
const File squarefile = file(square);
const Rank squarerank = rank(square);
const int bonus = squarerank * (squarerank - 1) * (squarerank - 2) +
bonusPerFile[squarefile] * (squarerank / 2 + 1);
PAWN_CHAIN_BONUS[square] = V((bonus * CHAIN_BONUS_WEIGHT_OP) / 256,
(bonus * CHAIN_BONUS_WEIGHT_EG) / 256);
}
}
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];
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;
}
ITERATE(kingSquare)
{
kingRealm[WHITE][square][kingSquare] =
kingRealm[BLACK][square][kingSquare] = EMPTY_BITBOARD;
}
kingTrapsRook[WHITE][square] = kingTrapsRook[BLACK][square] =
EMPTY_BITBOARD;
}
setSquare(kingTrapsRook[WHITE][F1], H1); /* a king on f1 traps a rook on h1 ... */
setSquare(kingTrapsRook[WHITE][F1], G1);
setSquare(kingTrapsRook[WHITE][F1], H2);
setSquare(kingTrapsRook[WHITE][F1], G2);
setSquare(kingTrapsRook[WHITE][G1], H1);
setSquare(kingTrapsRook[WHITE][G1], H2);
setSquare(kingTrapsRook[WHITE][G1], G2);
setSquare(kingTrapsRook[WHITE][G2], H2);
setSquare(kingTrapsRook[WHITE][C1], A1);
setSquare(kingTrapsRook[WHITE][C1], B1);
setSquare(kingTrapsRook[WHITE][C1], A2);
setSquare(kingTrapsRook[WHITE][C1], B2);
setSquare(kingTrapsRook[WHITE][B1], A1);
setSquare(kingTrapsRook[WHITE][B1], A2);
setSquare(kingTrapsRook[WHITE][B1], B2);
setSquare(kingTrapsRook[WHITE][B2], A2);
setSquare(kingTrapsRook[BLACK][F8], H8);
setSquare(kingTrapsRook[BLACK][F8], G8);
setSquare(kingTrapsRook[BLACK][F8], H7);
setSquare(kingTrapsRook[BLACK][F8], G7);
setSquare(kingTrapsRook[BLACK][G8], H8);
setSquare(kingTrapsRook[BLACK][G8], H7);
setSquare(kingTrapsRook[BLACK][G8], G7);
setSquare(kingTrapsRook[BLACK][G7], H7);
setSquare(kingTrapsRook[BLACK][C8], A8);
setSquare(kingTrapsRook[BLACK][C8], B8);
setSquare(kingTrapsRook[BLACK][C8], A7);
setSquare(kingTrapsRook[BLACK][C8], B7);
setSquare(kingTrapsRook[BLACK][B8], A8);
setSquare(kingTrapsRook[BLACK][B8], A7);
setSquare(kingTrapsRook[BLACK][B8], B7);
setSquare(kingTrapsRook[BLACK][B7], A7);
ITERATE(square)
{
const File squarefile = file(square);
const Rank 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 File kingsquarefile = file(kingsquare);
const Rank kingsquarerank = rank(kingsquare);
Square targetSquare;
if (kingsquarerank >= squarerank &&
distance(square, kingsquare) <= (int) (7 - squarerank))
{
setSquare(passedPawnRectangle[WHITE][square], kingsquare);
}
if (kingsquarerank <= squarerank &&
distance(square, kingsquare) <= (int) 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 <= (Rank) (squarerank + 1))
{
setSquare(kingRealm[WHITE][square][kingsquare],
targetSquare);
}
if (targetrank >= (Rank) (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 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();
*/
transposeMatrix(BONUS_KNIGHT_OUTPOST_HR, BONUS_KNIGHT_OUTPOST);
transposeMatrix(BONUS_BISHOP_OUTPOST_HR, BONUS_BISHOP_OUTPOST);
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;
homeland[WHITE] = (squaresOfRank[RANK_2] | squaresOfRank[RANK_3] |
squaresOfRank[RANK_4]) &
(squaresOfFile[FILE_C] | squaresOfFile[FILE_D] |
squaresOfFile[FILE_E] | squaresOfFile[FILE_F]);
homeland[BLACK] = getFlippedBitboard(homeland[WHITE]);
for (i = 0; i < 16; i++)
{
int j;
for (j = 0; j < 16; j++)
{
piecePieceAttackBonus[i][j] = 0;
}
}
piecePieceAttackBonus[WHITE_PAWN][BLACK_KNIGHT] = PPAB(56, 70);
piecePieceAttackBonus[WHITE_PAWN][BLACK_BISHOP] = PPAB(56, 70);
piecePieceAttackBonus[WHITE_PAWN][BLACK_ROOK] = PPAB(76, 99);
piecePieceAttackBonus[WHITE_PAWN][BLACK_QUEEN] = PPAB(86, 118);
piecePieceAttackBonus[WHITE_KNIGHT][BLACK_PAWN] = PPAB(7, 39);
piecePieceAttackBonus[WHITE_KNIGHT][BLACK_BISHOP] = PPAB(24, 49);
piecePieceAttackBonus[WHITE_KNIGHT][BLACK_ROOK] = PPAB(41, 100);
piecePieceAttackBonus[WHITE_KNIGHT][BLACK_QUEEN] = PPAB(41, 100);
piecePieceAttackBonus[WHITE_BISHOP][BLACK_PAWN] = PPAB(7, 39);
piecePieceAttackBonus[WHITE_BISHOP][BLACK_KNIGHT] = PPAB(24, 49);
piecePieceAttackBonus[WHITE_BISHOP][BLACK_ROOK] = PPAB(41, 100);
piecePieceAttackBonus[WHITE_BISHOP][BLACK_QUEEN] = PPAB(41, 100);
piecePieceAttackBonus[WHITE_ROOK][BLACK_PAWN] = PPAB(0, 22);
piecePieceAttackBonus[WHITE_ROOK][BLACK_KNIGHT] = PPAB(15, 49);
piecePieceAttackBonus[WHITE_ROOK][BLACK_BISHOP] = PPAB(15, 49);
piecePieceAttackBonus[WHITE_ROOK][BLACK_QUEEN] = PPAB(24, 49);
piecePieceAttackBonus[WHITE_QUEEN][BLACK_PAWN] = PPAB(15, 39);
piecePieceAttackBonus[WHITE_QUEEN][BLACK_KNIGHT] = PPAB(15, 39);
piecePieceAttackBonus[WHITE_QUEEN][BLACK_BISHOP] = PPAB(15, 39);
piecePieceAttackBonus[WHITE_QUEEN][BLACK_ROOK] = PPAB(15, 39);
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);
piecePieceAttackBonus[i][j] =
piecePieceAttackBonus[attacker][attackedPiece];
}
}
}
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();
initializeMoveBonusValue();
initializePawnChainBonus();
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->hashKey);
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 testKingPawnDistanceCalculation()
{
#ifndef NDEBUG
Bitboard whitePawns = minValue[B4] | minValue[G7], blackPawns =
minValue[E3];
Position position;
position.king[WHITE] = B2;
position.king[BLACK] = G6;
position.piecesOfType[WHITE_PAWN] = whitePawns;
position.piecesOfType[BLACK_PAWN] = blackPawns;
position.piece[B4] = position.piece[G7] = WHITE_PAWN;
position.piece[E3] = BLACK_PAWN;
assert(getKingPawnDistance
(&position
, WHITE
) == 2 * KP_DISTANCE_WEIGHT
);
assert(getKingPawnDistance
(&position
, BLACK
) == KP_DISTANCE_WEIGHT
);
position.king[WHITE] = B7;
assert(getKingPawnDistance
(&position
, WHITE
) ==
3 * KP_REDUCED_DISTANCE_WEIGHT);
position.king[WHITE] = E1;
assert(getKingPawnDistance
(&position
, WHITE
) ==
2 * KP_REDUCED_DISTANCE_WEIGHT);
position.king[BLACK] = E5;
assert(getKingPawnDistance
(&position
, BLACK
) == 2 * KP_DISTANCE_WEIGHT
);
#endif
return 0;
}
#ifndef NDEBUG
static void initializePawnHashtable(PawnHashInfo * pawnHashtable)
{
int i;
for (i = 0; i < PAWN_HASHTABLE_SIZE; i++)
{
pawnHashtable[i].hashKey = 0;
}
}
static void initializeKingsafetyHashtable(KingSafetyHashInfo *
kingsafetyHashtable)
{
int i;
for (i = 0; i < KINGSAFETY_HASHTABLE_SIZE; i++)
{
kingsafetyHashtable[i].hashKey = 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);
variation.pawnHashtable = localPawnHashtable;
variation.kingsafetyHashtable = localKingSafetyHashtable;
initializePawnHashtable(variation.pawnHashtable);
initializeKingsafetyHashtable(variation.kingsafetyHashtable);
assert(flipTest
(&variation.
singlePosition, variation.
pawnHashtable,
variation.kingsafetyHashtable) != FALSE);
initializeVariation(&variation, fen2);
assert(flipTest
(&variation.
singlePosition, variation.
pawnHashtable,
variation.kingsafetyHashtable) != FALSE);
initializeVariation(&variation, fen3);
assert(flipTest
(&variation.
singlePosition, variation.
pawnHashtable,
variation.kingsafetyHashtable) != FALSE);
initializeVariation(&variation, fen4);
assert(flipTest
(&variation.
singlePosition, variation.
pawnHashtable,
variation.kingsafetyHashtable) != FALSE);
initializeVariation(&variation, fen5);
assert(flipTest
(&variation.
singlePosition, variation.
pawnHashtable,
variation.kingsafetyHashtable) != FALSE);
return 0;
}
#endif
int testModuleEvaluation()
{
int result;
if ((result = testPawnInfoGeneration()) != 0)
{
return result;
}
if ((result = testWeakPawnDetection()) != 0)
{
return result;
}
if ((result = testBaseInitialization()) != 0)
{
return result;
}
if ((result = testKingPawnDistanceCalculation()) != 0)
{
return result;
}
#ifndef NDEBUG
if ((result = testFlippings()) != 0)
{
return result;
}
#endif
return 0;
}