/*
Protector -- a UCI chess engine
Copyright (C) 2009-2010 Raimund Heid (Raimund_Heid@yahoo.com)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <math.h>
#include "movegeneration.h"
#include "evaluation.h"
#include "fen.h"
#include "io.h"
#include "hash.h"
#include "evaluation.h"
#define PAWN_FOR_KNIGHT basicValue[BLACK_PAWN] - basicValue[WHITE_KNIGHT]
#define PAWN_FOR_BISHOP basicValue[BLACK_PAWN] - basicValue[WHITE_BISHOP]
int pieceOrder[16], promotionPieceValue[16];
MovegenerationStage moveGenerationStage[100];
int MG_SCHEME_STANDARD, MG_SCHEME_ESCAPE, MG_SCHEME_CHECKS,
MG_SCHEME_QUIESCENCE_WITH_CHECKS, MG_SCHEME_QUIESCENCE, MG_SCHEME_CAPTURES;
const Move NO_MOVE = (B4 << 6) | A1; /* (a1-b4 is always an illegal move) */
const Move NULLMOVE = 0;
const int VALUEOFFSET_PROMOTION_TO_QUEEN = 4000;
const int VALUEOFFSET_HISTORY_MOVE = 24000;
const int VALUEOFFSET_BAD_MOVE = 28000;
/**
* Register the specified killermove.
*/
void registerKillerMove(PlyInfo * plyInfo, Move killerMove)
{
if (plyInfo->killerMove1 != killerMove)
{
plyInfo->killerMove2 = plyInfo->killerMove1;
plyInfo->killerMove1 = killerMove;
}
}
/**
* Test if the passive king can be captured.
*/
bool passiveKingIsSafe(Position * position)
{
return (bool)
(getDirectAttackers(position,
position->king[opponent(position->activeColor)],
position->activeColor,
position->allPieces) == EMPTY_BITBOARD);
}
/**
* Test if the active king is safe (i.e. not in check).
*/
bool activeKingIsSafe(Position * position)
{
return (bool)
(getDirectAttackers(position,
position->king[position->activeColor],
opponent(position->activeColor),
position->allPieces) == EMPTY_BITBOARD);
}
int seeMove(Position * position, const Move move)
{
const Square to = getToSquare(move);
const Piece targetPiece = position->piece[to];
const Bitboard all = position->allPieces;
const Square enPassantSquare = position->enPassantSquare;
int result;
Bitboard attackers[2];
attackers[WHITE] =
getDirectAttackers(position, to, WHITE, position->allPieces);
attackers[BLACK] =
getDirectAttackers(position, to, BLACK, position->allPieces);
result = seeMoveRec(position, move, attackers, VALUE_MATED);
position->enPassantSquare = enPassantSquare;
position->allPieces = all;
position->piece[to] = targetPiece;
return result;
}
/**
* Compare the value of the two specified moves.
*/
int compareMoves(const void *move1, const void *move2)
{
return getMoveValue(*((Move *) move2)) - getMoveValue(*((Move *) move1));
}
/**
* Sort the specified movelist.
*/
void sortMoves(Movelist * movelist)
{
qsort(&(movelist
->moves
[0]), movelist
->numberOfMoves
,
sizeof(Move), compareMoves);
}
/**
* Initialize the specified movelist for quiescence move generation.
*/
void initQuiescenceMovelist(Movelist * movelist,
Position * position, PlyInfo * plyInfo,
UINT16 * historyValue, const Move hashMove,
const int restDepth, const bool check)
{
movelist->position = position;
movelist->plyInfo = plyInfo;
movelist->historyValue = historyValue;
movelist->nextMove = movelist->numberOfPieces = 0;
movelist->numberOfMoves = movelist->numberOfBadCaptures = 0;
movelist->hashMove = hashMove;
movelist->killer1Executed = movelist->killer2Executed = FALSE;
movelist->killer3Executed = movelist->killer4Executed = FALSE;
movelist->killer5Executed = movelist->killer6Executed = FALSE;
if (check)
{
movelist->currentStage = MG_SCHEME_ESCAPE;
}
else
{
movelist->currentStage =
(restDepth >= 0 ?
MG_SCHEME_QUIESCENCE_WITH_CHECKS : MG_SCHEME_QUIESCENCE);
}
if (hashMove != NO_MOVE)
{
movelist->moves[movelist->numberOfMoves++] = hashMove;
}
}
/**
* Initialize the specified movelist for capture move generation.
*/
void initCaptureMovelist(Movelist * movelist,
Position * position, PlyInfo * plyInfo,
UINT16 * historyValue, const Move hashMove,
const bool check)
{
movelist->position = position;
movelist->plyInfo = plyInfo;
movelist->historyValue = historyValue;
movelist->nextMove = movelist->numberOfPieces = 0;
movelist->numberOfMoves = movelist->numberOfBadCaptures = 0;
movelist->hashMove = hashMove;
movelist->killer1Executed = movelist->killer2Executed = FALSE;
movelist->killer3Executed = movelist->killer4Executed = FALSE;
movelist->killer5Executed = movelist->killer6Executed = FALSE;
if (check)
{
movelist->currentStage = MG_SCHEME_ESCAPE;
}
else
{
movelist->currentStage = MGS_GOOD_CAPTURES;
}
if (hashMove != NO_MOVE)
{
movelist->moves[movelist->numberOfMoves++] = hashMove;
}
}
/**
* Initialize the specified movelist for standard move generation.
*/
void initStandardMovelist(Movelist * movelist, Position * position,
PlyInfo * plyInfo, UINT16 * historyValue,
const Move hashMove, const bool check)
{
movelist->position = position;
movelist->plyInfo = plyInfo;
movelist->historyValue = historyValue;
movelist->nextMove = movelist->numberOfPieces = 0;
movelist->numberOfMoves = movelist->numberOfBadCaptures = 0;
movelist->hashMove = hashMove;
if (check)
{
movelist->currentStage = MG_SCHEME_ESCAPE;
}
else
{
movelist->currentStage = MG_SCHEME_STANDARD;
if (hashMove != NO_MOVE)
{
movelist->moves[movelist->numberOfMoves++] = hashMove;
}
}
}
/**
* Initialize the specified movelist for check move generation.
*/
void initCheckMovelist(Movelist * movelist, Position * position,
UINT16 * historyValue)
{
movelist->position = position;
movelist->plyInfo = 0;
movelist->historyValue = historyValue;
movelist->nextMove = movelist->numberOfPieces = 0;
movelist->numberOfMoves = movelist->numberOfBadCaptures = 0;
movelist->hashMove = NO_MOVE;
movelist->currentStage = MG_SCHEME_CHECKS;
movelist->killer1Executed = movelist->killer2Executed = FALSE;
movelist->killer3Executed = movelist->killer4Executed = FALSE;
movelist->killer5Executed = movelist->killer6Executed = FALSE;
}
/**
* Initialize the specified movelist for move insertion.
*/
void initMovelist(Movelist * movelist, Position * position)
{
movelist->position = position;
movelist->plyInfo = 0;
movelist->historyValue = 0;
movelist->nextMove = movelist->numberOfPieces = 0;
movelist->numberOfMoves = movelist->numberOfBadCaptures = 0;
movelist->hashMove = NO_MOVE;
movelist->currentStage = MG_SCHEME_CHECKS;
movelist->killer1Executed = movelist->killer2Executed = FALSE;
movelist->killer3Executed = movelist->killer4Executed = FALSE;
movelist->killer5Executed = movelist->killer6Executed = FALSE;
}
Move getNextMove(Movelist * movelist)
{
do
{
if (movelist->nextMove < movelist->numberOfMoves)
{
switch (moveGenerationStage[movelist->currentStage])
{
case MGS_GOOD_CAPTURES_AND_PROMOTIONS:
case MGS_GOOD_CAPTURES_AND_PROMOTIONS_PURE:
case MGS_GOOD_CAPTURES:
{
const Move move = movelist->moves[movelist->nextMove++];
if (basicValue[movelist->position->piece[getFromSquare(move)]]
> basicValue[movelist->position->piece[getToSquare(move)]]
&& seeMove(movelist->position, move) < 0)
{
movelist->badCaptures[movelist->numberOfBadCaptures++] =
move;
continue;
}
return move;
}
case MGS_SAFE_CHECKS:
{
const Move move = movelist->moves[movelist->nextMove++];
if (seeMove(movelist->position, move) < 0)
{
continue;
}
return move;
}
default:
return movelist->moves[movelist->nextMove++];
}
}
else
{
Position *position;
Move killer1, killer2, killer3, killer4, killer5, killer6;
switch (moveGenerationStage[++movelist->currentStage])
{
case MGS_GOOD_CAPTURES_AND_PROMOTIONS:
generateSpecialMoves(movelist);
break;
case MGS_GOOD_CAPTURES_AND_PROMOTIONS_PURE:
generateSpecialMovesPure(movelist);
break;
case MGS_GOOD_CAPTURES:
generateCaptures(movelist);
break;
case MGS_KILLER_MOVES:
movelist->killer1Executed = movelist->killer2Executed = FALSE;
movelist->killer3Executed = movelist->killer4Executed = FALSE;
movelist->numberOfMoves = movelist->nextMove = 0;
position = movelist->position;
killer1 = movelist->plyInfo->killerMove1;
killer2 = movelist->plyInfo->killerMove2;
killer3 = movelist->plyInfo->killerMove3;
killer4 = movelist->plyInfo->killerMove4;
killer5 = movelist->plyInfo->killerMove5;
killer6 = movelist->plyInfo->killerMove6;
if (moveIsPseudoLegal(position, killer1) &&
position->piece[getToSquare(killer1)] == NO_PIECE &&
position->piece[getFromSquare(killer1)] ==
(Piece) getMoveValue(killer1) &&
(pieceType(position->piece[getFromSquare(killer1)]) != PAWN ||
getToSquare(killer1) != position->enPassantSquare) &&
movesAreEqual(killer1, movelist->hashMove) == FALSE)
{
setMoveValue(&killer1, 6);
movelist->moves[movelist->numberOfMoves++] = killer1;
movelist->killer1Executed = TRUE;
}
if (moveIsPseudoLegal(position, killer2) &&
position->piece[getToSquare(killer2)] == NO_PIECE &&
position->piece[getFromSquare(killer2)] ==
(Piece) getMoveValue(killer2) &&
(pieceType(position->piece[getFromSquare(killer2)]) != PAWN ||
getToSquare(killer2) != position->enPassantSquare) &&
movesAreEqual(killer2, movelist->hashMove) == FALSE)
{
setMoveValue(&killer2, 5);
movelist->moves[movelist->numberOfMoves++] = killer2;
movelist->killer2Executed = TRUE;
}
if (moveIsPseudoLegal(position, killer3) &&
position->piece[getToSquare(killer3)] == NO_PIECE &&
position->piece[getFromSquare(killer3)] ==
(Piece) getMoveValue(killer3) &&
(pieceType(position->piece[getFromSquare(killer3)]) != PAWN ||
getToSquare(killer3) != position->enPassantSquare) &&
movesAreEqual(killer3, movelist->hashMove) == FALSE &&
movesAreEqual(killer3, killer1) == FALSE &&
movesAreEqual(killer3, killer2) == FALSE)
{
setMoveValue(&killer3, 4);
movelist->moves[movelist->numberOfMoves++] = killer3;
movelist->killer3Executed = TRUE;
}
if (moveIsPseudoLegal(position, killer4) &&
position->piece[getToSquare(killer4)] == NO_PIECE &&
position->piece[getFromSquare(killer4)] ==
(Piece) getMoveValue(killer4) &&
(pieceType(position->piece[getFromSquare(killer4)]) != PAWN ||
getToSquare(killer4) != position->enPassantSquare) &&
movesAreEqual(killer4, movelist->hashMove) == FALSE &&
movesAreEqual(killer4, killer1) == FALSE &&
movesAreEqual(killer4, killer2) == FALSE)
{
setMoveValue(&killer4, 3);
movelist->moves[movelist->numberOfMoves++] = killer4;
movelist->killer4Executed = TRUE;
}
if (moveIsPseudoLegal(position, killer5) &&
position->piece[getToSquare(killer5)] == NO_PIECE &&
position->piece[getFromSquare(killer5)] ==
(Piece) getMoveValue(killer5) &&
(pieceType(position->piece[getFromSquare(killer5)]) != PAWN ||
getToSquare(killer5) != position->enPassantSquare) &&
movesAreEqual(killer5, movelist->hashMove) == FALSE &&
movesAreEqual(killer5, killer1) == FALSE &&
movesAreEqual(killer5, killer2) == FALSE &&
movesAreEqual(killer5, killer3) == FALSE &&
movesAreEqual(killer5, killer4) == FALSE)
{
setMoveValue(&killer5, 2);
movelist->moves[movelist->numberOfMoves++] = killer5;
movelist->killer5Executed = TRUE;
}
if (moveIsPseudoLegal(position, killer6) &&
position->piece[getToSquare(killer6)] == NO_PIECE &&
position->piece[getFromSquare(killer6)] ==
(Piece) getMoveValue(killer6) &&
(pieceType(position->piece[getFromSquare(killer6)]) != PAWN ||
getToSquare(killer6) != position->enPassantSquare) &&
movesAreEqual(killer6, movelist->hashMove) == FALSE &&
movesAreEqual(killer6, killer1) == FALSE &&
movesAreEqual(killer6, killer2) == FALSE &&
movesAreEqual(killer6, killer3) == FALSE &&
movesAreEqual(killer6, killer4) == FALSE)
{
setMoveValue(&killer6, 1);
movelist->moves[movelist->numberOfMoves++] = killer6;
movelist->killer6Executed = TRUE;
}
break;
case MGS_REST:
generateRestMoves(movelist);
break;
case MGS_BAD_CAPTURES:
movelist->numberOfMoves = movelist->numberOfBadCaptures;
movelist->nextMove = 0;
&movelist->badCaptures[0],
movelist->numberOfMoves * sizeof(Move));
break;
case MGS_ESCAPES:
generateEscapes(movelist);
break;
case MGS_SAFE_CHECKS:
generateChecks(movelist, FALSE);
break;
case MGS_CHECKS:
generateChecks(movelist, TRUE);
break;
case MGS_DANGEROUS_PAWN_ADVANCES:
generateDangerousPawnAdvances(movelist);
break;
default:
break;
}
}
}
while (moveGenerationStage[movelist->currentStage] != MGS_FINISHED);
return NO_MOVE;
}
bool moveIsPseudoLegal(const Position * position, const Move move)
{
const Square from = getFromSquare(move), to = getToSquare(move);
const Piece newPiece = getNewPiece(move);
Piece piece;
Bitboard moves;
if (squareIsValid(from) == FALSE || squareIsValid(to) == FALSE ||
(piece = position->piece[from]) == NO_PIECE ||
pieceColor(piece) != position->activeColor)
{
return FALSE;
}
if (pieceType(position->piece[from]) == PAWN &&
colorRank(position->activeColor, from) == RANK_7)
{
if (newPiece != WHITE_QUEEN && newPiece != WHITE_ROOK &&
newPiece != WHITE_BISHOP && newPiece != WHITE_KNIGHT)
{
return FALSE;
}
}
else
{
if (newPiece != NO_PIECE)
{
return FALSE;
}
}
if (pieceType(position->piece[from]) == PAWN &&
position->enPassantSquare != NO_SQUARE)
{
Bitboard allPieces = position->allPieces |
minValue[position->enPassantSquare];
moves = getMoves(from, piece, allPieces);
}
else
{
moves = getMoves(from, piece, position->allPieces);
}
excludeSquares(moves, position->piecesOfColor[position->activeColor]);
if (pieceType(piece) == KING &&
hasCastlings(position->activeColor, position->castlingRights))
{
moves |= getCastlingMoves(position->activeColor,
position->castlingRights,
position->allPieces);
}
return (bool) testSquare(moves, to);
}
bool moveIsLegal(const Position * position, const Move move)
{
bool result = FALSE;
Variation variation;
if (moveIsPseudoLegal(position, move) == FALSE)
{
return FALSE;
}
setBasePosition(&variation, position);
if (makeMove(&variation, move) == 0 &&
passiveKingIsSafe(&variation.singlePosition))
{
result = TRUE;
}
unmakeLastMove(&variation);
return result;
}
static Bitboard getPinnedPieces(const Position * position,
const Color pinningColor)
{
const Square kingSquare = position->king[opponent(pinningColor)];
Bitboard pinnedPieces = EMPTY_BITBOARD, pinningCandidates =
(generalMoves[ROOK][kingSquare] &
(position->piecesOfType[QUEEN | pinningColor] |
position->piecesOfType[ROOK | pinningColor])) |
(generalMoves[BISHOP][kingSquare] &
(position->piecesOfType[QUEEN | pinningColor] |
position->piecesOfType[BISHOP | pinningColor]));
Square pinningCandidate;
ITERATE_BITBOARD(&pinningCandidates, pinningCandidate)
{
const Bitboard imSquares = squaresBetween[kingSquare][pinningCandidate];
if ((imSquares & position->piecesOfColor[pinningColor]) ==
EMPTY_BITBOARD)
{
const Bitboard pinnedCandidates = imSquares &
position->piecesOfColor[opponent(pinningColor)];
if (getNumberOfSetSquares(pinnedCandidates) == 1)
{
pinnedPieces |= pinnedCandidates;
}
}
}
return pinnedPieces;
}
int getNumberOfPieceMoves(const Position * position, const Color color,
const int sufficientNumberOfMoves)
{
const Color oppColor = opponent(color);
const Bitboard unpinnedPieces = ~getPinnedPieces(position, oppColor);
const Bitboard permittedSquares = ~position->piecesOfColor[color];
int numberOfMoves = 0;
Square square;
Bitboard moves, pieces = position->piecesOfColor[color] &
~(position->piecesOfType[PAWN | color] |
minValue[position->king[color]]) & unpinnedPieces;
ITERATE_BITBOARD(&pieces, square)
{
switch (pieceType(position->piece[square]))
{
case QUEEN:
moves =
getMagicQueenMoves(square,
position->allPieces) & permittedSquares;
break;
case ROOK:
moves =
getMagicRookMoves(square, position->allPieces) & permittedSquares;
break;
case BISHOP:
moves =
getMagicBishopMoves(square,
position->allPieces) & permittedSquares;
break;
case KNIGHT:
moves = getKnightMoves(square) & permittedSquares;
break;
default:
moves = EMPTY_BITBOARD;
}
numberOfMoves += getNumberOfSetSquares(moves);
if (numberOfMoves >= sufficientNumberOfMoves)
{
return numberOfMoves;
}
}
return numberOfMoves;
}
int seeMoveRec(Position * position, const Move move,
Bitboard attackers[2], const int minValue)
{
const Square from = getFromSquare(move), to = getToSquare(move);
const Color activeColor = pieceColor(position->piece[from]);
const Color passiveColor = opponent(activeColor);
int valueCaptured = basicValue[position->piece[to]];
Piece leastValuableAttacker, bestNewPiece;
Bitboard leastValuableAttackers;
Move bestCapture;
int recResult;
if (pieceType(position->piece[to]) == KING)
{
return valueCaptured;
}
position->piece[to] = position->piece[from];
clearSquare(position->allPieces, from);
clearSquare(attackers[activeColor], from);
if (horizontalDistance(to, from) == verticalDistance(to, from))
{
attackers[WHITE] |=
getMagicBishopMoves(to, position->allPieces) &
(position->piecesOfType[WHITE_QUEEN] |
position->piecesOfType[WHITE_BISHOP]) & position->allPieces;
attackers[BLACK] |=
getMagicBishopMoves(to, position->allPieces) &
(position->piecesOfType[BLACK_QUEEN] |
position->piecesOfType[BLACK_BISHOP]) & position->allPieces;
}
else
{
attackers[WHITE] |=
getMagicRookMoves(to, position->allPieces) &
(position->piecesOfType[WHITE_QUEEN] |
position->piecesOfType[WHITE_ROOK]) & position->allPieces;
attackers[BLACK] |=
getMagicRookMoves(to, position->allPieces) &
(position->piecesOfType[BLACK_QUEEN] |
position->piecesOfType[BLACK_ROOK]) & position->allPieces;
}
if (to == position->enPassantSquare &&
pieceType(position->piece[to]) == PAWN)
{
const Square captureSquare = (Square)
(to + (rank(from) - rank(to)) * 8);
clearSquare(position->allPieces, captureSquare);
attackers[WHITE] |= getMagicBishopMoves(to, position->allPieces) &
(position->piecesOfType[WHITE_QUEEN] |
position->piecesOfType[WHITE_BISHOP]) & position->allPieces;
attackers[WHITE] |= getMagicRookMoves(to, position->allPieces) &
(position->piecesOfType[WHITE_QUEEN] |
position->piecesOfType[WHITE_ROOK]) & position->allPieces;
attackers[BLACK] |= getMagicBishopMoves(to, position->allPieces) &
(position->piecesOfType[BLACK_QUEEN] |
position->piecesOfType[BLACK_BISHOP]) & position->allPieces;
attackers[BLACK] |= getMagicRookMoves(to, position->allPieces) &
(position->piecesOfType[BLACK_QUEEN] |
position->piecesOfType[BLACK_ROOK]) & position->allPieces;
valueCaptured += basicValue[position->piece[captureSquare]];
}
if (getNewPiece(move) != NO_PIECE)
{
valueCaptured += basicValue[getNewPiece(move) | activeColor] -
basicValue[PAWN | activeColor];
position->piece[to] = (Piece) (getNewPiece(move) | activeColor);
}
if (attackers[passiveColor] == EMPTY_BITBOARD)
{
return valueCaptured;
}
position->enPassantSquare = NO_SQUARE;
if (attackers[passiveColor] & position->piecesOfType[PAWN | passiveColor])
{
leastValuableAttacker = (Piece) (PAWN | passiveColor);
}
else if (attackers[passiveColor] &
position->piecesOfType[KNIGHT | passiveColor])
{
leastValuableAttacker = (Piece) (KNIGHT | passiveColor);
}
else if (attackers[passiveColor] &
position->piecesOfType[BISHOP | passiveColor])
{
leastValuableAttacker = (Piece) (BISHOP | passiveColor);
}
else if (attackers[passiveColor] &
position->piecesOfType[ROOK | passiveColor])
{
leastValuableAttacker = (Piece) (ROOK | passiveColor);
}
else if (attackers[passiveColor] &
position->piecesOfType[QUEEN | passiveColor])
{
leastValuableAttacker = (Piece) (QUEEN | passiveColor);
}
else
{
leastValuableAttacker = (Piece) (KING | passiveColor);
}
leastValuableAttackers =
attackers[passiveColor] & position->piecesOfType[leastValuableAttacker];
if ((leastValuableAttacker == WHITE_PAWN && rank(to) == RANK_8) ||
(leastValuableAttacker == BLACK_PAWN && rank(to) == RANK_1))
{
bestNewPiece = WHITE_QUEEN;
}
else
{
bestNewPiece = NO_PIECE;
}
bestCapture =
getMove(getLastSquare(&leastValuableAttackers), to, bestNewPiece, 0);
recResult = seeMoveRec(position, bestCapture, attackers, 0);
/*
logDebug("valueCaptured = %d\n", valueCaptured);
logDebug("recResult = %d\n", recResult);
logDebug("returnValue = %d\n", max(minValue, valueCaptured - recResult));
*/
return max(minValue, valueCaptured - recResult);
}
void getLegalMoves(Variation * variation, Movelist * movelist)
{
const int ply = variation->ply;
Position *position = &variation->singlePosition;
PlyInfo *plyInfo = &variation->plyInfo[ply];
Movelist allMoves;
Move hashmove = NO_MOVE;
Move currentMove;
allMoves.positionalGain = &(variation->positionalGain[0]);
initMovelist(movelist, position);
plyInfo->killerMove1 = NO_MOVE;
plyInfo->killerMove2 = NO_MOVE;
plyInfo->killerMove3 = NO_MOVE;
plyInfo->killerMove4 = NO_MOVE;
plyInfo->killerMove5 = NO_MOVE;
plyInfo->killerMove6 = NO_MOVE;
initStandardMovelist(&allMoves, position,
plyInfo, &variation->historyValue[0],
hashmove, FALSE);
while ((currentMove = getNextMove(&allMoves)) != NO_MOVE)
{
if (moveIsLegal(position, currentMove))
{
movelist->moves[movelist->numberOfMoves++] = currentMove;
}
}
sortMoves(movelist);
}
Gameresult getGameresult(Variation * variation)
{
Movelist movelist;
Gameresult result;
Position *pos = &variation->singlePosition;
int i, repetitionCount = 0, historyLimit;
/* Check for a draw by repetition */
historyLimit = POSITION_HISTORY_OFFSET - pos->halfMoveClock;
for (i = POSITION_HISTORY_OFFSET - 4; i >= historyLimit; i -= 2)
{
if (pos->hashKey == variation->positionHistory[i])
{
repetitionCount++;
}
}
if (repetitionCount >= 2)
{
strcpy(result.
result, GAMERESULT_DRAW
);
strcpy(result.
reason, GAMERESULT_REPETITION
);
return result;
}
if (pos->halfMoveClock >= 100)
{
strcpy(result.
result, GAMERESULT_DRAW
);
strcpy(result.
reason, GAMERESULT_50_MOVE_RULE
);
return result;
}
if (pos->numberOfPawns[WHITE] == 0 &&
pos->numberOfPawns[BLACK] == 0 &&
hasWinningPotential(pos, WHITE) == FALSE &&
hasWinningPotential(pos, BLACK) == FALSE)
{
strcpy(result.
result, GAMERESULT_DRAW
);
strcpy(result.
reason, GAMERESULT_INSUFFICIENT_MATERIAL
);
return result;
}
getLegalMoves(variation, &movelist);
if (movelist.numberOfMoves > 0)
{
strcpy(result.
result, GAMERESULT_UNKNOWN
);
}
else
{
if (activeKingIsSafe(pos))
{
strcpy(result.
result, GAMERESULT_DRAW
);
strcpy(result.
reason, GAMERESULT_STALEMATE
);
}
else
{
if (pos->activeColor == WHITE)
{
strcpy(result.
result, GAMERESULT_BLACK_WINS
);
strcpy(result.
reason, GAMERESULT_BLACK_MATES
);
}
else
{
strcpy(result.
result, GAMERESULT_WHITE_WINS
);
strcpy(result.
reason, GAMERESULT_WHITE_MATES
);
}
}
}
return result;
}
bool listContainsMove(const Movelist * movelist, const Move move)
{
int i;
const Move shortMove = move & 0xFFFF;
for (i = 0; i < movelist->numberOfMoves; i++)
{
if ((movelist->moves[i] & 0xFFFF) == shortMove)
{
return TRUE;
}
}
return FALSE;
}
static void deleteMove(Movelist * movelist, const Move move)
{
int i;
const Move shortMove = move & 0xFFFF;
for (i = 0; i < movelist->numberOfMoves; i++)
{
if ((movelist->moves[i] & 0xFFFF) == shortMove)
{
movelist->numberOfMoves--;
if (i < movelist->numberOfMoves)
{
&movelist->moves[i + 1],
(movelist->numberOfMoves - i) * sizeof(Move));
}
return;
}
}
}
static void setMoveValueInList(Movelist * movelist, const Move move)
{
int i;
const Move shortMove = move & 0xFFFF;
for (i = 0; i < movelist->numberOfMoves; i++)
{
if ((movelist->moves[i] & 0xFFFF) == shortMove)
{
movelist->moves[i] = move;
return;
}
}
}
bool listContainsSimpleMove(Movelist * movelist, const Square from,
const Square to)
{
return listContainsMove(movelist, getPackedMove(from, to, NO_PIECE));
}
void initializeMoveValues(Movelist * movelist)
{
int i;
for (i = 0; i < movelist->numberOfMoves; i++)
{
setMoveValue(&movelist->moves[i], VALUE_MATED - 1 - i);
}
}
static void addMoveByValue(Movelist * movelist, const Move move)
{
int low = -1, high = movelist->numberOfMoves, insertPosition;
const int value = getMoveValue(move);
while (high - low > 1)
{
const int avg = (low + high) >> 1;
assert(avg
< movelist
->numberOfMoves
);
if (value <= getMoveValue(movelist->moves[avg]))
{
low = avg;
}
else
{
high = avg;
}
}
insertPosition = low + 1;
assert(insertPosition
<= movelist
->numberOfMoves
);
value <= getMoveValue(movelist->moves[insertPosition - 1]));
if (insertPosition < movelist->numberOfMoves)
{
assert(value
> getMoveValue
(movelist
->moves
[insertPosition
]));
memmove(&movelist
->moves
[insertPosition
+ 1],
&movelist->moves[insertPosition],
(movelist->numberOfMoves - insertPosition) * sizeof(Move));
}
movelist->moves[insertPosition] = move;
movelist->numberOfMoves++;
}
void addMoveAtPosition(Movelist * movelist, const Move move,
const int insertPosition)
{
assert(insertPosition
<= movelist
->numberOfMoves
);
if (insertPosition < movelist->numberOfMoves)
{
memmove(&movelist
->moves
[insertPosition
+ 1],
&movelist->moves[insertPosition],
(movelist->numberOfMoves - insertPosition) * sizeof(Move));
}
movelist->moves[insertPosition] = move;
movelist->numberOfMoves++;
}
void deleteMoveAtPosition(Movelist * movelist, const int position)
{
assert(position
< movelist
->numberOfMoves
);
movelist->numberOfMoves--;
if (position < movelist->numberOfMoves)
{
memmove(&movelist
->moves
[position
],
&movelist->moves[position + 1],
(movelist->numberOfMoves - position) * sizeof(Move));
}
}
static INT16 captureMoveSortValue(const Position * position,
const Square from, const Square to)
{
return (INT16) (6 * pieceOrder[position->piece[to]] -
pieceOrder[position->piece[from]]);
}
static INT16 promotionMoveSortValue(const Position * position,
const Square to, const Piece newPiece)
{
return (INT16) (promotionPieceValue[newPiece] +
6 * pieceOrder[position->piece[to]]);
}
static INT16 historyMoveSortValue(const Position * position,
const Movelist * movelist, const Move move)
{
return (INT16) (movelist->historyValue[historyIndex(move, position)] -
VALUEOFFSET_HISTORY_MOVE);
}
static void addCaptures(Movelist * movelist, const Position * position,
const Square from, Bitboard captures)
{
Square to;
ITERATE_BITBOARD(&captures, to)
{
const INT16 value = captureMoveSortValue(position, from, to);
int i = 0;
movelist->moves[movelist->numberOfMoves] = (value - 1) << 16;
while (getMoveValue(movelist->moves[i]) >= value)
{
i++;
}
if (i < movelist->numberOfMoves)
{
memmove(&movelist
->moves
[i
+ 1], &movelist
->moves
[i
],
(movelist->numberOfMoves - i) * sizeof(Move));
}
movelist->moves[i] = getMove(from, to, NO_PIECE, value);
movelist->numberOfMoves++;
}
}
static void addPromotions(Movelist * movelist,
const Square from, Bitboard moves)
{
Square to;
ITERATE_BITBOARD(&moves, to)
{
INT16 value;
value = promotionMoveSortValue(movelist->position, to, WHITE_QUEEN);
addMoveByValue(movelist, getMove(from, to, WHITE_QUEEN, value));
value = promotionMoveSortValue(movelist->position, to, WHITE_ROOK);
movelist->badCaptures[movelist->numberOfBadCaptures++] =
getMove(from, to, WHITE_ROOK, value);
value = promotionMoveSortValue(movelist->position, to, WHITE_BISHOP);
movelist->badCaptures[movelist->numberOfBadCaptures++] =
getMove(from, to, WHITE_BISHOP, value);
value = promotionMoveSortValue(movelist->position, to, WHITE_KNIGHT);
movelist->badCaptures[movelist->numberOfBadCaptures++] =
getMove(from, to, WHITE_KNIGHT, value);
}
}
void deferMove(Movelist * movelist, Move move)
{
const int targetSpot = min(movelist->numberOfMoves - 1,
movelist->nextMove + 1);
if (targetSpot > movelist->nextMove &&
movelist->numberOfMoves < MAX_MOVES_PER_POSITION - 1)
{
int i;
for (i = movelist->numberOfMoves; i > targetSpot; i--)
{
movelist->moves[i] = movelist->moves[i - 1];
}
movelist->moves[targetSpot] = move;
movelist->numberOfMoves++;
}
}
void generateSpecialMoves(Movelist * movelist)
{
const Position *position = movelist->position;
const Color activeColor = position->activeColor;
const Color passiveColor = opponent(activeColor);
const Bitboard captureTargets = position->piecesOfColor[passiveColor];
Bitboard moves =
EMPTY_BITBOARD, pieces, pawnCaptureTargets, promotionPawns;
const Square hashFrom = getFromSquare(movelist->hashMove);
Square from;
movelist->nextMove = 0;
movelist->numberOfMoves = movelist->numberOfBadCaptures = 0;
pawnCaptureTargets = captureTargets;
if (position->enPassantSquare != NO_SQUARE)
{
setSquare(pawnCaptureTargets, position->enPassantSquare);
}
pieces = position->piecesOfType[PAWN | activeColor];
promotionPawns = pieces & promotionCandidates[activeColor];
pieces &= ~promotionPawns;
ITERATE_BITBOARD(&promotionPawns, from)
{
moves = getPawnCaptures((Piece) (PAWN | activeColor), from,
pawnCaptureTargets) |
getPawnAdvances(activeColor, from, position->allPieces);
if (moves != EMPTY_BITBOARD)
{
addPromotions(movelist, from, moves);
if (hashFrom == from)
{
deleteMove(movelist, movelist->hashMove);
}
}
}
if (position->activeColor == WHITE)
{
const Bitboard capturingPawns =
((pawnCaptureTargets & nonA) >> 9) |
((pawnCaptureTargets & nonH) >> 7);
pieces &= capturingPawns;
}
else
{
const Bitboard capturingPawns =
((pawnCaptureTargets & nonA) << 7) |
((pawnCaptureTargets & nonH) << 9);
pieces &= capturingPawns;
}
ITERATE_BITBOARD(&pieces, from)
{
moves = getPawnCaptures((Piece) (PAWN | activeColor), from,
pawnCaptureTargets);
if (moves != EMPTY_BITBOARD)
{
if (hashFrom == from)
{
clearSquare(moves, getToSquare(movelist->hashMove));
}
addCaptures(movelist, position, from, moves);
}
}
pieces = getOrdinaryPieces(position, activeColor);
ITERATE_BITBOARD(&pieces, from)
{
switch (pieceType(position->piece[from]))
{
case QUEEN:
moves = getMagicQueenMoves(from, position->allPieces);
break;
case ROOK:
moves = getMagicRookMoves(from, position->allPieces);
break;
case BISHOP:
moves = getMagicBishopMoves(from, position->allPieces);
break;
case KNIGHT:
moves = getKnightMoves(from);
break;
default:
break;
}
if (hashFrom == from)
{
clearSquare(moves, getToSquare(movelist->hashMove));
}
movelist->movesOfPiece[movelist->numberOfPieces].square = from;
movelist->movesOfPiece[movelist->numberOfPieces++].moves = moves;
moves &= captureTargets;
if (moves != EMPTY_BITBOARD)
{
addCaptures(movelist, position, from, moves);
}
}
moves = getKingMoves(position->king[activeColor]);
if (hasCastlings(position->activeColor, position->castlingRights))
{
moves |= getCastlingMoves(position->activeColor,
position->castlingRights,
position->allPieces);
}
if (hashFrom == position->king[activeColor])
{
clearSquare(moves, getToSquare(movelist->hashMove));
}
movelist->movesOfPiece[movelist->numberOfPieces].square =
position->king[activeColor];
movelist->movesOfPiece[movelist->numberOfPieces++].moves = moves;
moves &= captureTargets;
if (moves != EMPTY_BITBOARD)
{
addCaptures(movelist, position, position->king[activeColor], moves);
}
}
void generateSpecialMovesPure(Movelist * movelist)
{
const Position *position = movelist->position;
const Color activeColor = position->activeColor;
const Color passiveColor = opponent(activeColor);
const Bitboard captureTargets = position->piecesOfColor[passiveColor];
Bitboard moves =
EMPTY_BITBOARD, pieces, pawnCaptureTargets, promotionPawns;
const Square hashFrom = getFromSquare(movelist->hashMove);
Square from;
movelist->nextMove = 0;
movelist->numberOfMoves = movelist->numberOfBadCaptures = 0;
pawnCaptureTargets = captureTargets;
if (position->enPassantSquare != NO_SQUARE)
{
setSquare(pawnCaptureTargets, position->enPassantSquare);
}
pieces = position->piecesOfType[(Piece) (PAWN | activeColor)];
promotionPawns = pieces & promotionCandidates[activeColor];
pieces &= ~promotionPawns;
ITERATE_BITBOARD(&promotionPawns, from)
{
moves = getPawnCaptures((Piece) (PAWN | activeColor), from,
pawnCaptureTargets) |
getPawnAdvances(activeColor, from, position->allPieces);
if (moves != EMPTY_BITBOARD)
{
addPromotions(movelist, from, moves);
if (hashFrom == from)
{
deleteMove(movelist, movelist->hashMove);
}
}
}
if (position->activeColor == WHITE)
{
const Bitboard capturingPawns =
((pawnCaptureTargets & nonA) >> 9) |
((pawnCaptureTargets & nonH) >> 7);
pieces &= capturingPawns;
}
else
{
const Bitboard capturingPawns =
((pawnCaptureTargets & nonA) << 7) |
((pawnCaptureTargets & nonH) << 9);
pieces &= capturingPawns;
}
ITERATE_BITBOARD(&pieces, from)
{
moves = getPawnCaptures((Piece) (PAWN | activeColor), from,
pawnCaptureTargets);
if (moves != EMPTY_BITBOARD)
{
if (hashFrom == from)
{
clearSquare(moves, getToSquare(movelist->hashMove));
}
addCaptures(movelist, position, from, moves);
}
}
pieces = getOrdinaryPieces(position, activeColor);
ITERATE_BITBOARD(&pieces, from)
{
switch (pieceType(position->piece[from]))
{
case QUEEN:
moves = getMagicQueenMoves(from, position->allPieces);
break;
case ROOK:
moves = getMagicRookMoves(from, position->allPieces);
break;
case BISHOP:
moves = getMagicBishopMoves(from, position->allPieces);
break;
case KNIGHT:
moves = getKnightMoves(from);
break;
case KING:
moves = getKingMoves(position->king[activeColor]);
break;
default:
break;
}
moves &= captureTargets;
if (moves != EMPTY_BITBOARD)
{
if (hashFrom == from)
{
clearSquare(moves, getToSquare(movelist->hashMove));
}
if (moves != EMPTY_BITBOARD)
{
addCaptures(movelist, position, from, moves);
}
}
}
moves = getKingMoves(position->king[activeColor]) & captureTargets;
if (moves != EMPTY_BITBOARD)
{
if (hashFrom == position->king[activeColor])
{
clearSquare(moves, getToSquare(movelist->hashMove));
}
if (moves != EMPTY_BITBOARD)
{
addCaptures(movelist, position, position->king[activeColor], moves);
}
}
}
void generateCaptures(Movelist * movelist)
{
const Position *position = movelist->position;
const Color activeColor = position->activeColor;
const Color passiveColor = opponent(activeColor);
const Bitboard captureTargets = position->piecesOfColor[passiveColor];
Bitboard moves =
EMPTY_BITBOARD, pieces, pawnCaptureTargets, promotionPawns;
const Square hashFrom = getFromSquare(movelist->hashMove);
Square from;
movelist->nextMove = 0;
movelist->numberOfMoves = movelist->numberOfBadCaptures = 0;
pawnCaptureTargets = captureTargets;
pieces = position->piecesOfType[PAWN | activeColor];
promotionPawns = pieces & promotionCandidates[activeColor];
pieces &= ~promotionPawns;
ITERATE_BITBOARD(&promotionPawns, from)
{
moves = getPawnCaptures((Piece) (PAWN | activeColor), from,
pawnCaptureTargets);
if (moves != EMPTY_BITBOARD)
{
addPromotions(movelist, from, moves);
if (hashFrom == from)
{
deleteMove(movelist, movelist->hashMove);
}
}
}
if (position->activeColor == WHITE)
{
const Bitboard capturingPawns =
((pawnCaptureTargets & nonA) >> 9) |
((pawnCaptureTargets & nonH) >> 7);
pieces &= capturingPawns;
}
else
{
const Bitboard capturingPawns =
((pawnCaptureTargets & nonA) << 7) |
((pawnCaptureTargets & nonH) << 9);
pieces &= capturingPawns;
}
ITERATE_BITBOARD(&pieces, from)
{
moves = getPawnCaptures((Piece) (PAWN | activeColor), from,
pawnCaptureTargets);
if (moves != EMPTY_BITBOARD)
{
if (hashFrom == from)
{
clearSquare(moves, getToSquare(movelist->hashMove));
}
addCaptures(movelist, position, from, moves);
}
}
pieces = getOrdinaryPieces(position, activeColor);
ITERATE_BITBOARD(&pieces, from)
{
switch (pieceType(position->piece[from]))
{
case QUEEN:
moves = getMagicQueenMoves(from, position->allPieces);
break;
case ROOK:
moves = getMagicRookMoves(from, position->allPieces);
break;
case BISHOP:
moves = getMagicBishopMoves(from, position->allPieces);
break;
case KNIGHT:
moves = getKnightMoves(from);
break;
default:
break;
}
if (hashFrom == from)
{
clearSquare(moves, getToSquare(movelist->hashMove));
}
movelist->movesOfPiece[movelist->numberOfPieces].square = from;
movelist->movesOfPiece[movelist->numberOfPieces++].moves = moves;
moves &= captureTargets;
if (moves != EMPTY_BITBOARD)
{
addCaptures(movelist, position, from, moves);
}
}
moves = getKingMoves(position->king[activeColor]);
if (hashFrom == position->king[activeColor])
{
clearSquare(moves, getToSquare(movelist->hashMove));
}
movelist->movesOfPiece[movelist->numberOfPieces].square =
position->king[activeColor];
movelist->movesOfPiece[movelist->numberOfPieces++].moves = moves;
moves &= captureTargets;
if (moves != EMPTY_BITBOARD)
{
addCaptures(movelist, position, position->king[activeColor], moves);
}
}
void generateRestMoves(Movelist * movelist)
{
const Position *position = movelist->position;
const Bitboard permittedSquares = ~position->allPieces;
const Color activeColor = position->activeColor;
Bitboard pieces = (activeColor == WHITE ?
position->piecesOfType[WHITE_PAWN] &
~((position->allPieces >> 8) | squaresOfRank[RANK_7]) :
position->piecesOfType[BLACK_PAWN] &
~((position->allPieces << 8) | squaresOfRank[RANK_2]));
Square from;
const Square k1from =
(movelist->killer1Executed ?
getFromSquare(movelist->plyInfo->killerMove1) : NO_SQUARE);
const Square k2from =
(movelist->killer2Executed ?
getFromSquare(movelist->plyInfo->killerMove2) : NO_SQUARE);
const Square k3from =
(movelist->killer3Executed ?
getFromSquare(movelist->plyInfo->killerMove3) : NO_SQUARE);
const Square k4from =
(movelist->killer4Executed ?
getFromSquare(movelist->plyInfo->killerMove4) : NO_SQUARE);
const Square k5from =
(movelist->killer5Executed ?
getFromSquare(movelist->plyInfo->killerMove5) : NO_SQUARE);
const Square k6from =
(movelist->killer6Executed ?
getFromSquare(movelist->plyInfo->killerMove6) : NO_SQUARE);
int i;
ITERATE_BITBOARD(&pieces, from)
{
Bitboard moves =
getPawnAdvances(activeColor, from, position->allPieces);
assert(moves
!= EMPTY_BITBOARD
);
if (getFromSquare(movelist->hashMove) == from)
{
clearSquare(moves, getToSquare(movelist->hashMove));
}
movelist->movesOfPiece[movelist->numberOfPieces].square = from;
movelist->movesOfPiece[movelist->numberOfPieces++].moves = moves;
}
movelist->nextMove = 0;
movelist->numberOfMoves = 0;
for (i = 0; i < movelist->numberOfPieces; i++)
{
Bitboard moves = movelist->movesOfPiece[i].moves & permittedSquares;
UINT8 moveSquares[_64_];
int numMoves, moveIndex;
from = movelist->movesOfPiece[i].square;
if (from == k1from)
{
clearSquare(moves, getToSquare(movelist->plyInfo->killerMove1));
}
if (from == k2from)
{
clearSquare(moves, getToSquare(movelist->plyInfo->killerMove2));
}
if (from == k3from)
{
clearSquare(moves, getToSquare(movelist->plyInfo->killerMove3));
}
if (from == k4from)
{
clearSquare(moves, getToSquare(movelist->plyInfo->killerMove4));
}
if (from == k5from)
{
clearSquare(moves, getToSquare(movelist->plyInfo->killerMove5));
}
if (from == k6from)
{
clearSquare(moves, getToSquare(movelist->plyInfo->killerMove6));
}
numMoves = getSetSquares(moves, moveSquares);
for (moveIndex = 0; moveIndex < numMoves; moveIndex++)
{
Move move = getOrdinaryMove(from, (Square) moveSquares[moveIndex]);
setMoveValue(&move, historyMoveSortValue(position, movelist, move));
addMoveByValue(movelist, move);
assert(movesAreEqual
(move
, movelist
->hashMove
) == FALSE
);
}
}
}
void generateDangerousPawnAdvances(Movelist * movelist)
{
const Position *position = movelist->position;
const Color activeColor = position->activeColor;
const Rank sixthRank = (activeColor == WHITE ? RANK_6 : RANK_3);
Bitboard moves, pieces = position->piecesOfType[PAWN | activeColor] &
squaresOfRank[sixthRank];
Square from;
ITERATE_BITBOARD(&pieces, from)
{
if ((moves = getPawnAdvances(activeColor, from, position->allPieces)) !=
EMPTY_BITBOARD)
{
const Square to = getLastSquare(&moves);
Move move = getPackedMove(from, to, NO_PIECE);
if (move == movelist->hashMove)
{
continue;
}
setMoveValue(&move, historyMoveSortValue(position, movelist, move));
addMoveByValue(movelist, move);
}
}
}
void generateChecks(Movelist * movelist, bool allChecks)
{
Position *position = movelist->position;
const Color activeColor = position->activeColor;
const Color passiveColor = opponent(activeColor);
Bitboard permittedSquares;
Bitboard moves, orthoChecks, diaChecks, pawnChecks;
Bitboard pieces = position->piecesOfType[PAWN | activeColor] &
~promotionCandidates[activeColor];
const Square opponentKing = position->king[passiveColor];
Square from;
int i;
ITERATE_BITBOARD(&pieces, from)
{
if ((moves = getPawnAdvances(activeColor, from, position->allPieces)) !=
EMPTY_BITBOARD)
{
if (getFromSquare(movelist->hashMove) == from)
{
clearSquare(moves, getToSquare(movelist->hashMove));
}
movelist->movesOfPiece[movelist->numberOfPieces].square = from;
movelist->movesOfPiece[movelist->numberOfPieces++].moves = moves;
}
}
movelist->nextMove = 0;
movelist->numberOfMoves = movelist->numberOfBadCaptures = 0;
orthoChecks = getMagicRookMoves(opponentKing, position->allPieces);
diaChecks = getMagicBishopMoves(opponentKing, position->allPieces);
pawnChecks = generalMoves[PAWN | passiveColor][opponentKing];
permittedSquares = (allChecks ? ~position->piecesOfColor[activeColor] :
~position->allPieces);
for (i = 0; i < movelist->numberOfPieces; i++)
{
Bitboard checks = EMPTY_BITBOARD;
const Square from = movelist->movesOfPiece[i].square;
const PieceType piece = pieceType(position->piece[from]);
Square batteryPieceSquare = NO_SQUARE, to;
moves = movelist->movesOfPiece[i].moves & permittedSquares;
if (testSquare(orthoChecks, from))
{
static const int pieceProperties = PP_SLIDING_PIECE | PP_ORTHOPIECE;
Bitboard batteryPiece = position->piecesOfColor[activeColor] &
squaresBehind[from][opponentKing] &
getMagicRookMoves(from, position->allPieces);
batteryPieceSquare = getLastSquare(&batteryPiece);
if (batteryPieceSquare != NO_SQUARE &&
(int) (position->piece[batteryPieceSquare] & pieceProperties) !=
pieceProperties)
{
batteryPieceSquare = NO_SQUARE;
}
}
else if (testSquare(diaChecks, from))
{
static const int pieceProperties = PP_SLIDING_PIECE | PP_DIAPIECE;
Bitboard batteryPiece = position->piecesOfColor[activeColor] &
squaresBehind[from][opponentKing] &
getMagicBishopMoves(from, position->allPieces);
batteryPieceSquare = getLastSquare(&batteryPiece);
if (batteryPieceSquare != NO_SQUARE &&
(int) (position->piece[batteryPieceSquare] & pieceProperties) !=
pieceProperties)
{
batteryPieceSquare = NO_SQUARE;
}
}
if (batteryPieceSquare != NO_SQUARE)
{
checks = moves & ~squaresBetween[opponentKing][batteryPieceSquare];
}
else
{
switch (piece)
{
case QUEEN:
checks = moves & (orthoChecks | diaChecks);
break;
case ROOK:
checks = moves & orthoChecks;
break;
case BISHOP:
checks = moves & diaChecks;
break;
case KNIGHT:
checks = moves & getKnightMoves(opponentKing);
break;
case PAWN:
checks = moves & pawnChecks;
break;
default:
break;
}
}
if (piece == KING)
{
Bitboard castlingMoves = moves &
~getKingMoves(position->king[activeColor]);
Square kingSquare;
ITERATE_BITBOARD(&castlingMoves, kingSquare)
{
const Bitboard obstacles = position->allPieces &
maxValue[position->king[activeColor]];
Bitboard rookMoves;
const Square rookSquare = (Square)
((kingSquare + position->king[activeColor]) / 2);
rookMoves = getMagicRookMoves(rookSquare, obstacles);
if (testSquare(rookMoves, opponentKing))
{
setSquare(checks, kingSquare);
}
}
}
if (checks != EMPTY_BITBOARD)
{
if (from == getFromSquare(movelist->hashMove))
{
clearSquare(checks, getToSquare(movelist->hashMove));
}
if (movelist->killer1Executed &&
from == getFromSquare(movelist->plyInfo->killerMove1))
{
clearSquare(checks, getToSquare(movelist->plyInfo->killerMove1));
}
if (movelist->killer2Executed &&
from == getFromSquare(movelist->plyInfo->killerMove2))
{
clearSquare(checks, getToSquare(movelist->plyInfo->killerMove2));
}
if (movelist->killer3Executed &&
from == getFromSquare(movelist->plyInfo->killerMove3))
{
clearSquare(checks, getToSquare(movelist->plyInfo->killerMove3));
}
if (movelist->killer4Executed &&
from == getFromSquare(movelist->plyInfo->killerMove4))
{
clearSquare(checks, getToSquare(movelist->plyInfo->killerMove4));
}
if (movelist->killer5Executed &&
from == getFromSquare(movelist->plyInfo->killerMove5))
{
clearSquare(checks, getToSquare(movelist->plyInfo->killerMove5));
}
if (movelist->killer6Executed &&
from == getFromSquare(movelist->plyInfo->killerMove6))
{
clearSquare(checks, getToSquare(movelist->plyInfo->killerMove6));
}
movelist->movesOfPiece[i].moves &= ~checks;
ITERATE_BITBOARD(&checks, to)
{
Move move = getPackedMove(from, to, NO_PIECE);
setMoveValue(&move,
historyMoveSortValue(position, movelist, move));
addMoveByValue(movelist, move);
}
}
}
}
void generateEscapes(Movelist * movelist)
{
Move move;
Square from, to;
Piece newPiece;
INT16 value;
PieceType attackerType;
Position *position = movelist->position;
const Color activeColor = position->activeColor;
const Color passiveColor = opponent(activeColor);
Square kingsquare = position->king[activeColor], attackerSquare;
Bitboard attackers = getDirectAttackers(position, kingsquare, passiveColor,
position->allPieces), defenders;
Bitboard kingmoves =
getKingMoves(kingsquare) & ~position->piecesOfColor[activeColor];
Bitboard corridor;
const Bitboard obstacles = position->allPieces & maxValue[kingsquare];
movelist->nextMove = 0;
movelist->numberOfMoves = movelist->numberOfBadCaptures = 0;
from = kingsquare;
newPiece = NO_PIECE;
ITERATE_BITBOARD(&kingmoves, to)
{
if (getDirectAttackers(position, to, passiveColor, obstacles) ==
EMPTY_BITBOARD)
{
move = getPackedMove(from, to, newPiece);
if (position->piece[to] == NO_PIECE)
{
value = historyMoveSortValue(position, movelist, move);
}
else
{
value = captureMoveSortValue(position, from, to);
}
setMoveValue(&move, value);
movelist->moves[movelist->numberOfMoves++] = move;
}
}
if (getNumberOfSetSquares(attackers) > 1)
{
goto sortMoves;
}
attackerSquare = getLastSquare(&attackers);
attackerType = pieceType(position->piece[attackerSquare]);
defenders = getDirectAttackers(position, attackerSquare, activeColor,
position->allPieces);
clearSquare(defenders, kingsquare);
to = attackerSquare;
ITERATE_BITBOARD(&defenders, from)
{
if (pieceType(position->piece[from]) == PAWN &&
testSquare(promotionCandidates[activeColor], from))
{
INT16 value;
value = promotionMoveSortValue(movelist->position, to, WHITE_QUEEN);
movelist->moves[movelist->numberOfMoves++] =
getMove(from, to, WHITE_QUEEN, value);
value = promotionMoveSortValue(movelist->position, to, WHITE_ROOK);
movelist->moves[movelist->numberOfMoves++] =
getMove(from, to, WHITE_ROOK, value);
value = promotionMoveSortValue(movelist->position, to, WHITE_BISHOP);
movelist->moves[movelist->numberOfMoves++] =
getMove(from, to, WHITE_BISHOP, value);
value = promotionMoveSortValue(movelist->position, to, WHITE_KNIGHT);
movelist->moves[movelist->numberOfMoves++] =
getMove(from, to, WHITE_KNIGHT, value);
}
else
{
value = captureMoveSortValue(position, from, to);
move = getMove(from, to, NO_PIECE, value);
if (basicValue[position->piece[from]] >
basicValue[position->piece[to]] && seeMove(position, move) < 0)
{
setMoveValue(&move, value - VALUEOFFSET_BAD_MOVE);
}
movelist->moves[movelist->numberOfMoves++] = move;
}
}
if (position->enPassantSquare != NO_SQUARE && attackerType == PAWN)
{
defenders = getPawnCaptures((Piece) (PAWN | opponent(activeColor)),
position->enPassantSquare,
position->piecesOfType[PAWN | activeColor]);
to = position->enPassantSquare;
newPiece = NO_PIECE;
value = (INT16) basicValue[PAWN | opponent(activeColor)];
ITERATE_BITBOARD(&defenders, from)
{
movelist->moves[movelist->numberOfMoves++] =
getMove(from, to, newPiece, value);
}
goto sortMoves;
}
if ((attackerType & PP_SLIDING_PIECE) == 0)
{
goto sortMoves;
}
corridor = squaresBetween[attackerSquare][kingsquare];
ITERATE_BITBOARD(&corridor, to)
{
defenders = getInterestedPieces(position, to, activeColor);
clearSquare(defenders, kingsquare);
ITERATE_BITBOARD(&defenders, from)
{
if (pieceType(position->piece[from]) == PAWN &&
testSquare(promotionCandidates[activeColor], from))
{
INT16 value;
value = promotionMoveSortValue(movelist->position,
to, WHITE_QUEEN);
if (seeMove(position, getPackedMove(from, to, WHITE_QUEEN)) < 0)
{
value = (INT16) (value - (VALUEOFFSET_BAD_MOVE +
VALUEOFFSET_PROMOTION_TO_QUEEN));
}
movelist->moves[movelist->numberOfMoves++] =
getMove(from, to, WHITE_QUEEN, value);
value = promotionMoveSortValue(movelist->position,
to, WHITE_ROOK);
movelist->moves[movelist->numberOfMoves++] =
getMove(from, to, WHITE_ROOK, value);
value = promotionMoveSortValue(movelist->position,
to, WHITE_BISHOP);
movelist->moves[movelist->numberOfMoves++] =
getMove(from, to, WHITE_BISHOP, value);
value = promotionMoveSortValue(movelist->position,
to, WHITE_KNIGHT);
movelist->moves[movelist->numberOfMoves++] =
getMove(from, to, WHITE_KNIGHT, value);
}
else
{
move = getPackedMove(from, to, NO_PIECE);
if (seeMove(position, move) >= 0)
{
value = historyMoveSortValue(position, movelist, move);
}
else
{
value = (INT16) (captureMoveSortValue(position, from, to) -
VALUEOFFSET_BAD_MOVE);
}
setMoveValue(&move, value);
movelist->moves[movelist->numberOfMoves++] = move;
}
}
}
sortMoves:
if (movelist->hashMove != NO_MOVE && movelist->numberOfMoves > 1)
{
move = movelist->hashMove;
setMoveValue(&move, 32000);
setMoveValueInList(movelist, move);
}
sortMoves(movelist);
assert(movelist
->hashMove
== NO_MOVE
||
movesAreEqual(movelist->moves[0], movelist->hashMove));
}
bool simpleMoveIsCheck(const Position * position, const Move move)
{
const Color attackingColor = position->activeColor;
const Color defendingColor = opponent(attackingColor);
const Square from = getFromSquare(move);
const Square to = getToSquare(move);
const Piece movingPiece = position->piece[from];
const PieceType movingPieceType = pieceType(movingPiece);
const Square target = position->king[defendingColor];
const Bitboard moves =
getMoves(to, position->piece[from], position->allPieces);
if (testSquare(moves, target) && movingPieceType != KING)
{
return TRUE;
}
if (testSquare(getMagicRookMoves(target, position->allPieces), from))
{
Bitboard batteryPieces =
(position->piecesOfType[ROOK | attackingColor] |
position->piecesOfType[QUEEN | attackingColor]) &
squaresBehind[from][target];
Square square;
ITERATE_BITBOARD(&batteryPieces, square)
{
Bitboard blockingPieces = (position->allPieces | minValue[to]) &
squaresBetween[target][square] & maxValue[from];
if (blockingPieces == EMPTY_BITBOARD)
{
return TRUE;
}
}
}
if (testSquare(getMagicBishopMoves(target, position->allPieces), from))
{
Bitboard batteryPieces =
(position->piecesOfType[BISHOP | attackingColor] |
position->piecesOfType[QUEEN | attackingColor]) &
squaresBehind[from][target];
Square square;
ITERATE_BITBOARD(&batteryPieces, square)
{
Bitboard blockingPieces = (position->allPieces | minValue[to]) &
squaresBetween[target][square] & maxValue[from];
if (blockingPieces == EMPTY_BITBOARD)
{
return TRUE;
}
}
}
return FALSE;
}
bool kingCanEscape(Position * position)
{
Square square;
PieceType attackerType;
const Color activeColor = position->activeColor;
const Color passiveColor = opponent(activeColor);
Square kingsquare = position->king[activeColor], attackerSquare;
Bitboard attackers = getDirectAttackers(position, kingsquare, passiveColor,
position->allPieces), defenders;
Bitboard kingmoves =
getKingMoves(kingsquare) & ~position->piecesOfColor[activeColor];
Bitboard corridor;
const Bitboard unpinnedPieces = ~getPinnedPieces(position, passiveColor);
const Bitboard obstacles = position->allPieces & maxValue[kingsquare];
ITERATE_BITBOARD(&kingmoves, square)
{
if (getDirectAttackers(position, square, passiveColor, obstacles) ==
EMPTY_BITBOARD)
{
return TRUE;
}
}
if (getNumberOfSetSquares(attackers) > 1)
{
return FALSE;
}
attackerSquare = getLastSquare(&attackers);
attackerType = pieceType(position->piece[attackerSquare]);
defenders = getDirectAttackers(position, attackerSquare, activeColor,
position->allPieces);
clearSquare(defenders, kingsquare);
if ((defenders & unpinnedPieces) != EMPTY_BITBOARD)
{
return TRUE;
}
if (position->enPassantSquare != NO_SQUARE && attackerType == PAWN)
{
defenders = getPawnCaptures((Piece) (PAWN | opponent(activeColor)),
position->enPassantSquare,
position->piecesOfType[PAWN | activeColor]);
if ((defenders & unpinnedPieces) != EMPTY_BITBOARD)
{
return TRUE;
}
}
if ((attackerType & PP_SLIDING_PIECE) == 0)
{
return FALSE;
}
corridor = squaresBetween[attackerSquare][kingsquare];
ITERATE_BITBOARD(&corridor, square)
{
defenders = getInterestedPieces(position, square, activeColor);
clearSquare(defenders, kingsquare);
if ((defenders & unpinnedPieces) != EMPTY_BITBOARD)
{
return TRUE;
}
}
return FALSE;
}
int initializeModuleMovegeneration()
{
int i = 0;
MG_SCHEME_STANDARD = i;
moveGenerationStage[i++] = MGS_INITIALIZE;
moveGenerationStage[i++] = MGS_GOOD_CAPTURES_AND_PROMOTIONS;
moveGenerationStage[i++] = MGS_KILLER_MOVES;
moveGenerationStage[i++] = MGS_REST;
moveGenerationStage[i++] = MGS_BAD_CAPTURES;
moveGenerationStage[i++] = MGS_FINISHED;
MG_SCHEME_ESCAPE = i;
moveGenerationStage[i++] = MGS_INITIALIZE;
moveGenerationStage[i++] = MGS_ESCAPES;
moveGenerationStage[i++] = MGS_FINISHED;
MG_SCHEME_QUIESCENCE_WITH_CHECKS = i;
moveGenerationStage[i++] = MGS_INITIALIZE;
moveGenerationStage[i++] = MGS_GOOD_CAPTURES_AND_PROMOTIONS;
moveGenerationStage[i++] = MGS_SAFE_CHECKS;
moveGenerationStage[i++] = MGS_FINISHED;
MG_SCHEME_QUIESCENCE = i;
moveGenerationStage[i++] = MGS_INITIALIZE;
moveGenerationStage[i++] = MGS_GOOD_CAPTURES_AND_PROMOTIONS_PURE;
moveGenerationStage[i++] = MGS_FINISHED;
MG_SCHEME_CAPTURES = i;
moveGenerationStage[i++] = MGS_INITIALIZE;
moveGenerationStage[i++] = MGS_GOOD_CAPTURES;
moveGenerationStage[i++] = MGS_FINISHED;
MG_SCHEME_CHECKS = i;
moveGenerationStage[i++] = MGS_INITIALIZE;
moveGenerationStage[i++] = MGS_GOOD_CAPTURES_AND_PROMOTIONS;
moveGenerationStage[i++] = MGS_CHECKS;
moveGenerationStage[i++] = MGS_FINISHED;
pieceOrder[NO_PIECE] = 0;
pieceOrder[WHITE_PAWN] = pieceOrder[BLACK_PAWN] = 1;
pieceOrder[WHITE_KNIGHT] = pieceOrder[BLACK_KNIGHT] = 2;
pieceOrder[WHITE_BISHOP] = pieceOrder[BLACK_BISHOP] = 3;
pieceOrder[WHITE_ROOK] = pieceOrder[BLACK_ROOK] = 4;
pieceOrder[WHITE_QUEEN] = pieceOrder[BLACK_QUEEN] = 5;
pieceOrder[WHITE_KING] = pieceOrder[BLACK_KING] = 6;
promotionPieceValue[WHITE_KNIGHT] = promotionPieceValue[BLACK_KNIGHT] =
2 - VALUEOFFSET_BAD_MOVE;
promotionPieceValue[WHITE_BISHOP] = promotionPieceValue[BLACK_BISHOP] =
3 - VALUEOFFSET_BAD_MOVE;
promotionPieceValue[WHITE_ROOK] = promotionPieceValue[BLACK_ROOK] =
4 - VALUEOFFSET_BAD_MOVE;
promotionPieceValue[WHITE_QUEEN] = promotionPieceValue[BLACK_QUEEN] =
VALUEOFFSET_PROMOTION_TO_QUEEN;
return 0;
}
#ifndef NDEBUG
static int testPseudoLegalMoves()
{
Variation variation;
Bitboard attackers, interested;
initializeVariation(&variation, FEN_GAMESTART);
(&variation.singlePosition, getPackedMove(E2, E4, NO_PIECE)));
(&variation.singlePosition, getPackedMove(G1, F3, NO_PIECE)));
(&variation.singlePosition,
getPackedMove(G1, E2, NO_PIECE)) == FALSE);
(&variation.singlePosition,
getPackedMove(G8, F6, NO_PIECE)) == FALSE);
(&variation.singlePosition,
getPackedMove(E4, E5, NO_PIECE)) == FALSE);
attackers =
getDirectAttackers(&variation.singlePosition, F3, WHITE,
variation.singlePosition.allPieces);
assert(testSquare
(attackers
, G1
));
assert(testSquare
(attackers
, E2
));
assert(testSquare
(attackers
, G2
));
assert(getNumberOfSetSquares
(attackers
) == 3);
interested = getInterestedPieces(&variation.singlePosition, F3, WHITE);
assert(testSquare
(interested
, G1
));
assert(testSquare
(interested
, F2
));
assert(getNumberOfSetSquares
(interested
) == 2);
interested = getInterestedPieces(&variation.singlePosition, F4, WHITE);
assert(testSquare
(interested
, F2
));
assert(getNumberOfSetSquares
(interested
) == 1);
attackers =
getDirectAttackers(&variation.singlePosition, C6, BLACK,
variation.singlePosition.allPieces);
assert(testSquare
(attackers
, B8
));
assert(testSquare
(attackers
, B7
));
assert(testSquare
(attackers
, D7
));
assert(getNumberOfSetSquares
(attackers
) == 3);
makeMove(&variation, getPackedMove(E2, E4, NO_PIECE));
(&variation.singlePosition,
getPackedMove(E2, E4, NO_PIECE)) == FALSE);
(&variation.singlePosition,
getPackedMove(G1, F3, NO_PIECE)) == FALSE);
(&variation.singlePosition,
getPackedMove(G1, E2, NO_PIECE)) == FALSE);
(&variation.singlePosition, getPackedMove(G8, F6, NO_PIECE)));
(&variation.singlePosition,
getPackedMove(E4, E5, NO_PIECE)) == FALSE);
attackers =
getDirectAttackers(&variation.singlePosition, F3, WHITE,
variation.singlePosition.allPieces);
assert(testSquare
(attackers
, G1
));
assert(testSquare
(attackers
, D1
));
assert(testSquare
(attackers
, G2
));
assert(getNumberOfSetSquares
(attackers
) == 3);
attackers =
getDirectAttackers(&variation.singlePosition, D2, WHITE,
variation.singlePosition.allPieces);
assert(testSquare
(attackers
, B1
));
assert(testSquare
(attackers
, C1
));
assert(testSquare
(attackers
, D1
));
assert(testSquare
(attackers
, E1
));
assert(getNumberOfSetSquares
(attackers
) == 4);
makeMove(&variation, getPackedMove(G8, F6, NO_PIECE));
(&variation.singlePosition, getPackedMove(E4, E5, NO_PIECE)));
makeMove(&variation, getPackedMove(E4, E5, NO_PIECE));
(&variation.singlePosition, getPackedMove(D7, D5, NO_PIECE)));
makeMove(&variation, getPackedMove(D7, D5, NO_PIECE));
(&variation.singlePosition, getPackedMove(E5, D6, NO_PIECE)));
(&variation.singlePosition, getPackedMove(G1, F3, NO_PIECE)));
makeMove(&variation, getPackedMove(G1, F3, NO_PIECE));
(&variation.singlePosition, getPackedMove(E7, E6, NO_PIECE)));
makeMove(&variation, getPackedMove(E7, E6, NO_PIECE));
(&variation.singlePosition, getPackedMove(F1, C4, NO_PIECE)));
(&variation.singlePosition,
getPackedMove(E1, G1, NO_PIECE)) == FALSE);
makeMove(&variation, getPackedMove(F1, C4, NO_PIECE));
(&variation.singlePosition, getPackedMove(F8, C5, NO_PIECE)));
(&variation.singlePosition,
getPackedMove(E8, G8, NO_PIECE)) == FALSE);
makeMove(&variation, getPackedMove(F8, C5, NO_PIECE));
(&variation.singlePosition, getPackedMove(E1, G1, NO_PIECE)));
makeMove(&variation, getPackedMove(E1, G1, NO_PIECE));
(&variation.singlePosition, getPackedMove(E8, G8, NO_PIECE)));
return 0;
}
static int testLegalMoves()
{
Variation variation;
initializeVariation(&variation, FEN_GAMESTART);
(&variation.singlePosition, getPackedMove(E2, E4, NO_PIECE)));
(&variation.singlePosition, getPackedMove(G1, F3, NO_PIECE)));
makeMove(&variation, getPackedMove(E2, E4, NO_PIECE));
(&variation.singlePosition, getPackedMove(G8, F6, NO_PIECE)));
makeMove(&variation, getPackedMove(D7, D5, NO_PIECE));
makeMove(&variation, getPackedMove(F1, B5, NO_PIECE));
(&variation.singlePosition, getPackedMove(B8, C6, NO_PIECE)));
(&variation.singlePosition, getPackedMove(B8, D7, NO_PIECE)));
(&variation.singlePosition,
getPackedMove(B8, A6, NO_PIECE)) == FALSE);
(&variation.singlePosition,
getPackedMove(G8, F6, NO_PIECE)) == FALSE);
return 0;
}
static int testStaticExchangeEvaluation()
{
Variation variation;
Move move;
initializeVariation(&variation, FEN_GAMESTART);
makeMove(&variation, getPackedMove(E2, E4, NO_PIECE));
makeMove(&variation, getPackedMove(E7, E5, NO_PIECE));
makeMove(&variation, getPackedMove(G1, F3, NO_PIECE));
makeMove(&variation, getPackedMove(B8, C6, NO_PIECE));
move = getPackedMove(F3, E5, NO_PIECE);
assert(seeMove
(&variation.
singlePosition, move
) == PAWN_FOR_KNIGHT
);
makeMove(&variation, getPackedMove(B1, A3, NO_PIECE));
makeMove(&variation, getPackedMove(G8, H6, NO_PIECE));
makeMove(&variation, getPackedMove(A3, C4, NO_PIECE));
move = getPackedMove(F3, E5, NO_PIECE);
assert(seeMove
(&variation.
singlePosition, move
) == basicValue
[BLACK_PAWN
]);
move = getPackedMove(C4, E5, NO_PIECE);
assert(seeMove
(&variation.
singlePosition, move
) == basicValue
[BLACK_PAWN
]);
makeMove(&variation, getPackedMove(H6, G4, NO_PIECE));
move = getPackedMove(F3, E5, NO_PIECE);
assert(seeMove
(&variation.
singlePosition, move
) == PAWN_FOR_KNIGHT
);
makeMove(&variation, getPackedMove(B2, B3, NO_PIECE));
makeMove(&variation, getPackedMove(G7, G6, NO_PIECE));
makeMove(&variation, getPackedMove(C1, B2, NO_PIECE));
move = getPackedMove(F3, E5, NO_PIECE);
assert(seeMove
(&variation.
singlePosition, move
) == basicValue
[BLACK_PAWN
]);
move = getPackedMove(C4, E5, NO_PIECE);
assert(seeMove
(&variation.
singlePosition, move
) == basicValue
[BLACK_PAWN
]);
move = getPackedMove(B2, E5, NO_PIECE);
assert(seeMove
(&variation.
singlePosition, move
) ==
basicValue[BLACK_PAWN] - basicValue[WHITE_BISHOP] +
basicValue[BLACK_KNIGHT]);
makeMove(&variation, getPackedMove(F8, G7, NO_PIECE));
move = getPackedMove(F3, E5, NO_PIECE);
assert(seeMove
(&variation.
singlePosition, move
) == PAWN_FOR_KNIGHT
);
move = getPackedMove(C4, E5, NO_PIECE);
assert(seeMove
(&variation.
singlePosition, move
) == PAWN_FOR_KNIGHT
);
move = getPackedMove(B2, E5, NO_PIECE);
assert(seeMove
(&variation.
singlePosition, move
) == PAWN_FOR_BISHOP
);
makeMove(&variation, getPackedMove(A2, A4, NO_PIECE));
makeMove(&variation, getPackedMove(H7, H5, NO_PIECE));
makeMove(&variation, getPackedMove(A4, A5, NO_PIECE));
makeMove(&variation, getPackedMove(H5, H4, NO_PIECE));
makeMove(&variation, getPackedMove(A5, A6, NO_PIECE));
makeMove(&variation, getPackedMove(H4, H3, NO_PIECE));
makeMove(&variation, getPackedMove(A1, A5, NO_PIECE));
move = getPackedMove(F3, E5, NO_PIECE);
assert(seeMove
(&variation.
singlePosition, move
) > 0);
move = getPackedMove(C4, E5, NO_PIECE);
assert(seeMove
(&variation.
singlePosition, move
) > 0);
move = getPackedMove(B2, E5, NO_PIECE);
assert(seeMove
(&variation.
singlePosition, move
) > 0);
move = getPackedMove(A5, E5, NO_PIECE);
assert(seeMove
(&variation.
singlePosition, move
) ==
basicValue[BLACK_PAWN] + basicValue[BLACK_KNIGHT] -
basicValue[WHITE_ROOK]);
makeMove(&variation, getPackedMove(H8, H5, NO_PIECE));
move = getPackedMove(F3, E5, NO_PIECE);
assert(seeMove
(&variation.
singlePosition, move
) < 0);
move = getPackedMove(C4, E5, NO_PIECE);
assert(seeMove
(&variation.
singlePosition, move
) < 0);
move = getPackedMove(B2, E5, NO_PIECE);
assert(seeMove
(&variation.
singlePosition, move
) < 0);
move = getPackedMove(A5, E5, NO_PIECE);
assert(seeMove
(&variation.
singlePosition, move
) ==
basicValue[BLACK_PAWN] - basicValue[WHITE_ROOK]);
makeMove(&variation, getPackedMove(D1, A1, NO_PIECE));
move = getPackedMove(F3, E5, NO_PIECE);
assert(seeMove
(&variation.
singlePosition, move
) > 0);
move = getPackedMove(C4, E5, NO_PIECE);
assert(seeMove
(&variation.
singlePosition, move
) > 0);
move = getPackedMove(B2, E5, NO_PIECE);
assert(seeMove
(&variation.
singlePosition, move
) > 0);
move = getPackedMove(A5, E5, NO_PIECE);
assert(seeMove
(&variation.
singlePosition, move
) ==
basicValue[BLACK_PAWN] + basicValue[BLACK_KNIGHT] -
basicValue[WHITE_ROOK]);
makeMove(&variation, getPackedMove(D8, F6, NO_PIECE));
move = getPackedMove(F3, E5, NO_PIECE);
assert(seeMove
(&variation.
singlePosition, move
) == PAWN_FOR_KNIGHT
);
move = getPackedMove(C4, E5, NO_PIECE);
assert(seeMove
(&variation.
singlePosition, move
) == PAWN_FOR_KNIGHT
);
move = getPackedMove(B2, E5, NO_PIECE);
assert(seeMove
(&variation.
singlePosition, move
) == PAWN_FOR_BISHOP
);
move = getPackedMove(A5, E5, NO_PIECE);
assert(seeMove
(&variation.
singlePosition, move
) ==
basicValue[BLACK_PAWN] - basicValue[WHITE_KNIGHT] ||
seeMove(&variation.singlePosition, move) ==
basicValue[BLACK_PAWN] - basicValue[WHITE_BISHOP]);
move = getPackedMove(F6, F3, NO_PIECE);
assert(seeMove
(&variation.
singlePosition, move
) ==
basicValue[WHITE_KNIGHT] - basicValue[BLACK_QUEEN]);
move = getPackedMove(A6, B7, NO_PIECE);
assert(seeMove
(&variation.
singlePosition, move
) == 0);
makeMove(&variation, getPackedMove(A6, B7, NO_PIECE));
makeMove(&variation, getPackedMove(C8, B7, NO_PIECE));
move = getPackedMove(A5, A7, NO_PIECE);
assert(seeMove
(&variation.
singlePosition, move
) ==
basicValue[BLACK_PAWN] - basicValue[WHITE_ROOK]);
move = getPackedMove(C6, A5, NO_PIECE);
assert(seeMove
(&variation.
singlePosition, move
) ==
basicValue[WHITE_ROOK] - basicValue[BLACK_KNIGHT]);
return 0;
}
static int testStaticExchangeEvaluationWithKing()
{
Variation variation;
Move move;
initializeVariation(&variation, FEN_GAMESTART);
makeMove(&variation, getPackedMove(E2, E4, NO_PIECE));
makeMove(&variation, getPackedMove(E7, E5, NO_PIECE));
makeMove(&variation, getPackedMove(D1, H5, NO_PIECE));
makeMove(&variation, getPackedMove(D7, D6, NO_PIECE));
move = getPackedMove(H5, F7, NO_PIECE);
assert(seeMove
(&variation.
singlePosition, move
) ==
basicValue[BLACK_PAWN] - basicValue[WHITE_QUEEN]);
makeMove(&variation, getPackedMove(F1, C4, NO_PIECE));
move = getPackedMove(H5, F7, NO_PIECE);
assert(seeMove
(&variation.
singlePosition, move
) == basicValue
[BLACK_PAWN
]);
makeMove(&variation, getPackedMove(G8, H6, NO_PIECE));
move = getPackedMove(C4, F7, NO_PIECE);
assert(seeMove
(&variation.
singlePosition, move
) ==
basicValue[BLACK_PAWN] - basicValue[WHITE_BISHOP]);
return 0;
}
static int testStaticExchangeEvaluationWithEnPassantCapture()
{
Variation variation;
Move move;
initializeVariation(&variation, "6k1/8/7r/pP6/8/8/8/R5K1 w - a6 0 1");
move = getPackedMove(B5, A6, NO_PIECE);
assert(seeMove
(&variation.
singlePosition, move
) == basicValue
[BLACK_PAWN
]);
makeMove(&variation, getPackedMove(B5, A6, NO_PIECE));
makeMove(&variation, getPackedMove(G8, G7, NO_PIECE));
makeMove(&variation, getPackedMove(A6, A7, NO_PIECE));
makeMove(&variation, getPackedMove(H6, H8, NO_PIECE));
move = getPackedMove(A7, A8, WHITE_QUEEN);
assert(seeMove
(&variation.
singlePosition, move
) ==
basicValue[BLACK_ROOK] - basicValue[WHITE_PAWN]);
return 0;
}
#define P1 "2b3k1/1p1n1pP1/5P2/2r2q2/4Q3/3N1p2/5Pp1/1R1B2K1 w - - 0 1"
static int testAttackCalculations()
{
Variation variation;
initializeVariation(&variation, FEN_GAMESTART);
assert(passiveKingIsSafe
(&variation.
singlePosition));
initializeVariation(&variation, "R5k1/8/6K1/8/8/8/1r6/8 w - - 0 1");
assert(passiveKingIsSafe
(&variation.
singlePosition) == FALSE
);
initializeVariation(&variation, "6k1/R7/6K1/8/8/8/6r1/8 b - - 0 1");
assert(passiveKingIsSafe
(&variation.
singlePosition) == FALSE
);
initializeVariation(&variation, "6k1/R7/6K1/6P1/8/8/6r1/8 b - - 0 1");
assert(passiveKingIsSafe
(&variation.
singlePosition));
initializeVariation(&variation, "R5k1/8/6K1/8/8/8/1r6/8 b - - 0 1");
assert(activeKingIsSafe
(&variation.
singlePosition) == FALSE
);
initializeVariation(&variation, "6k1/R7/6K1/8/8/8/6r1/8 w - - 0 1");
assert(activeKingIsSafe
(&variation.
singlePosition) == FALSE
);
initializeVariation(&variation, "6k1/R7/6K1/6P1/8/8/6r1/8 w - - 0 1");
assert(activeKingIsSafe
(&variation.
singlePosition));
return 0;
}
static int testLegalMoveGeneration()
{
Variation variation;
Movelist movelist;
initializeVariation(&variation, "R5k1/8/5K2/8/8/8/1r6/8 b - - 0 1");
getLegalMoves(&variation, &movelist);
assert(movelist.
numberOfMoves == 2);
assert(listContainsSimpleMove
(&movelist
, G8
, H7
));
assert(listContainsSimpleMove
(&movelist
, B2
, B8
));
return 0;
}
static int testPinCheck()
{
static const char *fen1 =
"r1b1k2r/ppp2ppp/2n2n2/1B6/1b2qp2/2NP1N2/PPP1QPPP/R3K2R w KQkq - 0 9";
Variation variation;
Bitboard pinnedPieces;
initializeVariation(&variation, fen1);
pinnedPieces = getPinnedPieces(&variation.singlePosition, WHITE);
assert(testSquare
(pinnedPieces
, E4
));
assert(testSquare
(pinnedPieces
, C6
));
assert(getNumberOfSetSquares
(pinnedPieces
) == 2);
pinnedPieces = getPinnedPieces(&variation.singlePosition, BLACK);
assert(testSquare
(pinnedPieces
, E2
));
assert(testSquare
(pinnedPieces
, C3
));
assert(getNumberOfSetSquares
(pinnedPieces
) == 2);
return 0;
}
#endif
int testModuleMovegeneration()
{
#ifndef NDEBUG
int result;
if ((result = testPseudoLegalMoves()) != 0)
{
return result;
}
if ((result = testLegalMoves()) != 0)
{
return result;
}
if ((result = testStaticExchangeEvaluation()) != 0)
{
return result;
}
if ((result = testStaticExchangeEvaluationWithKing()) != 0)
{
return result;
}
if ((result = testStaticExchangeEvaluationWithEnPassantCapture()) != 0)
{
return result;
}
if ((result = testAttackCalculations()) != 0)
{
return result;
}
if ((result = testLegalMoveGeneration()) != 0)
{
return result;
}
if ((result = testPinCheck()) != 0)
{
return result;
}
#endif
return 0;
}