/*
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/>.
*/
/*
This module contains a bitboard-based chess move generator.
*/
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "bitboard.h"
#include "io.h"
#ifndef __builtin_popcountll // Pierre-Marie Baty -- __builtin_popcountll support for MSVC 32-bit
int __builtin_popcountll (unsigned long long x) {
static const unsigned long long m1 = 0x5555555555555555; //binary: 0101...
static const unsigned long long m2 = 0x3333333333333333; //binary: 00110011..
static const unsigned long long m4 = 0x0f0f0f0f0f0f0f0f; //binary: 4 zeros, 4 ones ...
static const unsigned long long h01 = 0x0101010101010101; //the sum of 256 to the power of 0,1,2,3...
x -= (x >> 1) & m1; //put count of each 2 bits into those 2 bits
x = (x & m2) + ((x >> 2) & m2); //put count of each 4 bits into those 4 bits
x = (x + (x >> 4)) & m4; //put count of each 8 bits into those 8 bits
return (int)((x * h01) >> 56); //returns left 8 bits of x + (x<<8) + (x<<16) + (x<<24) + ...
}
#endif // Pierre-Marie Baty -- __builtin_popcountll support for MSVC 32-bit
#ifndef __builtin_ctzll // Pierre-Marie Baty -- __builtin_ctzll support for MSVC 32-bit
int __builtin_ctzll (unsigned long long x)
{
// Returns the number of trailing 0-bits in x, starting at the least significant bit position.
// If x is zero, the result is undefined.
// This uses a binary search algorithm from Hacker's Delight.
int n = 1;
if ((x & 0x00000000FFFFFFFF) == 0) { n = n + 32; x = x >> 32; }
if ((x & 0x000000000000FFFF) == 0) { n = n + 16; x = x >> 16; }
if ((x & 0x00000000000000FF) == 0) { n = n + 8; x = x >> 8; }
if ((x & 0x000000000000000F) == 0) { n = n + 4; x = x >> 4; }
if ((x & 0x0000000000000003) == 0) { n = n + 2; x = x >> 2; }
return (n - (x & 1));
}
#endif // Pierre-Marie Baty -- __builtin_ctzll support for MSVC 32-bit
#ifndef __builtin_clzll // Pierre-Marie Baty -- __builtin_clzll support for MSVC 32-bit
int __builtin_clzll (unsigned long long x)
{
// Returns the number of leading 0-bits in x, starting at the most significant bit position.
// If x is zero, the result is undefined.
// This uses a binary search (counting down) algorithm from Hacker's Delight.
unsigned long long y;
int n = 64;
y = x >> 32; if (y != 0) { n = n - 32; x = y; }
y = x >> 16; if (y != 0) { n = n - 16; x = y; }
y = x >> 8; if (y != 0) { n = n - 8; x = y; }
y = x >> 4; if (y != 0) { n = n - 4; x = y; }
y = x >> 2; if (y != 0) { n = n - 2; x = y; }
y = x >> 1; if (y != 0) return (n - 2);
return (n - (int) x);
}
#endif // Pierre-Marie Baty -- __builtin_clzll support for MSVC 32-bit
#define offset(sq1,sq2) ( ( (sq2)-(sq1) ) / distance(sq1,sq2) )
/**
* Macros for internal use.
*/
#define HLANE(sq) ( rank(sq) )
#define HLANEBIT(sq) ( FILE_H - file(sq) )
#define VLANE(sq) ( file(sq) )
#define VLANEBIT(sq) ( RANK_8 - rank(sq) )
#define ULANE(sq) ( file(sq) - rank(sq) + 7 )
#define ULANEBIT(sq) ( RANK_8 - rank(sq) )
#define DLANE(sq) ( file(sq) + rank(sq) )
#define DLANEBIT(sq) ( rank(sq) )
#define HLANE_SQUARE(lane,bit) ( getSquare ( 7-(bit), (lane) ) )
#define VLANE_SQUARE(lane,bit) ( getSquare ( (lane), 7-(bit) ) )
#define ULANE_SQUARE(lane,bit) ( getSquare ( (lane)-(bit), 7-(bit) ) )
#define DLANE_SQUARE(lane,bit) ( getSquare ( (lane)-(bit), (bit) ) )
static bool isInitialized = FALSE;
UINT64 minValue[_64_];
UINT64 maxValue[_64_];
INT8 highestBit[0x10000];
INT8 lowestBit[0x10000];
INT8 numSetBits[0x10000];
UINT8 rankOverlay[0x10000];
UINT8 bitshiftGap[8][256];
int hLaneNumber[_64_], vLaneNumber[_64_];
int uLaneNumber[_64_], dLaneNumber[_64_];
Bitboard generalMoves[0x0f][_64_];
/* *INDENT-OFF* */
const Bitboard squaresOfFile[8] = {
0x0101010101010101llu,
0x0202020202020202llu,
0x0404040404040404llu,
0x0808080808080808llu,
0x1010101010101010llu,
0x2020202020202020llu,
0x4040404040404040llu,
0x8080808080808080llu
};
const Bitboard squaresOfRank[8] = {
0x00000000000000ffllu,
0x000000000000ff00llu,
0x0000000000ff0000llu,
0x00000000ff000000llu,
0x000000ff00000000llu,
0x0000ff0000000000llu,
0x00ff000000000000llu,
0xff00000000000000llu
};
const Bitboard squaresOfLateralFiles[8] = {
0x0202020202020202llu,
0x0505050505050505llu,
0x0a0a0a0a0a0a0a0allu,
0x1414141414141414llu,
0x2828282828282828llu,
0x5050505050505050llu,
0xa0a0a0a0a0a0a0a0llu,
0x4040404040404040llu
};
/* *INDENT-ON* */
Bitboard squaresOfFileRange[8][8];
Bitboard squaresOfRankRange[8][8];
Bitboard nonA, nonH, border, center, lightSquares, darkSquares, queenSide,
kingSide, centerFiles, extendedCenter;
Bitboard squaresBehind[_64_][_64_];
Bitboard squaresBetween[_64_][_64_];
Bitboard squaresInDistance[8][_64_];
Bitboard squaresInTaxiDistance[15][_64_];
Bitboard squaresAbove[2][_64_];
Bitboard squaresBelow[2][_64_];
Bitboard squaresLeftOf[_64_];
Bitboard squaresRightOf[_64_];
Bitboard orthoKingAttackers[_64_];
Bitboard diaKingAttackers[_64_];
Bitboard knightKingAttackers[_64_];
Bitboard pawnKingAttackers[2][_64_];
SquareLaneInfo squareLaneInfo[_64_];
Bitboard hlane[_64_][256];
Bitboard vlane[_64_][256];
Bitboard ulane[_64_][256];
Bitboard dlane[_64_][256];
ObstacleSquareInfo obsi[_64_];
Bitboard pawnMoves[2][_64_][256];
Bitboard interestedPawns[2][_64_][256];
Bitboard castlings[2][16][256];
int castlingLane[] = { HLANE(E1), HLANE(E8) };
Bitboard promotionCandidates[2];
SetSquaresInfo setSquares[4][0x10000];
Bitboard preMaskRook[64], preMaskBishop[64];
Bitboard magicRookMoves[64][IMAX_ROOK];
Bitboard magicBishopMoves[64][IMAX_BISHOP];
MagicSquareInfoRook magicSquareInfoRook[64];
MagicSquareInfoBishop magicSquareInfoBishop[64];
/* *INDENT-OFF* */
const Bitboard magicRookNumber[64] = {
2341871876025885824llu, 5908793080399659264llu,
2814784401577026llu, 4755810071654563842llu,
4683749110191751172llu, 648520571176420352llu,
288793875996213508llu, 36039242390061312llu,
2233855853176307712llu, 360296835543278592llu,
37470368710784llu, 2261832991510528llu,
74595267411776576llu, 4612831726723531008llu,
17491104022660138llu, 9015996489662496llu,
164381455144716288llu, 4785426803991552llu,
2603080765009821794llu, 4504870937840771llu,
73202185810346241llu, 2594073935322554944llu,
577059170398781952llu, 687199551504llu,
36029072970620928llu, 4755818807417635204llu,
2305854279342097445llu, 4654506018003485187llu,
1369095394823243808llu, 1650609881216llu,
35189740863840llu, 17609634498592llu,
17867407885440llu, 1307170084179935305llu,
5224509820511455237llu, 30399366238175240llu,
685674177139050632llu, 4504708001565696llu,
576777574861506688llu, 2305843147759948801llu,
36046664624070657llu, 2305862800624326656llu,
35201686183936llu, 76563943050448912llu,
4828140284174931982llu, 93630429790212llu,
2305862800758624268llu, 4918212371161546978llu,
1197987317416064llu, 4629700452154347536llu,
144220742299427329llu, 1152928385211832832llu,
40132191457288llu, 9354573578272llu,
650209674406199320llu, 36029355649925192llu,
3470081245843620386llu, 9208682512641llu,
586664357648667141llu, 113161891886927874llu,
19144700892151826llu, 594756909391937601llu,
562958551810122llu, 1152922124158043138llu,
};
const Bitboard magicBishopNumber[64] = {
2287018567549508llu, 20833559275112450llu,
1157535125460746242llu, 2343279465658384466llu,
182423557274534246llu, 91204498130747394llu,
79165240377360llu, 18024053647361153llu,
4756927389883318784llu, 2377974339296303121llu,
1529092243969llu, 18016872700051744llu,
1153204084472553600llu, 873698516757668385llu,
1125942867148800llu, 26423192526848llu,
289939073072784384llu, 10714208241454656llu,
2306405960274414104llu, 54114131212519426llu,
109212291534684230llu, 2306971108957557248llu,
288239189760215296llu, 166643228131737628llu,
3459894829004630016llu, 35193180131968llu,
576478344523031040llu, 1134696069202368llu,
298367873364066368llu, 2882596248975577091llu,
432437927499531776llu, 72621163549300482llu,
468396630660612192llu, 576812875222894592llu,
3463272528741531664llu, 2612123106223325312llu,
3242874314789487108llu, 3461016494560002066llu,
4539883779662384llu, 5909074606504807464llu,
4684333518172472324llu, 306280543752814656llu,
2345387698176llu, 293016142258114592llu,
5073215437209668llu, 79251277611040llu,
602532708688384llu, 20310252071682068llu,
4467607076866llu, 648573875995549696llu,
288232580007339520llu, 1188986585695191042llu,
9306611390751752llu, 5498105049088llu,
4625205909830770716llu, 1152994261659095304llu,
126118725618245632llu, 2305851875981395204llu,
351843796394505llu, 40532672078233696llu,
9009398294791225llu, 4611688257515749392llu,
1152930369572702464llu, 2306989456245202960llu,
};
/* *INDENT-ON* */
bool testSquare(const Bitboard bitboard, const Square square)
{
return (bool) (((bitboard) & minValue[(square)]) != EMPTY_BITBOARD);
}
/**
* Get the king moves for the specified square.
*/
Bitboard getKingMoves(const Square square)
{
return generalMoves[KING][square];
}
/**
* Get castling moves depending from the castling rights and
* the current position.
*/
Bitboard getCastlingMoves(const Color color, const BYTE castlingRights,
const Bitboard obstacles)
{
if (color == WHITE)
{
return castlings[WHITE][castlingRights][obstacles & 0xFF];
}
else
{
return castlings[BLACK][castlingRights][obstacles >> 56];
}
}
/**
* Get the queen moves for the specified square.
*/
/*
Bitboard getQueenMoves(const Square square, const BYTE * obstacles)
{
const ObstacleSquareInfo *_obsi = &obsi[square];
return _obsi->hLane[obstacles[_obsi->hLaneNumber]] |
_obsi->vLane[obstacles[_obsi->vLaneNumber]] |
_obsi->uLane[obstacles[_obsi->uLaneNumber]] |
_obsi->dLane[obstacles[_obsi->dLaneNumber]];
}
*/
int getWidth(const Bitboard set)
{
if (set == EMPTY_BITBOARD)
{
return 0;
}
else
{
File leftMost = FILE_A, rightMost = FILE_H;
while ((set & squaresOfFile[leftMost]) == EMPTY_BITBOARD)
{
leftMost++;
}
while ((set & squaresOfFile[rightMost]) == EMPTY_BITBOARD)
{
rightMost--;
}
return rightMost - leftMost;
}
}
/**
* Get the queen moves for the specified square.
*/
Bitboard getMagicQueenMoves(const Square square, const Bitboard obstacles)
{
MagicSquareInfoRook *msir = &magicSquareInfoRook[square];
MagicSquareInfoBishop *msib = &magicSquareInfoBishop[square];
return
msir->moves[((obstacles & msir->preMask) * msir->magicNumber) >> 52] |
msib->moves[((obstacles & msib->preMask) * msib->magicNumber) >> 55];
}
/**
* Get the rook moves for the specified square.
*/
Bitboard getRookMoves(const Square square, const BYTE * obstacles)
{
const ObstacleSquareInfo *_obsi = &obsi[square];
return _obsi->hLane[obstacles[_obsi->hLaneNumber]] |
_obsi->vLane[obstacles[_obsi->vLaneNumber]];
}
/**
* Get the rook moves for the specified square.
*/
Bitboard getMagicRookMoves(const Square square, const Bitboard obstacles)
{
MagicSquareInfoRook *msir = &magicSquareInfoRook[square];
return
msir->moves[((obstacles & msir->preMask) * msir->magicNumber) >> 52];
}
/**
* Get the bishop moves for the specified square.
*/
Bitboard getBishopMoves(const Square square, const BYTE * obstacles)
{
const ObstacleSquareInfo *_obsi = &obsi[square];
return _obsi->uLane[obstacles[_obsi->uLaneNumber]] |
_obsi->dLane[obstacles[_obsi->dLaneNumber]];
}
/**
* Get the bishop moves for the specified square.
*/
Bitboard getMagicBishopMoves(const Square square, const Bitboard obstacles)
{
MagicSquareInfoBishop *msib = &magicSquareInfoBishop[square];
return
msib->moves[((obstacles & msib->preMask) * msib->magicNumber) >> 55];
}
/**
* Get the knight moves for the specified square.
*/
Bitboard getKnightMoves(const Square square)
{
return generalMoves[KNIGHT][square];
}
/**
* Get the pawn captures for the specified square.
*/
Bitboard getPawnCaptures(const Piece piece, const Square square,
const Bitboard allPieces)
{
return generalMoves[piece][square] & allPieces;
}
/**
* Get the pawn advances for the specified square.
*/
Bitboard getPawnAdvances(const Color color, const Square square,
const Bitboard obstacles)
{
Bitboard advances;
if (color == WHITE)
{
advances = (minValue[square] << 8) & ~obstacles;
if (rank(square) == RANK_2)
{
advances |= (advances << 8) & ~obstacles;
}
}
else
{
advances = (minValue[square] >> 8) & ~obstacles;
if (rank(square) == RANK_7)
{
advances |= (advances >> 8) & ~obstacles;
}
}
return advances;
}
/**
* Get the pawns interested in advancing to the specified square.
*/
Bitboard getInterestedPawns(const Color color, const Square square,
const Bitboard obstacles)
{
Bitboard interestedPawns;
if (color == WHITE)
{
interestedPawns = minValue[square] >> 8;
if (rank(square) == RANK_4 &&
(interestedPawns & obstacles) == EMPTY_BITBOARD)
{
interestedPawns |= minValue[square] >> 16;
}
}
else
{
interestedPawns = minValue[square] << 8;
if (rank(square) == RANK_5 &&
(interestedPawns & obstacles) == EMPTY_BITBOARD)
{
interestedPawns |= minValue[square] << 16;
}
}
return interestedPawns;
}
/**
* Get the squares between the two specified squares.
*/
Bitboard getSquaresBetween(const Square square1, const Square square2)
{
return squaresBetween[square1][square2];
}
/**
* Get the squares behind 'target', as seen from 'viewpoint'.
*/
Bitboard getSquaresBehind(const Square target, const Square viewpoint)
{
return squaresBehind[target][viewpoint];
}
/**
* Shift all set squares one file to the left.
*/
Bitboard shiftLeft(const Bitboard bitboard)
{
return (bitboard & nonA) >> 1;
}
/**
* Shift all set squares one file to the right.
*/
Bitboard shiftRight(const Bitboard bitboard)
{
return (bitboard & nonH) << 1;
}
/**
* Get all squares lateral to the specified squares.
*/
Bitboard getLateralSquares(const Bitboard squares)
{
return ((squares & nonA) >> 1) | ((squares & nonH) << 1);
}
/**
* Get the squares of the specified file.
*/
Bitboard getSquaresOfFile(const File file)
{
return squaresOfFile[file];
}
/**
* Get the squares of the specified rank.
*/
Bitboard getSquaresOfRank(const Rank rank)
{
return squaresOfRank[rank];
}
/**
* Get the number of set squares in the specified bitboard.
*/
int getNumberOfSetSquares(const Bitboard bitboard)
{
return __builtin_popcountll(bitboard);
}
/**
* Get the rank overlay of the specified bitboard.
*/
int getRankOverlay(const Bitboard bitboard)
{
return rankOverlay[(bitboard) & UHEX_FFFF] |
rankOverlay[(bitboard >> 16) & UHEX_FFFF] |
rankOverlay[(bitboard >> 32) & UHEX_FFFF] |
rankOverlay[(bitboard >> 48) & UHEX_FFFF];
}
/**
* Get the moves of the the specified piece.
*/
Bitboard getMoves(Square square, Piece piece, Bitboard allPieces)
{
switch (pieceType(piece))
{
case PAWN:
return getPawnCaptures(piece, square, allPieces) |
getPawnAdvances(pieceColor(piece), square, allPieces);
case KING:
return getKingMoves(square);
case KNIGHT:
return getKnightMoves(square);
case ROOK:
return getMagicRookMoves(square, allPieces);
case BISHOP:
return getMagicBishopMoves(square, allPieces);
default:
return getMagicQueenMoves(square, allPieces);
}
}
/**
* Get the capture moves of the the specified piece.
*/
Bitboard getCaptureMoves(Square square, Piece piece, Bitboard allPieces)
{
switch (pieceType(piece))
{
case PAWN:
return getPawnCaptures(piece, square, allPieces);
case KING:
return getKingMoves(square);
case KNIGHT:
return getKnightMoves(square);
case ROOK:
return getMagicRookMoves(square, allPieces);
case BISHOP:
return getMagicBishopMoves(square, allPieces);
default:
return getMagicQueenMoves(square, allPieces);
}
}
/**
* Set a square in the specified vector of obstacles.
*/
void setObstacleSquare(Square square, BYTE obstacles[NUM_LANES])
{
SquareLaneInfo *sqi = &squareLaneInfo[square];
obstacles[sqi->hLane] |= sqi->hLaneSetMask;
obstacles[sqi->vLane] |= sqi->vLaneSetMask;
obstacles[sqi->uLane] |= sqi->uLaneSetMask;
obstacles[sqi->dLane] |= sqi->dLaneSetMask;
}
/**
* Clear a square in the specified vector of obstacles.
*/
void clearObstacleSquare(Square square, BYTE obstacles[NUM_LANES])
{
SquareLaneInfo *sqi = &squareLaneInfo[square];
obstacles[sqi->hLane] &= sqi->hLaneClearMask;
obstacles[sqi->vLane] &= sqi->vLaneClearMask;
obstacles[sqi->uLane] &= sqi->uLaneClearMask;
obstacles[sqi->dLane] &= sqi->dLaneClearMask;
}
/**
* Calculate all obstacles according to the specified bitboard.
*/
void calculateObstacles(Bitboard board, BYTE obstacles[NUM_LANES])
{
Square square;
memset(obstacles
, 0x00, NUM_LANES
);
ITERATE(square)
{
if (board & minValue[square])
{
setObstacleSquare(square, obstacles);
}
}
}
/**
* Get the number of a set square and clear the corresponding bit.
*
* @return NO_SQUARE if no square was set.
*/
Square getLastSquare(Bitboard * vector);
/**
* Extend all set bits by one square into all directions.
*/
void floodBoard(Bitboard * board);
/**
* Get the targets of all pawns specified by 'whitePawns'.
*/
Bitboard getWhitePawnTargets(const Bitboard whitePawns)
{
return ((whitePawns & nonA) << 7) | ((whitePawns & nonH) << 9);
}
/**
* Get the targets of all pawns specified by 'blackPawns'.
*/
Bitboard getBlackPawnTargets(const Bitboard blackPawns)
{
return ((blackPawns & nonA) >> 9) | ((blackPawns & nonH) >> 7);
}
/**
* Iteration shortcuts
*/
#define ITERATE_BITBOARD(b,sq) while ( ( sq = getLastSquare(b) ) >= 0 )
void floodBoard(Bitboard * board)
{
const Bitboard toLeft = *board & nonA, toRight = *board & nonH;
*board = (toLeft >> 1) | (toLeft << 7) | (*board >> 8) | (toLeft >> 9) |
(toRight << 1) | (toRight >> 7) | (*board << 8) | (toRight << 9);
}
Square getLastSquare(Bitboard * vector)
{
if (*vector == EMPTY_BITBOARD)
{
return NO_SQUARE;
}
else
{
const int index = 63 - __builtin_clzll(*vector);
*vector &= maxValue[index];
return index;
}
}
Square getFirstSquare(Bitboard * vector)
{
if (*vector == EMPTY_BITBOARD)
{
return NO_SQUARE;
}
else
{
const int index = __builtin_ctzll(*vector);
*vector &= maxValue[index];
return index;
}
}
int getSetSquares(const Bitboard board, UINT8 squares[_64_])
{
int index;
UINT8 *currentSquare = &squares[0];
if ((index = (int) (0xFFFF & board)) != 0)
{
const SetSquaresInfo *info = &setSquares[0][index];
memcpy(currentSquare
, info
->setSquares
, info
->numSetSquares
);
currentSquare += info->numSetSquares;
}
if ((index = (int) (0xFFFF & (board >> 16))) != 0)
{
const SetSquaresInfo *info = &setSquares[1][index];
memcpy(currentSquare
, info
->setSquares
, info
->numSetSquares
);
currentSquare += info->numSetSquares;
}
if ((index = (int) (0xFFFF & (board >> 32))) != 0)
{
const SetSquaresInfo *info = &setSquares[2][index];
memcpy(currentSquare
, info
->setSquares
, info
->numSetSquares
);
currentSquare += info->numSetSquares;
}
if ((index = (int) (board >> 48)) != 0)
{
const SetSquaresInfo *info = &setSquares[3][index];
memcpy(currentSquare
, info
->setSquares
, info
->numSetSquares
);
currentSquare += info->numSetSquares;
}
return (int) (currentSquare - &squares[0]);
}
Bitboard getMultipleSquaresBetween(const Square origin, Bitboard targets)
{
Bitboard squares = targets;
Square targetSquare;
Bitboard *sqb = &(squaresBetween[origin][0]);
ITERATE_BITBOARD(&targets, targetSquare)
{
squares |= sqb[targetSquare];
}
return squares;
}
int getFloodValue(const Square origin, const Bitboard targets,
const Bitboard permittedSquares)
{
Bitboard floodedSquares = getKingMoves(origin) & permittedSquares;
Bitboard oldFloodedSquares = minValue[origin];
int numSteps = 1;
while ((targets & floodedSquares) == EMPTY_BITBOARD &&
floodedSquares != oldFloodedSquares)
{
oldFloodedSquares = floodedSquares;
floodBoard(&floodedSquares);
floodedSquares |= oldFloodedSquares;
floodedSquares &= permittedSquares;
numSteps++;
}
return numSteps;
}
static void initializeKingMoves()
{
int offset[] = { 1, -1, 7, -7, 8, -8, 9, -9 }, direction;
Square square;
ITERATE(square)
{
for (direction = 0; direction < 8; direction++)
{
Square target = (Square) (square + offset[direction]);
if (squareIsValid(target) && distance(square, target) == 1)
{
generalMoves[KING][square] |= minValue[target];
}
}
}
}
static void initializeRookMoves()
{
int offset[] = { 1, -1, 8, -8 }, direction, moveLength;
Square square;
ITERATE(square)
{
for (direction = 0; direction < 4; direction++)
{
for (moveLength = 1; moveLength <= 7; moveLength++)
{
Square target =
(Square) (square + offset[direction] * moveLength);
bool sameFile = (bool) (file(square) == file(target));
bool sameRow = (bool) (rank(square) == rank(target));
if (squareIsValid(target) && (sameFile || sameRow))
{
generalMoves[ROOK][square] |= minValue[target];
}
else
{
break;
}
}
}
}
}
static void initializeBishopMoves()
{
int offset[] = { 7, -7, 9, -9 }, direction, moveLength;
Square square;
ITERATE(square)
{
for (direction = 0; direction < 4; direction++)
{
for (moveLength = 1; moveLength <= 7; moveLength++)
{
Square target =
(Square) (square + offset[direction] * moveLength);
int hDistance = horizontalDistance(square, target);
int vDistance = verticalDistance(square, target);
if (squareIsValid(target) && hDistance == vDistance)
{
generalMoves[BISHOP][square] |= minValue[target];
}
else
{
break;
}
}
}
}
}
static void initializeQueenMoves()
{
Square square;
ITERATE(square)
{
generalMoves[QUEEN][square] =
generalMoves[ROOK][square] | generalMoves[BISHOP][square];
}
}
static void initializeKnightMoves()
{
int offset[] = { 6, -6, 10, -10, 15, -15, 17, -17 }, direction;
Square square;
ITERATE(square)
{
for (direction = 0; direction < 8; direction++)
{
Square target = (Square) (square + offset[direction]);
if (squareIsValid(target) && distance(square, target) <= 2)
{
generalMoves[KNIGHT][square] |= minValue[target];
}
}
}
}
static void initializePawnMoves()
{
Square square;
ITERATE(square)
{
if (file(square) != FILE_A)
{
if (square <= H8 - 7)
{
generalMoves[WHITE_PAWN][square] |= minValue[square + 7];
}
if (square >= A1 + 9)
{
generalMoves[BLACK_PAWN][square] |= minValue[square - 9];
}
}
if (file(square) != FILE_H)
{
if (square <= H8 - 9)
{
generalMoves[WHITE_PAWN][square] |= minValue[square + 9];
}
if (square >= A1 + 7)
{
generalMoves[BLACK_PAWN][square] |= minValue[square - 7];
}
}
}
}
static Bitboard calculateSquaresBehind(Square square, int offset)
{
Bitboard squares = EMPTY_BITBOARD;
for (square = (Square) (square + offset);
squareIsValid(square) &&
distance(square, (Square) (square - offset)) == 1;
square = (Square) (square + offset))
{
Bitboard mv = minValue[square];
squares |= mv;
}
return squares;
}
static void initializeSquaresBehind()
{
Square sq1, sq2;
ITERATE(sq1)
{
Bitboard squares = generalMoves[QUEEN][sq1];
ITERATE_BITBOARD(&squares, sq2)
{
int offset = offset(sq1, sq2);
squaresBehind[sq2][sq1] = calculateSquaresBehind(sq2, offset);
}
}
}
static Bitboard calculateSquaresBetween(Square sq1, Square sq2)
{
Bitboard squares = EMPTY_BITBOARD;
int _offset = offset(sq1, sq2), square;
for (square = sq1 + _offset; square != sq2; square += _offset)
{
squares |= minValue[square];
}
return squares;
}
static void initializeSquaresBetween()
{
Square sq1, sq2;
ITERATE(sq1)
{
Bitboard squares = generalMoves[QUEEN][sq1];
ITERATE_BITBOARD(&squares, sq2)
{
squaresBetween[sq1][sq2] = calculateSquaresBetween(sq1, sq2);
}
}
}
static void initializeSquareLaneInfo()
{
Square square;
ITERATE(square)
{
SquareLaneInfo *sqi = &squareLaneInfo[square];
sqi->hLane = hLaneNumber[square] = HLANE(square);
sqi->hLaneSetMask = (BYTE) minValue[HLANEBIT(square)];
sqi->hLaneClearMask = (BYTE) ~ sqi->hLaneSetMask;
sqi->vLane = vLaneNumber[square] = VLANE(square) + 8;
sqi->vLaneSetMask = (BYTE) minValue[VLANEBIT(square)];
sqi->vLaneClearMask = (BYTE) ~ sqi->vLaneSetMask;
sqi->uLane = uLaneNumber[square] = ULANE(square) + 16;
sqi->uLaneSetMask = (BYTE) minValue[ULANEBIT(square)];
sqi->uLaneClearMask = (BYTE) ~ sqi->uLaneSetMask;
sqi->dLane = dLaneNumber[square] = DLANE(square) + 31;
sqi->dLaneSetMask = (BYTE) minValue[DLANEBIT(square)];
sqi->dLaneClearMask = (BYTE) ~ sqi->dLaneSetMask;
}
}
static Bitboard getHlaneVector(int lane, BYTE mask)
{
int i;
Bitboard v = EMPTY_BITBOARD;
for (i = 0; i < 8; i++)
{
if (mask & minValue[i])
{
v |= minValue[7 - i];
}
}
v <<= 8 * lane;
return v;
}
static Bitboard getVlaneVector(int lane, BYTE mask)
{
int i;
Bitboard v = EMPTY_BITBOARD;
for (i = 0; i < 8; i++)
{
if (mask & minValue[i])
{
v |= minValue[8 * (7 - i)];
}
}
v <<= lane;
return v;
}
static Bitboard getUlaneVector(int lane, BYTE mask)
{
int i;
Bitboard v = EMPTY_BITBOARD;
for (i = 0; i < 8; i++)
{
v <<= 8;
if (mask & minValue[i])
{
v |= minValue[7 - i];
}
}
if (lane < 7)
{
for (i = lane; i < 7; i++)
{
v = (v & nonA) >> 1;
}
}
else
{
for (i = lane; i > 7; i--)
{
v = (v & nonH) << 1;
}
}
return v;
}
static Bitboard getDlaneVector(int lane, BYTE mask)
{
int i;
Bitboard v = EMPTY_BITBOARD;
for (i = 0; i < 8; i++)
{
v <<= 8;
if (mask & minValue[7 - i])
{
v |= minValue[i];
}
}
if (lane < 7)
{
for (i = lane; i < 7; i++)
{
v = (v & nonA) >> 1;
}
}
else
{
for (i = lane; i > 7; i--)
{
v = (v & nonH) << 1;
}
}
return v;
}
static Bitboard getLaneMask(Square square, int offset,
Bitboard legalSquares, Bitboard obstacles)
{
Bitboard laneMask = EMPTY_BITBOARD, mv = EMPTY_BITBOARD;
while ((square = (Square) (square + offset)) >= A1 &&
square <= H8 && ((mv = minValue[square]) & legalSquares))
{
laneMask |= mv;
if (mv & obstacles)
{
break;
}
}
return laneMask;
}
static Bitboard getHLaneMask(Square square, BYTE mask)
{
int lane = HLANE(square);
Bitboard legalSquares = getHlaneVector(lane, 255);
Bitboard obstacles = getHlaneVector(lane, mask);
Bitboard laneMask = getLaneMask(square, 1, legalSquares, obstacles);
laneMask |= getLaneMask(square, -1, legalSquares, obstacles);
return laneMask;
}
static Bitboard getVLaneMask(Square square, BYTE mask)
{
int lane = VLANE(square);
Bitboard legalSquares = getVlaneVector(lane, 255);
Bitboard obstacles = getVlaneVector(lane, mask);
Bitboard laneMask = getLaneMask(square, 8, legalSquares, obstacles);
laneMask |= getLaneMask(square, -8, legalSquares, obstacles);
return laneMask;
}
static Bitboard getULaneMask(Square square, BYTE mask)
{
int lane = ULANE(square);
Bitboard legalSquares = getUlaneVector(lane, 255);
Bitboard obstacles = getUlaneVector(lane, mask);
Bitboard laneMask = getLaneMask(square, 9, legalSquares, obstacles);
laneMask |= getLaneMask(square, -9, legalSquares, obstacles);
return laneMask;
}
static Bitboard getDLaneMask(Square square, BYTE mask)
{
int lane = DLANE(square);
Bitboard legalSquares = getDlaneVector(lane, 255);
Bitboard obstacles = getDlaneVector(lane, mask);
Bitboard laneMask = getLaneMask(square, 7, legalSquares, obstacles);
laneMask |= getLaneMask(square, -7, legalSquares, obstacles);
return laneMask;
}
static Bitboard getWhitePawnMoves(Square square, BYTE laneMask)
{
int lane = VLANE(square);
Bitboard moves = EMPTY_BITBOARD, board = getVlaneVector(lane, laneMask);
if (square >= A2 && square <= H7 && (board & minValue[square + 8]) == 0)
{
moves |= minValue[square + 8];
if (square <= H2 && (board & minValue[square + 16]) == 0)
{
moves |= minValue[square + 16];
}
}
return moves;
}
static Bitboard getInterestedWhitePawns(Square square, BYTE laneMask)
{
int lane = VLANE(square);
Bitboard pawns = EMPTY_BITBOARD, board = getVlaneVector(lane, laneMask);
if (square >= A3 && square <= H8 && (board & minValue[square]) == 0)
{
pawns |= minValue[square - 8];
if (rank(square) == RANK_4 && (board & minValue[square - 8]) == 0)
{
pawns |= minValue[square - 16];
}
}
return pawns;
}
static Bitboard getBlackPawnMoves(Square square, BYTE laneMask)
{
int lane = VLANE(square);
Bitboard moves = EMPTY_BITBOARD, board = getVlaneVector(lane, laneMask);
if (square >= A2 && square <= H7 && (board & minValue[square - 8]) == 0)
{
moves |= minValue[square - 8];
if (square >= A7 && (board & minValue[square - 16]) == 0)
{
moves |= minValue[square - 16];
}
}
return moves;
}
static Bitboard getInterestedBlackPawns(Square square, BYTE laneMask)
{
int lane = VLANE(square);
Bitboard pawns = EMPTY_BITBOARD, board = getVlaneVector(lane, laneMask);
if (square >= A1 && square <= H6 && (board & minValue[square]) == 0)
{
pawns |= minValue[square + 8];
if (rank(square) == RANK_5 && (board & minValue[square + 8]) == 0)
{
pawns |= minValue[square + 16];
}
}
return pawns;
}
static void initializeLaneMasks()
{
Square square;
int i;
ITERATE(square)
{
for (i = 0; i <= 255; i++)
{
BYTE mask = (BYTE) i;
hlane[square][i] = getHLaneMask(square, mask);
vlane[square][i] = getVLaneMask(square, mask);
ulane[square][i] = getULaneMask(square, mask);
dlane[square][i] = getDLaneMask(square, mask);
pawnMoves[WHITE][square][i] = getWhitePawnMoves(square, mask);
pawnMoves[BLACK][square][i] = getBlackPawnMoves(square, mask);
interestedPawns[WHITE][square][i] =
getInterestedWhitePawns(square, mask);
interestedPawns[BLACK][square][i] =
getInterestedBlackPawns(square, mask);
}
}
ITERATE(square)
{
int i;
obsi[square].hLaneNumber = hLaneNumber[square];
obsi[square].vLaneNumber = vLaneNumber[square];
obsi[square].uLaneNumber = uLaneNumber[square];
obsi[square].dLaneNumber = dLaneNumber[square];
for (i = 0; i < 256; i++)
{
obsi[square].hLane[i] = hlane[square][i];
obsi[square].vLane[i] = vlane[square][i];
obsi[square].uLane[i] = ulane[square][i];
obsi[square].dLane[i] = dlane[square][i];
}
}
}
static Bitboard getCastlings(const Bitboard obstacles)
{
Bitboard castlings = EMPTY_BITBOARD;
if ((obstacles & minValue[F1]) == EMPTY_BITBOARD &&
(obstacles & minValue[G1]) == EMPTY_BITBOARD)
{
castlings |= minValue[G1];
}
if ((obstacles & minValue[B1]) == EMPTY_BITBOARD &&
(obstacles & minValue[C1]) == EMPTY_BITBOARD &&
(obstacles & minValue[D1]) == EMPTY_BITBOARD)
{
castlings |= minValue[C1];
}
return castlings;
}
static void initializeCastlings()
{
int i, c;
for (i = 0; i <= 255; i++)
{
BYTE mask = (BYTE) i;
Bitboard moves = getCastlings((Bitboard) mask);
for (c = 0; c <= 15; c++)
{
castlings[WHITE][c][mask] = castlings[BLACK][c][mask] = 0;
if (moves & minValue[G1])
{
if (c & WHITE_00)
{
castlings[WHITE][c][mask] |= minValue[G1];
}
if (c & BLACK_00)
{
castlings[BLACK][c][mask] |= minValue[G8];
}
}
if (moves & minValue[C1])
{
if (c & WHITE_000)
{
castlings[WHITE][c][mask] |= minValue[C1];
}
if (c & BLACK_000)
{
castlings[BLACK][c][mask] |= minValue[C8];
}
}
}
}
}
static INT8 _getNumberOfSetBits(INT32 v)
{
int count = 0, i;
for (i = 0; i < 16; i++)
{
count += (v >> i) & 1;
}
return (INT8) count;
}
static UINT8 _getRankOverlay(INT32 v)
{
return (UINT8) ((v & 0xff) | ((v >> 8) & 0xff));
}
unsigned int getMinimumDistance(const Bitboard targets, const Square square)
{
unsigned int distance;
for (distance = 1; distance <= 7; distance++)
{
if ((squaresInDistance[distance][square] & targets) != EMPTY_BITBOARD)
{
return distance;
}
}
return 0;
}
unsigned int getMaximumDistance(const Bitboard targets, const Square square)
{
unsigned int distance;
for (distance = 7; distance > 0; distance--)
{
if ((squaresInDistance[distance][square] & targets) != EMPTY_BITBOARD)
{
return distance;
}
}
return 0;
}
static Bitboard getPremaskExclusions(const Square square)
{
if (testSquare(border, square))
{
Bitboard exclusions = EMPTY_BITBOARD;
if (testSquare(squaresOfFile[FILE_A], square) == FALSE)
{
exclusions |= squaresOfFile[FILE_A];
}
if (testSquare(squaresOfFile[FILE_H], square) == FALSE)
{
exclusions |= squaresOfFile[FILE_H];
}
if (testSquare(squaresOfRank[RANK_1], square) == FALSE)
{
exclusions |= squaresOfRank[RANK_1];
}
if (testSquare(squaresOfRank[RANK_8], square) == FALSE)
{
exclusions |= squaresOfRank[RANK_8];
}
return exclusions;
}
else
{
return border;
}
}
static void initializePremasks()
{
Square square;
ITERATE(square)
{
preMaskRook[square] = generalMoves[WHITE_ROOK][square] &
~getPremaskExclusions(square);
preMaskBishop[square] = generalMoves[WHITE_BISHOP][square] &
~getPremaskExclusions(square);
}
}
static void initializeMagicRookMoves(const Square square)
{
Square squareOfIndex[12];
Bitboard allMoves = preMaskRook[square];
const Bitboard premask = preMaskRook[square];
int i, pieceSetup;
Square sq1;
BYTE obstacles[NUM_LANES];
const Bitboard magicNumber = magicRookNumber[square];
for (i = 0; i < IMAX_ROOK; i++)
{
magicRookMoves[square][i] = EMPTY_BITBOARD;
}
for (i = 0; i < 12; i++)
{
squareOfIndex[i] = NO_SQUARE;
}
i = 0;
ITERATE_BITBOARD(&allMoves, sq1)
{
squareOfIndex[i++] = sq1;
}
for (pieceSetup = 0; pieceSetup < 4096; pieceSetup++)
{
Bitboard currentSetup = EMPTY_BITBOARD, effectiveMoves;
int j = 1;
Bitboard magicIndex;
for (i = 0; i < 12 && squareOfIndex[i] != NO_SQUARE; i++)
{
if ((pieceSetup & j) != 0)
{
setSquare(currentSetup, squareOfIndex[i]);
}
j *= 2;
}
calculateObstacles(currentSetup, obstacles);
effectiveMoves = getRookMoves(square, obstacles);
magicIndex = ((currentSetup & premask) * magicNumber) >> 52;
magicRookMoves[square][magicIndex] = effectiveMoves;
}
}
static void initializeMagicBishopMoves(const Square square)
{
Square squareOfIndex[12];
Bitboard allMoves = preMaskBishop[square];
const Bitboard premask = preMaskBishop[square];
int i, pieceSetup;
Square sq1;
BYTE obstacles[NUM_LANES];
const Bitboard magicNumber = magicBishopNumber[square];
for (i = 0; i < IMAX_BISHOP; i++)
{
magicBishopMoves[square][i] = EMPTY_BITBOARD;
}
for (i = 0; i < 12; i++)
{
squareOfIndex[i] = NO_SQUARE;
}
i = 0;
ITERATE_BITBOARD(&allMoves, sq1)
{
squareOfIndex[i++] = sq1;
}
for (pieceSetup = 0; pieceSetup < 4096; pieceSetup++)
{
Bitboard currentSetup = EMPTY_BITBOARD, effectiveMoves;
int j = 1;
Bitboard magicIndex;
for (i = 0; i < 12 && squareOfIndex[i] != NO_SQUARE; i++)
{
if ((pieceSetup & j) != 0)
{
setSquare(currentSetup, squareOfIndex[i]);
}
j *= 2;
}
calculateObstacles(currentSetup, obstacles);
effectiveMoves = getBishopMoves(square, obstacles);
magicIndex = ((currentSetup & premask) * magicNumber) >> 55;
magicBishopMoves[square][magicIndex] = effectiveMoves;
}
}
/* #define GENERATE_MAGIC_NUMBERS */
#ifdef GENERATE_MAGIC_NUMBERS
#define IMAX 4096
#define BMAX 12
Bitboard collisions[IMAX];
static bool testMagicNumber(const Bitboard magicNumber, const Square square,
const bool rookMoves)
{
Square squareOfIndex[BMAX];
const Bitboard premask =
(rookMoves ? preMaskRook[square] : preMaskBishop[square]);
Bitboard allMoves = premask;
int i, pieceSetup;
Square sq1;
BYTE obstacles[NUM_LANES];
for (i = 0; i < IMAX; i++)
{
collisions[i] = EMPTY_BITBOARD;
}
for (i = 0; i < BMAX; i++)
{
squareOfIndex[i] = NO_SQUARE;
}
i = 0;
ITERATE_BITBOARD(&allMoves, sq1)
{
squareOfIndex[i++] = sq1;
}
for (pieceSetup = 0; pieceSetup < IMAX; pieceSetup++)
{
Bitboard currentSetup = EMPTY_BITBOARD, effectiveMoves, calcBase;
int j = 1;
Bitboard magicIndex;
const int shift = (rookMoves ? 64 - 12 : 64 - 9);
for (i = 0; i < BMAX && squareOfIndex[i] != NO_SQUARE; i++)
{
if ((pieceSetup & j) != 0)
{
setSquare(currentSetup, squareOfIndex[i]);
}
j *= 2;
}
calculateObstacles(currentSetup, obstacles);
effectiveMoves =
(rookMoves ? getRookMoves(square, obstacles) :
getBishopMoves(square, obstacles));
calcBase = currentSetup & premask;
magicIndex = (calcBase * magicNumber) >> shift;
if (collisions[magicIndex] == EMPTY_BITBOARD)
{
collisions[magicIndex] = effectiveMoves;
}
else
{
if (effectiveMoves != collisions[magicIndex])
{
return FALSE; /* severe collision -> magic number not suitable */
}
}
}
return TRUE; /* the given magic number is valid */
}
static UINT64 get64bitRandom()
{
const UINT64 limit = (RAND_MAX * 13) / 100;
UINT64 rn = 0, runningOne = 1;
int i;
for (i = 0; i < 64; i++)
{
{
rn |= runningOne;
}
runningOne *= 2;
}
return rn;
}
static void calculateMagicNumbers()
{
Square square;
ITERATE(square)
{
Bitboard magicNumber = get64bitRandom();
while (testMagicNumber(magicNumber, square, TRUE) == FALSE)
{
magicNumber = get64bitRandom();
}
printf("%llu, ", magicNumber
);
if ((square % 2) == 1)
{
}
}
ITERATE(square)
{
Bitboard magicNumber = get64bitRandom();
while (testMagicNumber(magicNumber, square, FALSE) == FALSE)
{
magicNumber = get64bitRandom();
}
printf("%llu, ", magicNumber
);
if ((square % 2) == 1)
{
}
}
getKeyStroke();
}
#endif /* GENREATE_MAGIC_NUMBERS */
Bitboard getFlippedBitboard(Bitboard original)
{
Bitboard flipped = EMPTY_BITBOARD;
Square square;
ITERATE_BITBOARD(&original, square)
{
setSquare(flipped, getFlippedSquare(square));
}
return flipped;
}
int initializeModuleBitboard()
{
INT32 i;
UINT32 j;
INT8 k, indexLow, indexHigh;
UINT64 min = 1;
Square square;
if (isInitialized)
{
return 0;
}
else
{
isInitialized = TRUE;
}
ITERATE(i)
{
minValue[i] = min;
maxValue[i] = ~min;
min *= 2;
}
lowestBit[0] = highestBit[0] = NO_SQUARE;
numSetBits[0] = rankOverlay[0] = 0;
for (i = 1; i <= 0xffffL; i++)
{
numSetBits[i] = _getNumberOfSetBits(i);
rankOverlay[i] = _getRankOverlay(i);
j = i;
indexLow = indexHigh = NO_SQUARE;
for (k = 0x00; k <= 0x0f; k++)
{
if ((j & 1) == 1)
{
if (indexLow == NO_SQUARE)
{
indexLow = k;
}
indexHigh = k;
}
j >>= 1;
}
lowestBit[i] = indexLow;
highestBit[i] = indexHigh;
}
ITERATE(square)
{
int distance;
if (squareColor(square) == DARK)
{
setSquare(darkSquares, square);
clearSquare(lightSquares, square);
}
else
{
clearSquare(darkSquares, square);
setSquare(lightSquares, square);
}
for (distance = 0; distance <= 7; distance++)
{
Square square2;
squaresInDistance[distance][square] = EMPTY_BITBOARD;
ITERATE(square2)
{
if (distance(square, square2) <= distance)
{
setSquare(squaresInDistance[distance][square], square2);
}
}
}
for (distance = 0; distance <= 14; distance++)
{
Square square2;
squaresInTaxiDistance[distance][square] = EMPTY_BITBOARD;
ITERATE(square2)
{
if (taxiDistance(square, square2) <= distance)
{
setSquare(squaresInTaxiDistance[distance][square], square2);
}
}
}
}
for (i = FILE_A; i <= FILE_H; i++)
{
int j;
for (j = FILE_A; j <= FILE_H; j++)
{
int k;
squaresOfFileRange[i][j] = squaresOfRankRange[i][j] = EMPTY_BITBOARD;
for (k = FILE_A; k <= FILE_H; k++)
{
if ((k >= i && k <= j) || (k >= j && k <= i))
{
squaresOfFileRange[i][j] |= squaresOfFile[k];
squaresOfRankRange[i][j] |= squaresOfRank[k];
}
}
}
}
nonA = ~squaresOfFile[FILE_A], nonH = ~squaresOfFile[FILE_H];
center = minValue[D4] | minValue[D5] | minValue[E4] | minValue[E5];
extendedCenter =
(squaresOfFile[FILE_C] | squaresOfFile[FILE_D] |
squaresOfFile[FILE_E] | squaresOfFile[FILE_F]) &
(squaresOfRank[RANK_3] | squaresOfRank[RANK_4] |
squaresOfRank[RANK_5] | squaresOfRank[RANK_6]);
border = squaresOfFile[FILE_A] | squaresOfFile[FILE_H] |
squaresOfRank[RANK_1] | squaresOfRank[RANK_8];
queenSide =
squaresOfFile[FILE_A] | squaresOfFile[FILE_B] | squaresOfFile[FILE_C];
kingSide =
squaresOfFile[FILE_F] | squaresOfFile[FILE_G] | squaresOfFile[FILE_H];
centerFiles = squaresOfFile[FILE_D] | squaresOfFile[FILE_E];
promotionCandidates[WHITE] = squaresOfRank[RANK_7];
promotionCandidates[BLACK] = squaresOfRank[RANK_2];
initializeKingMoves();
initializeRookMoves();
initializeBishopMoves();
initializeQueenMoves();
initializeKnightMoves();
initializePawnMoves();
initializeSquaresBehind();
initializeSquaresBetween();
initializeSquareLaneInfo();
initializeLaneMasks();
initializeCastlings();
ITERATE(square)
{
const Bitboard corona = generalMoves[KING][square];
Square square2;
orthoKingAttackers[square] = diaKingAttackers[square] =
knightKingAttackers[square] = pawnKingAttackers[WHITE][square] =
pawnKingAttackers[BLACK][square] = EMPTY_BITBOARD;
squaresAbove[WHITE][square] = squaresAbove[BLACK][square] =
squaresBelow[WHITE][square] = squaresBelow[BLACK][square] =
squaresLeftOf[square] = squaresRightOf[square] = EMPTY_BITBOARD;
ITERATE(square2)
{
const Bitboard orthoSquares = generalMoves[ROOK][square2];
const Bitboard diaSquares = generalMoves[BISHOP][square2];
const Bitboard knightSquares = generalMoves[KNIGHT][square2];
const Bitboard whitePawnSquares = generalMoves[WHITE_PAWN][square2];
const Bitboard blackPawnSquares = generalMoves[BLACK_PAWN][square2];
if (square != square2 && (corona & orthoSquares) != EMPTY_BITBOARD &&
taxiDistance(square, square2) > 1)
{
setSquare(orthoKingAttackers[square], square2);
}
if (square != square2 && (corona & diaSquares) != EMPTY_BITBOARD &&
(distance(square, square2) > 1 ||
taxiDistance(square, square2) != 2))
{
setSquare(diaKingAttackers[square], square2);
}
if (square != square2 &&
(corona & knightSquares) != EMPTY_BITBOARD &&
testSquare(knightSquares, square) == EMPTY_BITBOARD)
{
setSquare(knightKingAttackers[square], square2);
}
if (square != square2 &&
(corona & whitePawnSquares) != EMPTY_BITBOARD &&
testSquare(whitePawnSquares, square) == EMPTY_BITBOARD)
{
setSquare(pawnKingAttackers[WHITE][square], square2);
}
if (square != square2 &&
(corona & blackPawnSquares) != EMPTY_BITBOARD &&
testSquare(blackPawnSquares, square) == EMPTY_BITBOARD)
{
setSquare(pawnKingAttackers[BLACK][square], square2);
}
if (rank(square2) < rank(square))
{
setSquare(squaresBelow[WHITE][square], square2);
setSquare(squaresAbove[BLACK][square], square2);
}
if (rank(square2) > rank(square))
{
setSquare(squaresAbove[WHITE][square], square2);
setSquare(squaresBelow[BLACK][square], square2);
}
if (file(square2) < file(square))
{
setSquare(squaresLeftOf[square], square2);
}
if (file(square2) > file(square))
{
setSquare(squaresRightOf[square], square2);
}
}
}
for (i = 0; i < 256; i++)
{
for (j = 0; j < 8; j++)
{
bitshiftGap[j][i] = (i == 0 ? 0 : 8);
for (k = 0; k < 8; k++)
{
if ((minValue[(int) k] & i) != 0
&& abs(j
- k
) < bitshiftGap
[j
][i
])
{
bitshiftGap
[j
][i
] = (UINT8
) abs(j
- k
);
}
}
}
}
for (i = 0; i < 4; i++)
{
UINT64 bitMask;
for (bitMask = 0; bitMask < 0x10000; bitMask++)
{
SetSquaresInfo *info = &setSquares[i][bitMask];
Bitboard board = bitMask << (16 * i);
Square square;
info->numSetSquares = 0;
ITERATE_BITBOARD(&board, square)
{
info->setSquares[info->numSetSquares++] = (UINT8) square;
}
}
}
initializePremasks();
ITERATE(square)
{
initializeMagicRookMoves(square);
initializeMagicBishopMoves(square);
}
ITERATE(square)
{
int i;
magicSquareInfoRook[square].preMask = preMaskRook[square];
magicSquareInfoRook[square].magicNumber = magicRookNumber[square];
for (i = 0; i < IMAX_ROOK; i++)
{
magicSquareInfoRook[square].moves[i] = magicRookMoves[square][i];
}
magicSquareInfoBishop[square].preMask = preMaskBishop[square];
magicSquareInfoBishop[square].magicNumber = magicBishopNumber[square];
for (i = 0; i < IMAX_BISHOP; i++)
{
magicSquareInfoBishop[square].moves[i] = magicBishopMoves[square][i];
}
}
/*
for (i = 0; i < 8; i++)
{
logDebug("0x%016llx,\n", squaresOfLateralFiles[i]);
}
getKeyStroke();
*/
#ifdef GENERATE_MAGIC_NUMBERS
calculateMagicNumbers();
#endif
return 0;
}
#ifndef NDEBUG
static int testBitOperations()
{
Bitboard b = EMPTY_BITBOARD;
assert(testSquare
(lightSquares
, A1
) == 0);
assert(testSquare
(lightSquares
, B1
));
assert(testSquare
(lightSquares
, G8
));
assert(testSquare
(lightSquares
, H8
) == 0);
assert(testSquare
(darkSquares
, A1
));
assert(testSquare
(darkSquares
, B1
) == 0);
assert(testSquare
(darkSquares
, G8
) == 0);
assert(testSquare
(darkSquares
, H8
));
assert(highestBit
[0x0f] == 3);
assert(highestBit
[0xffff] == 15);
assert(numSetBits
[0x5555] == 8);
assert(numSetBits
[0xaaaa] == 8);
assert(numSetBits
[0xffff] == 16);
assert(testSquare
(b
, D4
) == 0);
setSquare(b, D4);
assert(testSquare
(b
, D4
) != 0);
clearSquare(b, D4);
assert(testSquare
(b
, D4
) == 0);
assert(testSquare
(b
, H8
) == 0);
setSquare(b, H8);
assert(testSquare
(b
, H8
) != 0);
clearSquare(b, H8);
assert(testSquare
(b
, H8
) == 0);
assert(getLastSquare
(&b
) == NO_SQUARE
);
setSquare(b, H8);
assert(getLastSquare
(&b
) == H8
);
assert(getLastSquare
(&b
) == NO_SQUARE
);
assert(testSquare
(squaresBehind
[D4
][C3
], E5
));
assert(testSquare
(squaresBehind
[D4
][C3
], F6
));
assert(testSquare
(squaresBehind
[D4
][C3
], G7
));
assert(testSquare
(squaresBehind
[D4
][C3
], H8
));
assert(getNumberOfSetSquares
(squaresBehind
[D4
][C3
]) == 4);
assert(testSquare
(squaresBetween
[B3
][F7
], C4
));
assert(testSquare
(squaresBetween
[B3
][F7
], D5
));
assert(testSquare
(squaresBetween
[B3
][F7
], E6
));
assert(getNumberOfSetSquares
(squaresBetween
[B3
][F7
]) == 3);
assert(rankOverlay
[0x8143] == 0xC3);
b = EMPTY_BITBOARD;
setSquare(b, A4);
setSquare(b, E1);
setSquare(b, E8);
setSquare(b, H7);
assert(getRankOverlay
(b
) == 0x91);
assert(testSquare
(squaresInDistance
[1][C3
], C4
) != FALSE
);
assert(testSquare
(squaresInDistance
[1][C3
], C5
) == FALSE
);
assert(testSquare
(squaresInDistance
[3][E5
], E2
) != FALSE
);
assert(testSquare
(squaresInDistance
[3][E5
], E1
) == FALSE
);
assert(testSquare
(squaresInDistance
[5][H8
], C3
) != FALSE
);
assert(testSquare
(squaresInDistance
[5][H8
], B2
) == FALSE
);
assert(bitshiftGap
[5][0] == 0);
assert(bitshiftGap
[1][129] == 1);
assert(bitshiftGap
[4][129] == 3);
return 0;
}
static int testGeneralMoves()
{
assert(testSquare
(generalMoves
[KING
][C3
], C4
));
assert(testSquare
(generalMoves
[KING
][C3
], D4
));
assert(testSquare
(generalMoves
[KING
][C3
], D3
));
assert(testSquare
(generalMoves
[KING
][C3
], D2
));
assert(testSquare
(generalMoves
[KING
][C3
], C2
));
assert(testSquare
(generalMoves
[KING
][C3
], B2
));
assert(testSquare
(generalMoves
[KING
][C3
], B3
));
assert(testSquare
(generalMoves
[KING
][C3
], B4
));
assert(getNumberOfSetSquares
(generalMoves
[KING
][C3
]) == 8);
assert(testSquare
(generalMoves
[ROOK
][C3
], C8
));
assert(testSquare
(generalMoves
[ROOK
][C3
], H3
));
assert(testSquare
(generalMoves
[ROOK
][C3
], C1
));
assert(testSquare
(generalMoves
[ROOK
][C3
], A3
));
assert(getNumberOfSetSquares
(generalMoves
[ROOK
][C3
]) == 14);
assert(testSquare
(generalMoves
[BISHOP
][C3
], H8
));
assert(testSquare
(generalMoves
[BISHOP
][C3
], E1
));
assert(testSquare
(generalMoves
[BISHOP
][C3
], A1
));
assert(testSquare
(generalMoves
[BISHOP
][C3
], A5
));
assert(getNumberOfSetSquares
(generalMoves
[BISHOP
][C3
]) == 11);
assert(testSquare
(generalMoves
[QUEEN
][C3
], C8
));
assert(testSquare
(generalMoves
[QUEEN
][C3
], H8
));
assert(testSquare
(generalMoves
[QUEEN
][C3
], H3
));
assert(testSquare
(generalMoves
[QUEEN
][C3
], E1
));
assert(testSquare
(generalMoves
[QUEEN
][C3
], C1
));
assert(testSquare
(generalMoves
[QUEEN
][C3
], A1
));
assert(testSquare
(generalMoves
[QUEEN
][C3
], A3
));
assert(testSquare
(generalMoves
[QUEEN
][C3
], A5
));
assert(getNumberOfSetSquares
(generalMoves
[QUEEN
][C3
]) == 25);
assert(testSquare
(generalMoves
[KNIGHT
][C3
], A2
));
assert(testSquare
(generalMoves
[KNIGHT
][C3
], A4
));
assert(testSquare
(generalMoves
[KNIGHT
][C3
], B5
));
assert(testSquare
(generalMoves
[KNIGHT
][C3
], D5
));
assert(testSquare
(generalMoves
[KNIGHT
][C3
], E4
));
assert(testSquare
(generalMoves
[KNIGHT
][C3
], E2
));
assert(testSquare
(generalMoves
[KNIGHT
][C3
], D1
));
assert(testSquare
(generalMoves
[KNIGHT
][C3
], B1
));
assert(getNumberOfSetSquares
(generalMoves
[KNIGHT
][C3
]) == 8);
assert(getNumberOfSetSquares
(generalMoves
[KNIGHT
][A1
]) == 2);
assert(getNumberOfSetSquares
(generalMoves
[KNIGHT
][H8
]) == 2);
assert(testSquare
(generalMoves
[WHITE_PAWN
][A2
], B3
));
assert(getNumberOfSetSquares
(generalMoves
[WHITE_PAWN
][A2
]) == 1);
assert(testSquare
(generalMoves
[WHITE_PAWN
][B2
], A3
));
assert(testSquare
(generalMoves
[WHITE_PAWN
][B2
], C3
));
assert(getNumberOfSetSquares
(generalMoves
[WHITE_PAWN
][B2
]) == 2);
assert(testSquare
(generalMoves
[WHITE_PAWN
][H2
], G3
));
assert(getNumberOfSetSquares
(generalMoves
[WHITE_PAWN
][H2
]) == 1);
assert(testSquare
(generalMoves
[BLACK_PAWN
][A7
], B6
));
assert(getNumberOfSetSquares
(generalMoves
[BLACK_PAWN
][A7
]) == 1);
assert(testSquare
(generalMoves
[BLACK_PAWN
][B7
], A6
));
assert(testSquare
(generalMoves
[BLACK_PAWN
][B7
], C6
));
assert(getNumberOfSetSquares
(generalMoves
[BLACK_PAWN
][B7
]) == 2);
assert(testSquare
(generalMoves
[BLACK_PAWN
][H7
], G6
));
assert(getNumberOfSetSquares
(generalMoves
[BLACK_PAWN
][H7
]) == 1);
return 0;
}
static int testPieces()
{
Bitboard b = EMPTY_BITBOARD, moves;
BYTE obstacles[NUM_LANES];
setSquare(b, C3);
setSquare(b, C6);
setSquare(b, F6);
calculateObstacles(b, obstacles);
moves = getMagicRookMoves(C4, b);
assert(testSquare
(moves
, C3
));
assert(testSquare
(moves
, C5
));
assert(testSquare
(moves
, C6
));
assert(testSquare
(moves
, A4
));
assert(testSquare
(moves
, B4
));
assert(testSquare
(moves
, D4
));
assert(testSquare
(moves
, E4
));
assert(testSquare
(moves
, F4
));
assert(testSquare
(moves
, G4
));
assert(testSquare
(moves
, H4
));
assert(getNumberOfSetSquares
(moves
) == 10);
moves = getMagicBishopMoves(E5, b);
assert(testSquare
(moves
, D4
));
assert(testSquare
(moves
, C3
));
assert(testSquare
(moves
, D6
));
assert(testSquare
(moves
, C7
));
assert(testSquare
(moves
, B8
));
assert(testSquare
(moves
, F6
));
assert(testSquare
(moves
, F4
));
assert(testSquare
(moves
, G3
));
assert(testSquare
(moves
, H2
));
assert(getNumberOfSetSquares
(moves
) == 9);
moves = getMagicQueenMoves(F3, b);
assert(testSquare
(moves
, F2
));
assert(testSquare
(moves
, F1
));
assert(testSquare
(moves
, F4
));
assert(testSquare
(moves
, F5
));
assert(testSquare
(moves
, F6
));
assert(testSquare
(moves
, E3
));
assert(testSquare
(moves
, D3
));
assert(testSquare
(moves
, C3
));
assert(testSquare
(moves
, G3
));
assert(testSquare
(moves
, H3
));
assert(testSquare
(moves
, E4
));
assert(testSquare
(moves
, D5
));
assert(testSquare
(moves
, C6
));
assert(testSquare
(moves
, G4
));
assert(testSquare
(moves
, H5
));
assert(testSquare
(moves
, G2
));
assert(testSquare
(moves
, H1
));
assert(testSquare
(moves
, E2
));
assert(testSquare
(moves
, D1
));
assert(getNumberOfSetSquares
(moves
) == 19);
moves = getKnightMoves(A8);
assert(testSquare
(moves
, B6
));
assert(testSquare
(moves
, C7
));
assert(getNumberOfSetSquares
(moves
) == 2);
moves = getKnightMoves(E5);
assert(testSquare
(moves
, F7
));
assert(testSquare
(moves
, G6
));
assert(testSquare
(moves
, G4
));
assert(testSquare
(moves
, F3
));
assert(testSquare
(moves
, D3
));
assert(testSquare
(moves
, C4
));
assert(testSquare
(moves
, C6
));
assert(testSquare
(moves
, D7
));
assert(getNumberOfSetSquares
(moves
) == 8);
return 0;
}
static int testPawns()
{
Bitboard b = EMPTY_BITBOARD, moves, pawns;
BYTE obstacles[NUM_LANES];
setSquare(b, B3);
setSquare(b, C4);
setSquare(b, E4);
setSquare(b, F6);
setSquare(b, E5);
setSquare(b, D6);
setSquare(b, G2);
setSquare(b, G3);
setSquare(b, H2);
setSquare(b, H7);
calculateObstacles(b, obstacles);
moves = getPawnAdvances(WHITE, A2, b);
assert(testSquare
(moves
, A3
));
assert(testSquare
(moves
, A4
));
assert(getNumberOfSetSquares
(moves
) == 2);
moves = getPawnAdvances(WHITE, B2, b);
assert(getNumberOfSetSquares
(moves
) == 0);
moves = getPawnAdvances(WHITE, C2, b);
assert(testSquare
(moves
, C3
));
assert(getNumberOfSetSquares
(moves
) == 1);
moves = getPawnAdvances(BLACK, H7, b);
assert(testSquare
(moves
, H6
));
assert(testSquare
(moves
, H5
));
assert(getNumberOfSetSquares
(moves
) == 2);
moves = getPawnAdvances(BLACK, F7, b);
assert(getNumberOfSetSquares
(moves
) == 0);
moves = getPawnAdvances(BLACK, E7, b);
assert(testSquare
(moves
, E6
));
assert(getNumberOfSetSquares
(moves
) == 1);
moves = getPawnCaptures(WHITE_PAWN, A2, b);
assert(testSquare
(moves
, B3
));
assert(getNumberOfSetSquares
(moves
) == 1);
moves = getPawnCaptures(WHITE_PAWN, D3, b);
assert(testSquare
(moves
, C4
));
assert(testSquare
(moves
, E4
));
assert(getNumberOfSetSquares
(moves
) == 2);
moves = getPawnCaptures(BLACK_PAWN, G7, b);
assert(testSquare
(moves
, F6
));
assert(getNumberOfSetSquares
(moves
) == 1);
moves = getPawnCaptures(BLACK_PAWN, E7, b);
assert(testSquare
(moves
, D6
));
assert(testSquare
(moves
, F6
));
assert(getNumberOfSetSquares
(moves
) == 2);
pawns = getInterestedPawns(BLACK, D5, b);
assert(testSquare
(pawns
, D6
));
assert(getNumberOfSetSquares
(pawns
) == 1);
pawns = getInterestedPawns(BLACK, H5, b);
assert(testSquare
(pawns
, H7
));
assert(testSquare
(pawns
, H6
));
assert(getNumberOfSetSquares
(pawns
) == 2);
pawns = getInterestedPawns(WHITE, H4, b);
assert(testSquare
(pawns
, H2
));
assert(testSquare
(pawns
, H3
));
assert(getNumberOfSetSquares
(pawns
) == 2);
pawns = getInterestedPawns(WHITE, G4, b);
assert(testSquare
(pawns
, G3
));
assert(getNumberOfSetSquares
(pawns
) == 1);
return 0;
}
static int testKings()
{
Bitboard obstacles = EMPTY_BITBOARD, moves;
BYTE castlingRights = WHITE_00 | WHITE_000 | BLACK_000 | BLACK_00;
moves = getKingMoves(A1);
assert(testSquare
(moves
, B1
));
assert(testSquare
(moves
, B2
));
assert(testSquare
(moves
, A2
));
assert(getNumberOfSetSquares
(moves
) == 3);
moves = getKingMoves(D5);
assert(testSquare
(moves
, D6
));
assert(testSquare
(moves
, E6
));
assert(testSquare
(moves
, E5
));
assert(testSquare
(moves
, E4
));
assert(testSquare
(moves
, D4
));
assert(testSquare
(moves
, C4
));
assert(testSquare
(moves
, C5
));
assert(testSquare
(moves
, C6
));
assert(getNumberOfSetSquares
(moves
) == 8);
moves = getKingMoves(D5);
assert(testSquare
(moves
, D6
));
assert(testSquare
(moves
, E6
));
assert(testSquare
(moves
, E5
));
assert(testSquare
(moves
, E4
));
assert(testSquare
(moves
, D4
));
assert(testSquare
(moves
, C4
));
assert(testSquare
(moves
, C5
));
assert(testSquare
(moves
, C6
));
assert(getNumberOfSetSquares
(moves
) == 8);
moves = getCastlingMoves(WHITE, castlingRights, obstacles);
assert(testSquare
(moves
, G1
));
assert(testSquare
(moves
, C1
));
assert(getNumberOfSetSquares
(moves
) == 2);
moves = getCastlingMoves(BLACK, castlingRights, obstacles);
assert(testSquare
(moves
, G8
));
assert(testSquare
(moves
, C8
));
assert(getNumberOfSetSquares
(moves
) == 2);
castlingRights = WHITE_00 | BLACK_00;
moves = getCastlingMoves(WHITE, castlingRights, obstacles);
assert(testSquare
(moves
, G1
));
assert(getNumberOfSetSquares
(moves
) == 1);
moves = getCastlingMoves(BLACK, castlingRights, obstacles);
assert(testSquare
(moves
, G8
));
assert(getNumberOfSetSquares
(moves
) == 1);
castlingRights = WHITE_000 | BLACK_000;
moves = getCastlingMoves(WHITE, castlingRights, obstacles);
assert(testSquare
(moves
, C1
));
assert(getNumberOfSetSquares
(moves
) == 1);
moves = getCastlingMoves(BLACK, castlingRights, obstacles);
assert(testSquare
(moves
, C8
));
assert(getNumberOfSetSquares
(moves
) == 1);
castlingRights = WHITE_00 | WHITE_000 | BLACK_000 | BLACK_00;
setSquare(obstacles, D1);
setSquare(obstacles, D8);
moves = getCastlingMoves(WHITE, castlingRights, obstacles);
assert(testSquare
(moves
, G1
));
assert(getNumberOfSetSquares
(moves
) == 1);
moves = getCastlingMoves(BLACK, castlingRights, obstacles);
assert(testSquare
(moves
, G8
));
assert(getNumberOfSetSquares
(moves
) == 1);
clearSquare(obstacles, D1);
clearSquare(obstacles, D8);
moves = getCastlingMoves(WHITE, castlingRights, obstacles);
assert(testSquare
(moves
, G1
));
assert(testSquare
(moves
, C1
));
assert(getNumberOfSetSquares
(moves
) == 2);
moves = getCastlingMoves(BLACK, castlingRights, obstacles);
assert(testSquare
(moves
, G8
));
assert(testSquare
(moves
, C8
));
assert(getNumberOfSetSquares
(moves
) == 2);
setSquare(obstacles, C1);
setSquare(obstacles, C8);
moves = getCastlingMoves(WHITE, castlingRights, obstacles);
assert(testSquare
(moves
, G1
));
assert(getNumberOfSetSquares
(moves
) == 1);
moves = getCastlingMoves(BLACK, castlingRights, obstacles);
assert(testSquare
(moves
, G8
));
assert(getNumberOfSetSquares
(moves
) == 1);
clearSquare(obstacles, C1);
clearSquare(obstacles, C8);
setSquare(obstacles, F1);
setSquare(obstacles, F8);
moves = getCastlingMoves(WHITE, castlingRights, obstacles);
assert(testSquare
(moves
, C1
));
assert(getNumberOfSetSquares
(moves
) == 1);
moves = getCastlingMoves(BLACK, castlingRights, obstacles);
assert(testSquare
(moves
, C8
));
assert(getNumberOfSetSquares
(moves
) == 1);
clearSquare(obstacles, F1);
clearSquare(obstacles, F8);
setSquare(obstacles, G1);
setSquare(obstacles, G8);
moves = getCastlingMoves(WHITE, castlingRights, obstacles);
assert(testSquare
(moves
, C1
));
assert(getNumberOfSetSquares
(moves
) == 1);
moves = getCastlingMoves(BLACK, castlingRights, obstacles);
assert(testSquare
(moves
, C8
));
assert(getNumberOfSetSquares
(moves
) == 1);
clearSquare(obstacles, G1);
clearSquare(obstacles, G8);
setSquare(obstacles, G1);
setSquare(obstacles, G8);
setSquare(obstacles, C1);
setSquare(obstacles, C8);
moves = getCastlingMoves(WHITE, castlingRights, obstacles);
assert(getNumberOfSetSquares
(moves
) == 0);
moves = getCastlingMoves(BLACK, castlingRights, obstacles);
assert(getNumberOfSetSquares
(moves
) == 0);
clearSquare(obstacles, G1);
clearSquare(obstacles, G8);
clearSquare(obstacles, C1);
clearSquare(obstacles, C8);
return 0;
}
static int testFlooding()
{
Bitboard kingMoves = getKingMoves(D4);
Bitboard expected;
floodBoard(&kingMoves);
expected = squaresBetween[A6][G6] | squaresBetween[A5][G5] |
squaresBetween[A4][G4] | squaresBetween[A3][G3] |
squaresBetween[A2][G2];
assert(kingMoves
== expected
);
kingMoves = getKingMoves(H1);
floodBoard(&kingMoves);
expected = squaresBehind[E3][A3] | squaresBehind[E2][A2] |
squaresBehind[E1][A1];
assert(kingMoves
== expected
);
kingMoves = getKingMoves(A8);
floodBoard(&kingMoves);
expected = squaresBehind[D8][H8] | squaresBehind[D7][H7] |
squaresBehind[D6][H6];
assert(kingMoves
== expected
);
return 0;
}
static int testGetSetSquares()
{
UINT8 moveSquares[_64_];
Bitboard kingMoves = getKingMoves(D4);
int numMoves = getSetSquares(kingMoves, moveSquares), i;
for (i = 0; i < numMoves; i++)
{
const Square square = (Square) moveSquares[i];
assert(testSquare
(kingMoves
, square
) == TRUE
);
}
return 0;
}
#endif
int testModuleBitboard()
{
#ifndef NDEBUG
int result;
if ((result = testBitOperations()) != 0)
{
return result;
}
if ((result = testGeneralMoves()) != 0)
{
return result;
}
if ((result = testPieces()) != 0)
{
return result;
}
if ((result = testPawns()) != 0)
{
return result;
}
if ((result = testKings()) != 0)
{
return result;
}
if ((result = testFlooding()) != 0)
{
return result;
}
if ((result = testGetSetSquares()) != 0)
{
return result;
}
#endif
return 0;
}