/*
Protector -- a UCI chess engine
Copyright (C) 2008 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 <string.h>
#include <assert.h>
#include <math.h>
#include "position.h"
#include "fen.h"
#include "io.h"
#include "keytable.h"
#include "hash.h"
int basicValue[16];
int pieceSquareValue[16][_64_][2];
BYTE remainingCastlings[_64_];
Square rookOrigin[_64_];
int pieceCountShift[16];
UINT32 pieceCountWeight[16];
static UINT64 getHashValue(const Position * position)
{
UINT64 hashValue = ULONG_ZERO;
Square square;
Piece piece;
ITERATE(square)
{
piece = position->piece[square];
if (piece != NO_PIECE)
{
hashValue ^= GENERATED_KEYTABLE[piece][square];
}
}
if (position->activeColor == BLACK)
{
hashValue = ~hashValue;
}
hashValue ^= GENERATED_KEYTABLE[0][position->castlingRights];
if (position->enPassantSquare != NO_SQUARE)
{
hashValue ^= GENERATED_KEYTABLE[0][position->enPassantSquare];
}
return hashValue;
}
static UINT64 getPawnHashValue(const Position * position)
{
UINT64 hashValue = ULONG_ZERO;
Square square;
Piece piece;
ITERATE(square)
{
piece = position->piece[square];
if (pieceType(piece) == PAWN)
{
hashValue ^= GENERATED_KEYTABLE[piece][square];
}
}
return hashValue;
}
void clearPosition(Position * position)
{
Square square;
ITERATE(square)
{
position->piece[square] = NO_PIECE;
}
position->activeColor = WHITE;
position->castlingRights = 0;
position->enPassantSquare = NO_SQUARE;
position->moveNumber = 1;
position->halfMoveClock = 0;
}
void initializePosition(Position * position)
{
int i;
Square square;
position->allPieces = EMPTY_BITBOARD;
position->piecesOfColor[WHITE] = EMPTY_BITBOARD;
position->piecesOfColor[BLACK] = EMPTY_BITBOARD;
position->openingValue[WHITE] = position->openingValue[BLACK] = 0;
position->endgameValue[WHITE] = position->endgameValue[BLACK] = 0;
position->pieceCount = 0;
for (i = 0x00; i <= 0x0F; i++)
{
position->piecesOfType[i] = EMPTY_BITBOARD;
}
if ((position->castlingRights & WHITE_00) &&
(position->piece[E1] != WHITE_KING ||
position->piece[H1] != WHITE_ROOK))
{
position->castlingRights -= WHITE_00;
}
if ((position->castlingRights & WHITE_000) &&
(position->piece[E1] != WHITE_KING ||
position->piece[A1] != WHITE_ROOK))
{
position->castlingRights -= WHITE_000;
}
if ((position->castlingRights & BLACK_00) &&
(position->piece[E8] != BLACK_KING ||
position->piece[H8] != BLACK_ROOK))
{
position->castlingRights -= BLACK_00;
}
if ((position->castlingRights & BLACK_000) &&
(position->piece[E8] != BLACK_KING ||
position->piece[A8] != BLACK_ROOK))
{
position->castlingRights -= BLACK_000;
}
if (position->enPassantSquare != NO_SQUARE)
{
if (position->activeColor == WHITE)
{
if (rank(position->enPassantSquare) != RANK_6 ||
position->piece[position->enPassantSquare - 8] != BLACK_PAWN)
{
position->enPassantSquare = NO_SQUARE;
}
}
else
{
if (rank(position->enPassantSquare) != RANK_3 ||
position->piece[position->enPassantSquare + 8] != WHITE_PAWN)
{
position->enPassantSquare = NO_SQUARE;
}
}
}
ITERATE(square)
{
Piece piece = position->piece[square];
Color color = pieceColor(piece);
if (piece != NO_PIECE)
{
setSquare(position->allPieces, square);
setSquare(position->piecesOfColor[color], square);
setSquare(position->piecesOfType[piece], square);
if (pieceType(piece) == KING)
{
position->king[color] = square;
}
position->openingValue[color] +=
pieceSquareValue[piece][square][OPENING];
position->endgameValue[color] +=
pieceSquareValue[piece][square][ENDGAME];
position->pieceCount += pieceCountWeight[piece];
}
}
position->numberOfPieces[WHITE] =
getNumberOfSetSquares(position->piecesOfColor[WHITE]);
position->numberOfPieces[BLACK] =
getNumberOfSetSquares(position->piecesOfColor[BLACK]);
position->numberOfPawns[WHITE] =
getNumberOfSetSquares(position->piecesOfType[WHITE_PAWN]);
position->numberOfPawns[BLACK] =
getNumberOfSetSquares(position->piecesOfType[BLACK_PAWN]);
position->hashValue = getHashValue(position);
position->pawnHashValue = getPawnHashValue(position);
}
void flipPosition(Position * position)
{
Square square;
BYTE castlingRights = 0;
position->activeColor = opponent(position->activeColor);
if (position->castlingRights & WHITE_00)
{
castlingRights += BLACK_00;
}
if (position->castlingRights & WHITE_000)
{
castlingRights += BLACK_000;
}
if (position->castlingRights & BLACK_00)
{
castlingRights += WHITE_00;
}
if (position->castlingRights & BLACK_000)
{
castlingRights += WHITE_000;
}
position->castlingRights = castlingRights;
if (position->enPassantSquare != NO_SQUARE)
{
position->enPassantSquare = getFlippedSquare(position->enPassantSquare);
}
for (square = A1; square <= H4; square++)
{
const Square flippedSquare = getFlippedSquare(square);
const Piece piece = position->piece[square];
position->piece[square] =
(position->piece[flippedSquare] == NO_PIECE ? NO_PIECE :
(Piece) (position->piece[flippedSquare] ^ BLACK));
position->piece[flippedSquare] =
(piece == NO_PIECE ? NO_PIECE : (Piece) (piece ^ BLACK));
}
}
void resetHistoryValues(Variation * variation)
{
int i;
for (i = 0; i < HISTORY_SIZE; i++)
{
variation->historyValue[i] = 0;
}
}
void resetHistoryHitValues(Variation * variation)
{
int i;
for (i = 0; i < HISTORY_SIZE; i++)
{
variation->historyTotalCount[i] = variation->historyHitCount[i] = 1;
}
}
void prepareSearch(Variation * variation)
{
int i;
variation->nodes = 0;
initializePosition(&variation->singlePosition);
variation->hashtable = &globalHashtable;
variation->drawScore[WHITE] = variation->drawScore[BLACK] = 0;
for (i = 0; i < MAX_DEPTH; i++)
{
PlyInfo *pi = &(variation->plyInfo[i]);
pi->killerMove1 = pi->killerMove2 = NO_MOVE;
}
}
void shrinkHistoryValues(Variation * variation)
{
int i;
for (i = 0; i < HISTORY_SIZE; i++)
{
variation->historyValue[i] = (variation->historyValue[i] + 1) / 2;
}
}
void shrinkHistoryHitValues(Variation * variation)
{
int i;
for (i = 0; i < HISTORY_SIZE; i++)
{
variation->historyTotalCount[i] =
(variation->historyTotalCount[i] + 1) / 2;
variation->historyHitCount[i] = (variation->historyHitCount[i] + 1) / 2;
}
}
void initializeVariation(Variation * variation, const char *fen)
{
variation->ply = 0;
readFen(fen, &variation->singlePosition);
prepareSearch(variation);
variation->startPosition = variation->singlePosition;
}
void setBasePosition(Variation * variation, const Position * position)
{
variation->ply = 0;
variation->singlePosition = *position;
variation->startPosition = variation->singlePosition;
}
void setDrawScore(Variation * variation, int score, Color color)
{
variation->drawScore[color] = score;
variation->drawScore[opponent(color)] = -score;
}
Bitboard getInterestedPieces(const Position * position, const Square square,
const Color attackerColor)
{
Bitboard king = getKingMoves(square);
Bitboard dia = getMagicBishopMoves(square, position->allPieces);
Bitboard ortho = getMagicRookMoves(square, position->allPieces);
Bitboard knights = getKnightMoves(square);
Bitboard pawns = getInterestedPawns(attackerColor, square,
position->allPieces);
king &= position->piecesOfType[KING | attackerColor];
ortho &= (position->piecesOfType[QUEEN | attackerColor] |
position->piecesOfType[ROOK | attackerColor]);
dia &= (position->piecesOfType[QUEEN | attackerColor] |
position->piecesOfType[BISHOP | attackerColor]);
knights &= position->piecesOfType[KNIGHT | attackerColor];
pawns &= position->piecesOfType[PAWN | attackerColor];
return king | ortho | dia | knights | pawns;
}
int checkVariation(Variation * variation)
{
if (checkConsistency(&variation->singlePosition) != 0)
{
logDebug("consistency check failed!\n");
dumpVariation(variation);
}
return 0;
}
int makeMove(Variation * variation, const Move move)
{
Position *position = &variation->singlePosition;
PlyInfo *plyInfo = &variation->plyInfo[variation->ply++];
const Square from = getFromSquare(move);
const Square to = getToSquare(move);
const Piece newPiece = getNewPiece(move);
const Piece movingPiece = position->piece[from];
const Piece capturedPiece = position->piece[to];
const Color activeColor = position->activeColor;
const Color passiveColor = opponent(activeColor);
const Bitboard minTo = minValue[to];
const Bitboard maxFrom = maxValue[from];
int result = 0;
assert(to == from || pieceType(capturedPiece) != KING);
variation->positionHistory[POSITION_HISTORY_OFFSET - 1 + variation->ply] =
plyInfo->hashValue = position->hashValue;
plyInfo->currentMove = move;
position->hashValue = ~position->hashValue;
if (position->enPassantSquare != NO_SQUARE)
{
position->hashValue ^= GENERATED_KEYTABLE[0][position->enPassantSquare];
}
plyInfo->pawnHashValue = position->pawnHashValue;
plyInfo->enPassantSquare = position->enPassantSquare;
position->enPassantSquare = NO_SQUARE;
position->activeColor = passiveColor;
if (to == from)
{
assert(checkVariation(variation) == 0);
return result; /* Nullmove */
}
plyInfo->captured = capturedPiece;
plyInfo->kingSquare = position->king[activeColor];
plyInfo->castlingRights = position->castlingRights;
plyInfo->halfMoveClock = position->halfMoveClock;
plyInfo->allPieces = position->allPieces;
plyInfo->whitePieces = position->piecesOfColor[WHITE];
plyInfo->blackPieces = position->piecesOfColor[BLACK];
position->piecesOfColor[activeColor] &= maxFrom;
position->piecesOfColor[activeColor] |= minTo;
position->piecesOfType[movingPiece] &= maxFrom;
position->hashValue ^=
GENERATED_KEYTABLE[movingPiece][from] ^
GENERATED_KEYTABLE[movingPiece][to];
position->castlingRights &=
remainingCastlings[to] & remainingCastlings[from];
if (position->castlingRights != plyInfo->castlingRights)
{
position->hashValue ^=
GENERATED_KEYTABLE[0][plyInfo->castlingRights] ^
GENERATED_KEYTABLE[0][position->castlingRights];
}
position->halfMoveClock++;
position->piece[to] = movingPiece;
position->piece[from] = NO_PIECE;
plyInfo->openingValue[activeColor] = position->openingValue[activeColor];
plyInfo->endgameValue[activeColor] = position->endgameValue[activeColor];
position->openingValue[activeColor] +=
pieceSquareValue[movingPiece][to][OPENING] -
pieceSquareValue[movingPiece][from][OPENING];
position->endgameValue[activeColor] +=
pieceSquareValue[movingPiece][to][ENDGAME] -
pieceSquareValue[movingPiece][from][ENDGAME];
if (capturedPiece != NO_PIECE)
{
position->halfMoveClock = 0;
position->piecesOfColor[passiveColor] &= ~minTo;
position->piecesOfType[capturedPiece] &= ~minTo;
position->numberOfPieces[passiveColor]--;
if (pieceType(capturedPiece) == PAWN)
{
position->numberOfPawns[passiveColor]--;
position->pawnHashValue ^= GENERATED_KEYTABLE[capturedPiece][to];
}
else
{
position->pieceCount -= pieceCountWeight[capturedPiece];
}
position->hashValue ^= GENERATED_KEYTABLE[capturedPiece][to];
plyInfo->openingValue[passiveColor] =
position->openingValue[passiveColor];
plyInfo->endgameValue[passiveColor] =
position->endgameValue[passiveColor];
position->openingValue[passiveColor] -=
pieceSquareValue[capturedPiece][to][OPENING];
position->endgameValue[passiveColor] -=
pieceSquareValue[capturedPiece][to][ENDGAME];
}
if (pieceType(movingPiece) == PAWN)
{
position->halfMoveClock = 0;
position->pawnHashValue ^=
GENERATED_KEYTABLE[movingPiece][from] ^
GENERATED_KEYTABLE[movingPiece][to];
if (distance(from, to) == 2)
{
position->enPassantSquare = (Square) ((from + to) >> 1);
position->hashValue ^=
GENERATED_KEYTABLE[0][position->enPassantSquare];
}
else if (to == plyInfo->enPassantSquare)
{
const Square captureSquare =
(Square) (to + (rank(from) - rank(to)) * 8);
const Piece capturedPawn = position->piece[captureSquare];
clearSquare(position->piecesOfColor[passiveColor], captureSquare);
clearSquare(position->piecesOfType[capturedPawn], captureSquare);
position->hashValue ^=
GENERATED_KEYTABLE[capturedPawn][captureSquare];
position->pawnHashValue ^=
GENERATED_KEYTABLE[capturedPawn][captureSquare];
plyInfo->openingValue[passiveColor] =
position->openingValue[passiveColor];
plyInfo->endgameValue[passiveColor] =
position->endgameValue[passiveColor];
position->openingValue[passiveColor] -=
pieceSquareValue[capturedPawn][captureSquare][OPENING];
position->endgameValue[passiveColor] -=
pieceSquareValue[capturedPawn][captureSquare][ENDGAME];
plyInfo->restoreSquare1 = captureSquare;
plyInfo->restorePiece1 = capturedPawn;
position->piece[captureSquare] = NO_PIECE;
position->numberOfPieces[passiveColor]--;
position->numberOfPawns[passiveColor]--;
}
else if (newPiece != NO_PIECE)
{
const Piece effectiveNewPiece = (Piece) (newPiece | activeColor);
plyInfo->restoreSquare1 = from;
plyInfo->restorePiece1 = movingPiece;
position->piece[to] = effectiveNewPiece;
position->numberOfPawns[activeColor]--;
position->pieceCount += pieceCountWeight[effectiveNewPiece];
position->hashValue ^=
GENERATED_KEYTABLE[movingPiece][to] ^
GENERATED_KEYTABLE[effectiveNewPiece][to];
position->pawnHashValue ^= GENERATED_KEYTABLE[movingPiece][to];
position->openingValue[activeColor] +=
pieceSquareValue[effectiveNewPiece][to][OPENING] -
pieceSquareValue[movingPiece][to][OPENING];
position->endgameValue[activeColor] +=
pieceSquareValue[effectiveNewPiece][to][ENDGAME] -
pieceSquareValue[movingPiece][to][ENDGAME];
}
}
else if (pieceType(movingPiece) == KING)
{
position->king[activeColor] = to;
if (distance(from, to) == 2)
{
const Square rookFrom = rookOrigin[to];
const Square rookTo = (Square) ((from + to) >> 1);
const Piece movingRook = position->piece[rookFrom];
plyInfo->restoreSquare1 = rookFrom;
plyInfo->restorePiece1 = movingRook;
plyInfo->restoreSquare2 = rookTo;
plyInfo->restorePiece2 = position->piece[rookTo];
position->piece[rookFrom] = NO_PIECE;
position->piece[rookTo] = movingRook;
position->halfMoveClock = 0;
setSquare(position->piecesOfColor[activeColor], rookTo);
clearSquare(position->piecesOfColor[activeColor], rookFrom);
setSquare(position->piecesOfType[movingRook], rookTo);
clearSquare(position->piecesOfType[movingRook], rookFrom);
position->hashValue ^=
GENERATED_KEYTABLE[movingRook][rookFrom] ^
GENERATED_KEYTABLE[movingRook][rookTo];
position->openingValue[activeColor] +=
pieceSquareValue[movingRook][rookTo][OPENING] -
pieceSquareValue[movingRook][rookFrom][OPENING];
position->endgameValue[activeColor] +=
pieceSquareValue[movingRook][rookTo][ENDGAME] -
pieceSquareValue[movingRook][rookFrom][ENDGAME];
if (getDirectAttackers(position, from, passiveColor,
position->allPieces) != EMPTY_BITBOARD ||
getDirectAttackers(position, rookTo, passiveColor,
position->allPieces) != EMPTY_BITBOARD)
{
result = 1; /* castling move was not legal */
}
}
}
setSquare(position->piecesOfType[position->piece[to]], to);
position->allPieces =
position->piecesOfColor[WHITE] | position->piecesOfColor[BLACK];
assert(checkVariation(variation) == 0);
return result;
}
int makeMoveFast(Variation * variation, const Move move)
{
Position *position = &variation->singlePosition;
PlyInfo *plyInfo = &variation->plyInfo[variation->ply++];
const Square from = getFromSquare(move);
const Square to = getToSquare(move);
const Piece newPiece = getNewPiece(move);
const Piece movingPiece = position->piece[from];
const Piece capturedPiece = position->piece[to];
const Color activeColor = position->activeColor;
const Color passiveColor = opponent(activeColor);
const Bitboard minTo = minValue[to];
const Bitboard maxFrom = maxValue[from];
int result = 0;
assert(to == from || pieceType(capturedPiece) != KING);
variation->positionHistory[POSITION_HISTORY_OFFSET - 1 + variation->ply] =
plyInfo->hashValue = position->hashValue;
plyInfo->currentMove = move;
position->hashValue = ~position->hashValue;
if (position->enPassantSquare != NO_SQUARE)
{
position->hashValue ^= GENERATED_KEYTABLE[0][position->enPassantSquare];
}
position->enPassantSquare = NO_SQUARE;
position->activeColor = passiveColor;
if (to == from)
{
assert(checkVariation(variation) == 0);
return result; /* Nullmove */
}
plyInfo->captured = capturedPiece;
position->piecesOfColor[activeColor] &= maxFrom;
position->piecesOfColor[activeColor] |= minTo;
position->piecesOfType[movingPiece] &= maxFrom;
position->hashValue ^=
GENERATED_KEYTABLE[movingPiece][from] ^
GENERATED_KEYTABLE[movingPiece][to];
position->castlingRights &=
remainingCastlings[to] & remainingCastlings[from];
if (position->castlingRights != plyInfo->castlingRights)
{
position->hashValue ^=
GENERATED_KEYTABLE[0][plyInfo->castlingRights] ^
GENERATED_KEYTABLE[0][position->castlingRights];
}
position->halfMoveClock++;
position->piece[to] = movingPiece;
position->piece[from] = NO_PIECE;
position->openingValue[activeColor] +=
pieceSquareValue[movingPiece][to][OPENING] -
pieceSquareValue[movingPiece][from][OPENING];
position->endgameValue[activeColor] +=
pieceSquareValue[movingPiece][to][ENDGAME] -
pieceSquareValue[movingPiece][from][ENDGAME];
if (capturedPiece != NO_PIECE)
{
position->halfMoveClock = 0;
position->piecesOfColor[passiveColor] &= ~minTo;
position->piecesOfType[capturedPiece] &= ~minTo;
position->numberOfPieces[passiveColor]--;
if (pieceType(capturedPiece) == PAWN)
{
position->numberOfPawns[passiveColor]--;
position->pawnHashValue ^= GENERATED_KEYTABLE[capturedPiece][to];
}
else
{
position->pieceCount -= pieceCountWeight[capturedPiece];
}
position->hashValue ^= GENERATED_KEYTABLE[capturedPiece][to];
position->openingValue[passiveColor] -=
pieceSquareValue[capturedPiece][to][OPENING];
position->endgameValue[passiveColor] -=
pieceSquareValue[capturedPiece][to][ENDGAME];
}
if (pieceType(movingPiece) == PAWN)
{
position->halfMoveClock = 0;
position->pawnHashValue ^=
GENERATED_KEYTABLE[movingPiece][from] ^
GENERATED_KEYTABLE[movingPiece][to];
if (distance(from, to) == 2)
{
position->enPassantSquare = (Square) ((from + to) >> 1);
position->hashValue ^=
GENERATED_KEYTABLE[0][position->enPassantSquare];
}
else if (to == plyInfo->enPassantSquare)
{
const Square captureSquare =
(Square) (to + (rank(from) - rank(to)) * 8);
const Piece capturedPawn = position->piece[captureSquare];
clearSquare(position->piecesOfColor[passiveColor], captureSquare);
clearSquare(position->piecesOfType[capturedPawn], captureSquare);
position->hashValue ^=
GENERATED_KEYTABLE[capturedPawn][captureSquare];
position->pawnHashValue ^=
GENERATED_KEYTABLE[capturedPawn][captureSquare];
position->openingValue[passiveColor] -=
pieceSquareValue[capturedPawn][captureSquare][OPENING];
position->endgameValue[passiveColor] -=
pieceSquareValue[capturedPawn][captureSquare][ENDGAME];
plyInfo->restoreSquare1 = captureSquare;
plyInfo->restorePiece1 = capturedPawn;
position->piece[captureSquare] = NO_PIECE;
position->numberOfPieces[passiveColor]--;
position->numberOfPawns[passiveColor]--;
}
else if (newPiece != NO_PIECE)
{
const Piece effectiveNewPiece = (Piece) (newPiece | activeColor);
plyInfo->restoreSquare1 = from;
plyInfo->restorePiece1 = movingPiece;
position->piece[to] = effectiveNewPiece;
position->numberOfPawns[activeColor]--;
position->pieceCount += pieceCountWeight[effectiveNewPiece];
position->hashValue ^=
GENERATED_KEYTABLE[movingPiece][to] ^
GENERATED_KEYTABLE[effectiveNewPiece][to];
position->pawnHashValue ^= GENERATED_KEYTABLE[movingPiece][to];
position->openingValue[activeColor] +=
pieceSquareValue[effectiveNewPiece][to][OPENING] -
pieceSquareValue[movingPiece][to][OPENING];
position->endgameValue[activeColor] +=
pieceSquareValue[effectiveNewPiece][to][ENDGAME] -
pieceSquareValue[movingPiece][to][ENDGAME];
}
}
else if (pieceType(movingPiece) == KING)
{
position->king[activeColor] = to;
if (distance(from, to) == 2)
{
const Square rookFrom = rookOrigin[to];
const Square rookTo = (Square) ((from + to) >> 1);
const Piece movingRook = position->piece[rookFrom];
plyInfo->restoreSquare1 = rookFrom;
plyInfo->restorePiece1 = movingRook;
plyInfo->restoreSquare2 = rookTo;
plyInfo->restorePiece2 = position->piece[rookTo];
position->piece[rookFrom] = NO_PIECE;
position->piece[rookTo] = movingRook;
position->halfMoveClock = 0;
setSquare(position->piecesOfColor[activeColor], rookTo);
clearSquare(position->piecesOfColor[activeColor], rookFrom);
setSquare(position->piecesOfType[movingRook], rookTo);
clearSquare(position->piecesOfType[movingRook], rookFrom);
position->hashValue ^=
GENERATED_KEYTABLE[movingRook][rookFrom] ^
GENERATED_KEYTABLE[movingRook][rookTo];
position->openingValue[activeColor] +=
pieceSquareValue[movingRook][rookTo][OPENING] -
pieceSquareValue[movingRook][rookFrom][OPENING];
position->endgameValue[activeColor] +=
pieceSquareValue[movingRook][rookTo][ENDGAME] -
pieceSquareValue[movingRook][rookFrom][ENDGAME];
if (getDirectAttackers(position, from, passiveColor,
position->allPieces) != EMPTY_BITBOARD ||
getDirectAttackers(position, rookTo, passiveColor,
position->allPieces) != EMPTY_BITBOARD)
{
result = 1; /* castling move was not legal */
}
}
}
setSquare(position->piecesOfType[position->piece[to]], to);
position->allPieces =
position->piecesOfColor[WHITE] | position->piecesOfColor[BLACK];
assert(checkVariation(variation) == 0);
return result;
}
void unmakeLastMove(Variation * variation)
{
Position *position = &variation->singlePosition;
const PlyInfo *plyInfo = &variation->plyInfo[--variation->ply];
const Move move = plyInfo->currentMove;
const Square from = getFromSquare(move);
const Square to = getToSquare(move);
const Piece newPiece = getNewPiece(move);
const Color activeColor = position->activeColor =
opponent(position->activeColor);
position->enPassantSquare = plyInfo->enPassantSquare;
position->hashValue = plyInfo->hashValue;
if (from == to)
{
assert(checkVariation(variation) == 0);
return; /* Nullmove */
}
position->pawnHashValue = plyInfo->pawnHashValue;
clearSquare(position->piecesOfType[position->piece[to]], to);
position->king[activeColor] = plyInfo->kingSquare;
position->piece[from] = position->piece[to];
position->piece[to] = plyInfo->captured;
if (newPiece != NO_PIECE)
{
position->numberOfPawns[activeColor]++;
position->pieceCount -= pieceCountWeight[position->piece[from]];
position->piece[plyInfo->restoreSquare1] = plyInfo->restorePiece1;
}
setSquare(position->piecesOfType[position->piece[from]], from);
position->halfMoveClock = plyInfo->halfMoveClock;
position->castlingRights = plyInfo->castlingRights;
position->piecesOfColor[WHITE] = plyInfo->whitePieces;
position->piecesOfColor[BLACK] = plyInfo->blackPieces;
position->allPieces = plyInfo->allPieces;
position->openingValue[activeColor] = plyInfo->openingValue[activeColor];
position->endgameValue[activeColor] = plyInfo->endgameValue[activeColor];
if (plyInfo->captured != NO_PIECE)
{
const Color passiveColor = opponent(activeColor);
setSquare(position->piecesOfType[plyInfo->captured], to);
position->numberOfPieces[passiveColor]++;
if (pieceType(plyInfo->captured) == PAWN)
{
position->numberOfPawns[passiveColor]++;
}
else
{
position->pieceCount += pieceCountWeight[plyInfo->captured];
}
position->openingValue[passiveColor] =
plyInfo->openingValue[passiveColor];
position->endgameValue[passiveColor] =
plyInfo->endgameValue[passiveColor];
}
else if (to == plyInfo->enPassantSquare &&
pieceType(position->piece[from]) == PAWN)
{
const Color passiveColor = opponent(activeColor);
position->piece[plyInfo->restoreSquare1] = plyInfo->restorePiece1;
setSquare(position->piecesOfType[plyInfo->restorePiece1],
plyInfo->restoreSquare1);
position->numberOfPieces[passiveColor]++;
position->numberOfPawns[passiveColor]++;
position->openingValue[passiveColor] =
plyInfo->openingValue[passiveColor];
position->endgameValue[passiveColor] =
plyInfo->endgameValue[passiveColor];
}
else if (distance(from, to) == 2 &&
pieceType(position->piece[from]) == KING)
{
position->piece[plyInfo->restoreSquare1] = plyInfo->restorePiece1;
position->piece[plyInfo->restoreSquare2] = plyInfo->restorePiece2;
setSquare(position->piecesOfType[plyInfo->restorePiece1],
plyInfo->restoreSquare1);
clearSquare(position->piecesOfType[plyInfo->restorePiece1],
plyInfo->restoreSquare2);
}
assert(checkVariation(variation) == 0);
}
bool moveIsCheck(const Move move, const Position * position)
{
const Square kingSquare = position->king[opponent(position->activeColor)];
const Square from = getFromSquare(move);
const Square to = getToSquare(move);
const Piece piece = position->piece[from];
if (testSquare(generalMoves[QUEEN][kingSquare], from) &&
(position->allPieces & squaresBetween[kingSquare][from]) ==
EMPTY_BITBOARD &&
testSquare(squaresBetween[kingSquare][from], to) == FALSE &&
testSquare(squaresBehind[from][kingSquare], to) == FALSE)
{
/* Detect undiscovered check: */
const Color color = position->activeColor;
Bitboard batteryPieces;
Square square;
if (rank(from) == rank(kingSquare) || file(from) == file(kingSquare))
{
batteryPieces = squaresBehind[from][kingSquare] &
(position->piecesOfType[ROOK | color] |
position->piecesOfType[QUEEN | color]);
}
else
{
batteryPieces = squaresBehind[from][kingSquare] &
(position->piecesOfType[BISHOP | color] |
position->piecesOfType[QUEEN | color]);
}
ITERATE_BITBOARD(&batteryPieces, square)
{
if ((squaresBetween[square][kingSquare] & position->allPieces) ==
minValue[from])
{
return TRUE;
}
}
}
/* No undiscovered check: */
if (piece & PP_SLIDING_PIECE)
{
return (bool)
(testSquare(generalMoves[pieceType(piece)][to], kingSquare) &&
(position->allPieces & squaresBetween[kingSquare][to]) ==
EMPTY_BITBOARD);
}
else if (pieceType(piece) == KNIGHT)
{
return (testSquare(generalMoves[KNIGHT][kingSquare], to) !=
EMPTY_BITBOARD);
}
else if (pieceType(piece) == PAWN)
{
const Piece newPiece = getNewPiece(move);
if (newPiece == NO_PIECE)
{
if (testSquare(generalMoves[piece][to], kingSquare) != FALSE)
{
return TRUE;
}
if (to == position->enPassantSquare)
{
const Square captureSquare =
(Square) (to + (rank(from) - rank(to)) * 8);
if (testSquare(generalMoves[QUEEN][kingSquare], captureSquare) &&
(squaresBetween[captureSquare][kingSquare] &
position->allPieces) == EMPTY_BITBOARD)
{
const Color color = position->activeColor;
Bitboard batteryPieces;
const Bitboard blockers = minValue[to] |
(position->allPieces & maxValue[captureSquare] &
maxValue[from]);
Square square;
if (rank(captureSquare) == rank(kingSquare) ||
file(captureSquare) == file(kingSquare))
{
batteryPieces = squaresBehind[captureSquare][kingSquare] &
(position->piecesOfType[ROOK | color] |
position->piecesOfType[QUEEN | color]);
}
else
{
batteryPieces = squaresBehind[captureSquare][kingSquare] &
(position->piecesOfType[BISHOP | color] |
position->piecesOfType[QUEEN | color]);
}
ITERATE_BITBOARD(&batteryPieces, square)
{
if ((squaresBetween[kingSquare][square] & blockers) ==
EMPTY_BITBOARD)
{
return TRUE;
}
}
}
}
}
else
{
if (newPiece & PP_SLIDING_PIECE)
{
const Bitboard blockers = position->allPieces & maxValue[from];
return (bool)
(testSquare(generalMoves[newPiece][to], kingSquare) &&
(blockers & squaresBetween[kingSquare][to]) ==
EMPTY_BITBOARD);
}
else
{
return (testSquare(generalMoves[KNIGHT][kingSquare], to) !=
EMPTY_BITBOARD);
}
}
}
else if (pieceType(piece) == KING && abs(to - from) == 2)
{
const Bitboard blockers = position->allPieces & maxValue[from];
const int rookSquare = (to + from) / 2;
return (bool)
(testSquare(generalMoves[ROOK][rookSquare], kingSquare) &&
(blockers & squaresBetween[kingSquare][rookSquare]) ==
EMPTY_BITBOARD);
}
return FALSE;
}
int checkConsistency(const Position * position)
{
Square square;
int numPieces[2], numPawns[2], value[2], i;
int openingValue[2], endgameValue[2];
Bitboard temp;
BYTE obstacles[NUM_LANES];
numPieces[WHITE] = numPieces[BLACK] = 0;
numPawns[WHITE] = numPawns[BLACK] = 0;
memset(obstacles, 0x00, NUM_LANES);
value[WHITE] = value[BLACK] = 0;
openingValue[WHITE] = openingValue[BLACK] = 0;
endgameValue[WHITE] = endgameValue[BLACK] = 0;
assert(position->activeColor == WHITE || position->activeColor == BLACK);
if (position->castlingRights & WHITE_00)
{
assert(position->piece[E1] == WHITE_KING);
assert(position->piece[H1] == WHITE_ROOK);
}
if (position->castlingRights & WHITE_000)
{
assert(position->piece[E1] == WHITE_KING);
assert(position->piece[A1] == WHITE_ROOK);
}
if (position->castlingRights & BLACK_00)
{
assert(position->piece[E8] == BLACK_KING);
assert(position->piece[H8] == BLACK_ROOK);
}
if (position->castlingRights & BLACK_000)
{
assert(position->piece[E8] == BLACK_KING);
assert(position->piece[A8] == BLACK_ROOK);
}
assert(position->enPassantSquare == NO_SQUARE ||
squareIsValid(position->enPassantSquare));
if (position->enPassantSquare != NO_SQUARE)
{
if (position->activeColor == WHITE)
{
assert(rank(position->enPassantSquare) == RANK_6);
assert(position->piece[position->enPassantSquare - 8] == BLACK_PAWN);
}
else
{
assert(rank(position->enPassantSquare) == RANK_3);
assert(position->piece[position->enPassantSquare + 8] == WHITE_PAWN);
}
}
assert((position->piecesOfColor[WHITE] ^ position->piecesOfColor[BLACK]) ==
position->allPieces);
temp = EMPTY_BITBOARD;
for (i = 1; i <= 0x0F; i++)
{
temp ^= position->piecesOfType[i];
}
assert(temp == position->allPieces);
assert(squareIsValid(position->king[WHITE]));
assert(position->piece[position->king[WHITE]] == WHITE_KING);
assert(squareIsValid(position->king[BLACK]));
assert(position->piece[position->king[BLACK]] == BLACK_KING);
assert(testSquare
(position->piecesOfType[WHITE_KING], position->king[WHITE]));
assert(getNumberOfSetSquares(position->piecesOfType[WHITE_KING]) == 1);
assert(testSquare
(position->piecesOfType[BLACK_KING], position->king[BLACK]));
assert(getNumberOfSetSquares(position->piecesOfType[BLACK_KING]) == 1);
assert(getNumberOfSetSquares(position->piecesOfType[WHITE_QUEEN]) ==
getPieceCount(position, WHITE_QUEEN));
assert(getNumberOfSetSquares(position->piecesOfType[WHITE_ROOK]) ==
getPieceCount(position, WHITE_ROOK));
assert(getNumberOfSetSquares(position->piecesOfType[WHITE_BISHOP]) ==
getPieceCount(position, WHITE_BISHOP));
assert(getNumberOfSetSquares(position->piecesOfType[WHITE_KNIGHT]) ==
getPieceCount(position, WHITE_KNIGHT));
assert(getNumberOfSetSquares(position->piecesOfType[BLACK_QUEEN]) ==
getPieceCount(position, BLACK_QUEEN));
assert(getNumberOfSetSquares(position->piecesOfType[BLACK_ROOK]) ==
getPieceCount(position, BLACK_ROOK));
assert(getNumberOfSetSquares(position->piecesOfType[BLACK_BISHOP]) ==
getPieceCount(position, BLACK_BISHOP));
assert(getNumberOfSetSquares(position->piecesOfType[BLACK_KNIGHT]) ==
getPieceCount(position, BLACK_KNIGHT));
ITERATE(square)
{
Piece piece = position->piece[square];
PieceType pieceType = pieceType(piece);
Color color = pieceColor(piece);
assert(piece >= 0 && piece <= 15);
if (piece != NO_PIECE)
{
numPieces[color]++;
setObstacleSquare(square, obstacles);
assert(testSquare(position->allPieces, square));
assert(testSquare(position->piecesOfColor[color], square));
assert(testSquare(position->piecesOfType[piece], square));
if (pieceType == PAWN)
{
numPawns[color]++;
}
if (pieceType != KING)
{
value[color] += basicValue[piece];
}
openingValue[color] += pieceSquareValue[piece][square][OPENING];
endgameValue[color] += pieceSquareValue[piece][square][ENDGAME];
}
else
{
assert(testSquare(position->allPieces, square) == FALSE);
assert(testSquare(position->piecesOfColor[WHITE], square) == FALSE);
assert(testSquare(position->piecesOfColor[BLACK], square) == FALSE);
}
}
assert(numPieces[WHITE] == position->numberOfPieces[WHITE]);
assert(numPieces[WHITE] >= 1);
assert(numPieces[WHITE] <= 16);
assert(numPieces[WHITE] ==
getNumberOfSetSquares(position->piecesOfColor[WHITE]));
assert(numPieces[BLACK] == position->numberOfPieces[BLACK]);
assert(numPieces[BLACK] >= 1);
assert(numPieces[BLACK] <= 16);
assert(numPieces[BLACK] ==
getNumberOfSetSquares(position->piecesOfColor[BLACK]));
assert(numPawns[WHITE] == position->numberOfPawns[WHITE]);
assert(numPawns[WHITE] >= 0);
assert(numPawns[WHITE] <= 8);
assert(numPawns[WHITE] ==
getNumberOfSetSquares(position->piecesOfType[WHITE_PAWN]));
assert(numPawns[BLACK] == position->numberOfPawns[BLACK]);
assert(numPawns[BLACK] >= 0);
assert(numPawns[BLACK] <= 8);
assert(numPawns[BLACK] ==
getNumberOfSetSquares(position->piecesOfType[BLACK_PAWN]));
assert(openingValue[WHITE] == position->openingValue[WHITE]);
assert(openingValue[BLACK] == position->openingValue[BLACK]);
assert(endgameValue[WHITE] == position->endgameValue[WHITE]);
assert(endgameValue[BLACK] == position->endgameValue[BLACK]);
assert(getHashValue(position) == position->hashValue);
assert(getPawnHashValue(position) == position->pawnHashValue);
return 0;
}
bool positionIsLegal(const Position * position)
{
Square square;
int numPieces[2], numPawns[2], value[2], i;
Bitboard temp;
BYTE obstacles[NUM_LANES];
numPieces[WHITE] = numPieces[BLACK] = 0;
numPawns[WHITE] = numPawns[BLACK] = 0;
memset(obstacles, 0x00, NUM_LANES);
value[WHITE] = value[BLACK] = 0;
if (position->activeColor != WHITE && position->activeColor != BLACK)
{
return FALSE;
}
if (position->castlingRights & WHITE_00)
{
if (position->piece[E1] != WHITE_KING)
{
return FALSE;
}
if (position->piece[H1] != WHITE_ROOK)
{
return FALSE;
}
}
if (position->castlingRights & WHITE_000)
{
if (position->piece[E1] != WHITE_KING)
{
return FALSE;
}
if (position->piece[A1] != WHITE_ROOK)
{
return FALSE;
}
}
if (position->castlingRights & BLACK_00)
{
if (position->piece[E8] != BLACK_KING)
{
return FALSE;
}
if (position->piece[H8] != BLACK_ROOK)
{
return FALSE;
}
}
if (position->castlingRights & BLACK_000)
{
if (position->piece[E8] != BLACK_KING)
{
return FALSE;
}
if (position->piece[A8] != BLACK_ROOK)
{
return FALSE;
}
}
if (position->enPassantSquare != NO_SQUARE)
{
if (squareIsValid(position->enPassantSquare) == FALSE)
{
return FALSE;
}
if (position->activeColor == WHITE)
{
if (rank(position->enPassantSquare) != RANK_6)
{
return FALSE;
}
if (position->piece[position->enPassantSquare - 8] != BLACK_PAWN)
{
return FALSE;
}
}
else
{
if (rank(position->enPassantSquare) != RANK_3)
{
return FALSE;
}
if (position->piece[position->enPassantSquare + 8] != WHITE_PAWN)
{
return FALSE;
}
}
}
if ((position->piecesOfColor[WHITE] ^ position->piecesOfColor[BLACK]) !=
position->allPieces)
{
return FALSE;
}
temp = EMPTY_BITBOARD;
for (i = 1; i <= 0x0F; i++)
{
temp ^= position->piecesOfType[i];
}
/*
dumpBitboard(temp, "temp");
dumpBitboard(position->allPieces, "allPieces");
*/
if (temp != position->allPieces)
{
return FALSE;
}
if (squareIsValid(position->king[WHITE]) == FALSE)
{
return FALSE;
}
if (position->piece[position->king[WHITE]] != WHITE_KING)
{
return FALSE;
}
if (squareIsValid(position->king[BLACK]) == FALSE)
{
return FALSE;
}
if (position->piece[position->king[BLACK]] != BLACK_KING)
{
return FALSE;
}
if (distance(position->king[WHITE], position->king[BLACK]) < 2)
{
return FALSE;
}
if (testSquare(position->piecesOfType[WHITE_KING],
position->king[WHITE]) == FALSE)
{
return FALSE;
}
if (getNumberOfSetSquares(position->piecesOfType[WHITE_KING]) != 1)
{
return FALSE;
}
if (testSquare(position->piecesOfType[BLACK_KING],
position->king[BLACK]) == FALSE)
{
return FALSE;
}
if (getNumberOfSetSquares(position->piecesOfType[BLACK_KING]) != 1)
{
return FALSE;
}
ITERATE(square)
{
Piece piece = position->piece[square];
PieceType pieceType = pieceType(piece);
Color color = pieceColor(piece);
if (piece < 0 || piece > 15)
{
return FALSE;
}
if (piece != NO_PIECE)
{
numPieces[color]++;
setObstacleSquare(square, obstacles);
if (testSquare(position->allPieces, square) == FALSE)
{
return FALSE;
}
if (testSquare(position->piecesOfColor[color], square) == FALSE)
{
return FALSE;
}
if (testSquare(position->piecesOfType[piece], square) == FALSE)
{
return FALSE;
}
if (pieceType == PAWN)
{
numPawns[color]++;
}
if (pieceType != KING)
{
value[color] += basicValue[piece];
}
}
else
{
if (testSquare(position->allPieces, square))
{
return FALSE;
}
if (testSquare(position->piecesOfColor[WHITE], square))
{
return FALSE;
}
if (testSquare(position->piecesOfColor[BLACK], square))
{
return FALSE;
}
}
}
if (numPieces[WHITE] < 1)
{
return FALSE;
}
if (numPieces[WHITE] > 16)
{
return FALSE;
}
if (numPieces[BLACK] < 1)
{
return FALSE;
}
if (numPieces[BLACK] > 16)
{
return FALSE;
}
if (numPawns[WHITE] < 0)
{
return FALSE;
}
if (numPawns[WHITE] > 8)
{
return FALSE;
}
if (numPawns[BLACK] < 0)
{
return FALSE;
}
if (numPawns[BLACK] > 8)
{
return FALSE;
}
return TRUE;
}
bool positionsAreIdentical(const Position * position1,
const Position * position2)
{
Square square;
if (position1->activeColor != position2->activeColor ||
position1->castlingRights != position2->castlingRights ||
position1->enPassantSquare != position2->enPassantSquare)
{
logDebug("activeColor1=%d activeColor2=%d\n",
position1->activeColor, position2->activeColor);
logDebug("castlingRights1=%d castlingRights2=%d\n",
position1->castlingRights, position2->castlingRights);
logDebug("enPassantSquare1=%d enPassantSquare2=%d\n",
position1->enPassantSquare, position2->enPassantSquare);
return FALSE;
}
if (position1->halfMoveClock != position2->halfMoveClock ||
position1->moveNumber != position2->moveNumber)
{
logDebug("halfMoveClock1=%d halfMoveClock2=%d\n",
position1->halfMoveClock, position2->halfMoveClock);
logDebug("moveNumber1=%d moveNumber2=%d\n",
position1->moveNumber, position2->moveNumber);
return FALSE;
}
ITERATE(square)
{
if (position1->piece[square] != position2->piece[square])
{
logDebug("piece diff!\n");
dumpSquare(square);
return FALSE;
}
}
return (bool) (checkConsistency(position1) == 0);
}
int initializeModulePosition()
{
Square square;
int i, maxValuePieces;
ITERATE(square)
{
remainingCastlings[square] = (WHITE_00 | WHITE_000 |
BLACK_00 | BLACK_000);
switch (square)
{
case A1:
remainingCastlings[square] -= WHITE_000;
break;
case E1:
remainingCastlings[square] -= WHITE_000;
remainingCastlings[square] -= WHITE_00;
break;
case H1:
remainingCastlings[square] -= WHITE_00;
break;
case A8:
remainingCastlings[square] -= BLACK_000;
break;
case E8:
remainingCastlings[square] -= BLACK_000;
remainingCastlings[square] -= BLACK_00;
break;
case H8:
remainingCastlings[square] -= BLACK_00;
break;
default:
break;
}
}
rookOrigin[C1] = A1;
rookOrigin[G1] = H1;
rookOrigin[C8] = A8;
rookOrigin[G8] = H8;
basicValue[NO_PIECE] = 0;
basicValue[WHITE_KING] = basicValue[BLACK_KING] = -VALUE_MATED;
basicValue[WHITE_QUEEN] = basicValue[BLACK_QUEEN] = VALUE_QUEEN_OPENING;
basicValue[WHITE_ROOK] = basicValue[BLACK_ROOK] = VALUE_ROOK_OPENING;
basicValue[WHITE_BISHOP] = basicValue[BLACK_BISHOP] = VALUE_BISHOP_OPENING;
basicValue[WHITE_KNIGHT] = basicValue[BLACK_KNIGHT] = VALUE_KNIGHT_OPENING;
basicValue[WHITE_PAWN] = basicValue[BLACK_PAWN] = VALUE_PAWN;
/*logDebug("size of Variation: %d bytes\n", sizeof(Variation)); */
maxValuePieces = basicValue[WHITE_QUEEN] + 2 * basicValue[WHITE_ROOK] +
2 * basicValue[WHITE_BISHOP] + 2 * basicValue[WHITE_KNIGHT];
pieceCountShift[WHITE_KING] = 32;
pieceCountShift[WHITE_QUEEN] = 0;
pieceCountShift[WHITE_ROOK] = 4;
pieceCountShift[WHITE_BISHOP] = 8;
pieceCountShift[WHITE_KNIGHT] = 12;
pieceCountShift[WHITE_PAWN] = 32;
pieceCountShift[BLACK_KING] = 32;
pieceCountShift[BLACK_QUEEN] = 16;
pieceCountShift[BLACK_ROOK] = 20;
pieceCountShift[BLACK_BISHOP] = 24;
pieceCountShift[BLACK_KNIGHT] = 28;
pieceCountShift[BLACK_PAWN] = 32;
for (i = 0; i < 16; i++)
{
pieceCountWeight[i] =
(pieceCountShift[i] < 32 ? 0x00000001 << pieceCountShift[i] : 0);
/* logDebug("pcw(%d) = %lu (%d)\n", i, pieceCountWeight[i], pieceCountShift[i]); */
}
return 0;
}
static int checkMove(Square from, Square to, Piece newPiece,
Variation * variation)
{
Move move = getPackedMove(from, to, newPiece);
makeMove(variation, move);
assert(checkConsistency(&variation->singlePosition) == 0);
return 0;
}
static int testPawnMoves()
{
Variation variation;
initializeVariation(&variation, FEN_GAMESTART);
assert(checkConsistency(&variation.singlePosition) == 0);
checkMove(E2, E4, NO_PIECE, &variation);
assert(variation.singlePosition.enPassantSquare == E3);
checkMove(D7, D5, NO_PIECE, &variation);
assert(variation.singlePosition.enPassantSquare == D6);
checkMove(E4, D5, NO_PIECE, &variation);
assert(variation.singlePosition.enPassantSquare == NO_SQUARE);
checkMove(D8, D5, NO_PIECE, &variation);
checkMove(D2, D4, NO_PIECE, &variation);
checkMove(D5, D8, NO_PIECE, &variation);
checkMove(D4, D5, NO_PIECE, &variation);
checkMove(C7, C5, NO_PIECE, &variation);
assert(variation.singlePosition.enPassantSquare == C6);
checkMove(D5, C6, NO_PIECE, &variation);
checkMove(E7, E5, NO_PIECE, &variation);
checkMove(C6, B7, NO_PIECE, &variation);
checkMove(E5, E4, NO_PIECE, &variation);
checkMove(F2, F4, NO_PIECE, &variation);
assert(variation.singlePosition.enPassantSquare == F3);
checkMove(E4, F3, NO_PIECE, &variation);
checkMove(B7, C8, WHITE_ROOK, &variation);
checkMove(F3, G2, NO_PIECE, &variation);
checkMove(C8, B8, NO_PIECE, &variation);
checkMove(G2, H1, WHITE_QUEEN, &variation);
checkMove(D1, D8, WHITE_QUEEN, &variation); /* checkmate; what a game! */
return 0;
}
static int testShortCastlings()
{
Variation variation;
initializeVariation(&variation, FEN_GAMESTART);
assert(checkConsistency(&variation.singlePosition) == 0);
checkMove(E2, E4, NO_PIECE, &variation);
checkMove(E7, E5, NO_PIECE, &variation);
checkMove(G1, F3, NO_PIECE, &variation);
checkMove(G8, F6, NO_PIECE, &variation);
checkMove(F1, C4, NO_PIECE, &variation);
checkMove(F8, C5, NO_PIECE, &variation);
checkMove(E1, G1, NO_PIECE, &variation);
assert(variation.singlePosition.piece[F1] == WHITE_ROOK);
checkMove(E8, G8, NO_PIECE, &variation);
assert(variation.singlePosition.piece[F8] == BLACK_ROOK);
return 0;
}
static int testLongCastlings()
{
Variation variation;
initializeVariation(&variation, FEN_GAMESTART);
assert(checkConsistency(&variation.singlePosition) == 0);
checkMove(D2, D4, NO_PIECE, &variation);
checkMove(D7, D5, NO_PIECE, &variation);
checkMove(B1, C3, NO_PIECE, &variation);
checkMove(B8, C6, NO_PIECE, &variation);
checkMove(C1, F4, NO_PIECE, &variation);
checkMove(C8, F5, NO_PIECE, &variation);
checkMove(D1, D2, NO_PIECE, &variation);
checkMove(D8, D7, NO_PIECE, &variation);
checkMove(E1, C1, NO_PIECE, &variation);
assert(variation.singlePosition.piece[D1] == WHITE_ROOK);
checkMove(E8, C8, NO_PIECE, &variation);
assert(variation.singlePosition.piece[D8] == BLACK_ROOK);
return 0;
}
static int testCastlingLegality()
{
Variation variation, *p_variation = &variation;
initializeVariation(&variation, FEN_GAMESTART);
assert(checkConsistency(&variation.singlePosition) == 0);
checkMove(E2, E4, NO_PIECE, &variation);
checkMove(E7, E5, NO_PIECE, &variation);
checkMove(G1, F3, NO_PIECE, &variation);
checkMove(G8, F6, NO_PIECE, &variation);
checkMove(F3, E5, NO_PIECE, &variation);
checkMove(F6, E4, NO_PIECE, &variation);
checkMove(E5, G6, NO_PIECE, &variation);
checkMove(E4, G3, NO_PIECE, &variation);
checkMove(F1, C4, NO_PIECE, &variation);
checkMove(F8, C5, NO_PIECE, &variation);
assert(makeMove(&variation, getPackedMove(E1, G1, NO_PIECE)) == 1);
unmakeLastMove(p_variation);
checkMove(H2, G3, NO_PIECE, &variation);
assert(makeMove(&variation, getPackedMove(E8, G8, NO_PIECE)) == 1);
unmakeLastMove(p_variation);
checkMove(H7, G6, NO_PIECE, &variation);
assert(makeMove(&variation, getPackedMove(E1, G1, NO_PIECE)) == 0);
assert(makeMove(&variation, getPackedMove(E8, G8, NO_PIECE)) == 0);
initializeVariation(&variation, FEN_GAMESTART);
assert(checkConsistency(&variation.singlePosition) == 0);
checkMove(E2, E4, NO_PIECE, &variation);
checkMove(E7, E5, NO_PIECE, &variation);
checkMove(G1, F3, NO_PIECE, &variation);
checkMove(G8, F6, NO_PIECE, &variation);
checkMove(F3, E5, NO_PIECE, &variation);
checkMove(F6, E4, NO_PIECE, &variation);
checkMove(E5, F3, NO_PIECE, &variation);
checkMove(E4, F6, NO_PIECE, &variation);
checkMove(F1, C4, NO_PIECE, &variation);
checkMove(F8, C5, NO_PIECE, &variation);
checkMove(D1, E2, NO_PIECE, &variation);
assert(makeMove(&variation, getPackedMove(E8, G8, NO_PIECE)) == 1);
unmakeLastMove(p_variation); /* 0-0 */
unmakeLastMove(p_variation); /* Qe2+ */
assert(makeMove(&variation, getPackedMove(E1, G1, NO_PIECE)) == 0);
unmakeLastMove(p_variation); /* 0-0 */
checkMove(D2, D3, NO_PIECE, &variation);
assert(makeMove(&variation, getPackedMove(E8, G8, NO_PIECE)) == 0);
unmakeLastMove(p_variation); /* 0-0 */
checkMove(D8, E7, NO_PIECE, &variation);
assert(makeMove(&variation, getPackedMove(E1, G1, NO_PIECE)) == 1);
unmakeLastMove(p_variation); /* 0-0 */
unmakeLastMove(p_variation); /* Qe7+ */
checkMove(D7, D6, NO_PIECE, &variation);
assert(makeMove(&variation, getPackedMove(E1, G1, NO_PIECE)) == 0);
return 0;
}
int testMove()
{
Move move;
move = getMove(A1, C3, NO_PIECE, -17);
assert(getFromSquare(move) == A1);
assert(getToSquare(move) == C3);
assert(getNewPiece(move) == NO_PIECE);
assert(getMoveValue(move) == -17);
return 0;
}
int testModulePosition()
{
int result;
if ((result = testPawnMoves()) != 0)
{
return result;
}
if ((result = testShortCastlings()) != 0)
{
return result;
}
if ((result = testLongCastlings()) != 0)
{
return result;
}
if ((result = testCastlingLegality()) != 0)
{
return result;
}
if ((result = testMove()) != 0)
{
return result;
}
return 0;
}