Skip to content

Instantly share code, notes, and snippets.

@crisu83
Created April 12, 2012 09:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save crisu83/2366059 to your computer and use it in GitHub Desktop.
Save crisu83/2366059 to your computer and use it in GitHub Desktop.
OgreChess Position.cpp
// Game constants.
#define A_FILE 0x0101010101010101
#define B_FILE 0x202020202020202
#define C_FILE 0x404040404040404
#define D_FILE 0x808080808080808
#define E_FILE 0x1010101010101010
#define F_FILE 0x2020202020202020
#define G_FILE 0x4040404040404040
#define H_FILE 0x8080808080808080
#define FIRST_RANK 0x00000000000000FF
#define EIGHT_RANK 0xFF00000000000000
#define THIRD_RANK 0x0000000000FF0000
#define SIXTH_RANK 0x0000FF0000000000
#define D1C1B1_MASK 0x000000000000000E
#define F1G1_MASK 0x0000000000000060
#define F8G8_MASK 0x6000000000000000
#define D8C8B8_MASK 0xE00000000000000
#define A1_MASK 0x0000000000000001
#define H1_MASK 0x0000000010000000
#define A8_MASK 0x0100000000000000
#define H8_MASK 0x8000000000000000
#include "stdafx.h"
Position::Position(void)
: mTurn(0)
{
}
Position::~Position(void)
{
}
void Position::setup(void)
{
}
/**
Returns all legal moves in the current situation.
@param bitboards The bitboards.
@return The moves.
*/
std::vector<std::vector<UI64>> Position::genLegalMoves(UI64 bitboards[])
{
int count = 0;
std::vector<UI64> tmp;
UI64 pieces, current, moves;
mMoves.clear();
// White player moves.
if (mTurn == WHITE)
{
if (whiteChecked(bitboards))
{
// White player is checked.
pieces = bitboards[W_PAWN];
while (pieces != 0)
{
current = pieces & -pieces;
moves = wBlockCheck(current, pawnMoves(current, bitboards[EMPTYSQUARES], bitboards, WHITE), bitboards);
addMoves(current, moves);
pieces &= pieces - 1;
}
pieces = bitboards[W_KNIGHT];
while (pieces != 0)
{
current = pieces & -pieces;
moves = wBlockCheck(current, knightMoves(current, bitboards[W_PIECES]), bitboards);
addMoves(current, moves);
pieces &= pieces - 1;
}
pieces = bitboards[W_BISHOP];
while (pieces != 0)
{
current = pieces & -pieces;
moves = wBlockCheck(current, bishopMoves(current, bitboards[EMPTYSQUARES], bitboards[W_PIECES]), bitboards);
addMoves(current, moves);
pieces &= pieces - 1;
}
pieces = bitboards[W_ROOK];
while (pieces != 0)
{
current = pieces & -pieces;
moves = wBlockCheck(current, rookMoves(current, bitboards[EMPTYSQUARES], bitboards[W_PIECES]), bitboards);
addMoves(current, moves);
pieces &= pieces - 1;
}
pieces = bitboards[W_QUEEN];
while (pieces != 0)
{
current = pieces & -pieces;
moves = wBlockCheck(current, queenMoves(current, bitboards[EMPTYSQUARES], bitboards[W_PIECES]), bitboards);
addMoves(current, moves);
pieces &= pieces - 1;
}
moves = wEscapeMoves(bitboards);
addMoves(bitboards[W_KING], moves);
}
else
{
// White player is not checked.
if ((bitboards[CASTLING] & A1_MASK) && !(D1C1B1_MASK & ~bitboards[EMPTYSQUARES]) && !(D1C1B1_MASK & bAttacks(bitboards)))
{
tmp.insert(tmp.end(), bitboards[W_KING]);
tmp.insert(tmp.end(), bitboards[W_KING] >> 2);
mMoves.insert(mMoves.end(), tmp);
}
if ((bitboards[CASTLING] & H1_MASK) && !(F1G1_MASK & ~bitboards[EMPTYSQUARES]) && !(F1G1_MASK & bAttacks(bitboards)))
{
tmp.insert(tmp.end(), bitboards[W_KING]);
tmp.insert(tmp.end(), bitboards[W_KING] << 2);
mMoves.insert(mMoves.end(), tmp);
}
pieces = bitboards[W_PAWN];
while (pieces != 0)
{
current = pieces & -pieces;
moves = pawnMoves(current, bitboards[EMPTYSQUARES], bitboards, WHITE);
moves = wPiecePinned(current, bitboards) ? wPinnedMoves(current, moves, bitboards) : moves;
addMoves(current, moves);
pieces &= pieces - 1;
}
pieces = bitboards[W_KNIGHT];
while (pieces != 0)
{
current = pieces & -pieces;
moves = knightMoves(current, bitboards[W_PIECES]);
moves = wPiecePinned(current, bitboards) ? wPinnedMoves(current, moves, bitboards) : moves;
addMoves(current, moves);
pieces &= pieces - 1;
}
pieces = bitboards[W_BISHOP];
while (pieces != 0)
{
current = pieces & -pieces;
moves = bishopMoves(current, bitboards[EMPTYSQUARES], bitboards[W_PIECES]);
moves = wPiecePinned(current, bitboards) ? wPinnedMoves(current, moves, bitboards) : moves;
addMoves(current, moves);
pieces &= pieces - 1;
}
pieces = bitboards[W_ROOK];
while (pieces != 0)
{
current = pieces & -pieces;
moves = rookMoves(current, bitboards[EMPTYSQUARES], bitboards[W_PIECES]);
moves = wPiecePinned(current, bitboards) ? wPinnedMoves(current, moves, bitboards) : moves;
addMoves(current, moves);
pieces &= pieces - 1;
}
pieces = bitboards[W_QUEEN];
while (pieces != 0)
{
current = pieces & -pieces;
moves = queenMoves(current, bitboards[EMPTYSQUARES], bitboards[W_PIECES]);
moves = wPiecePinned(current, bitboards) ? wPinnedMoves(current, moves, bitboards) : moves;
addMoves(current, moves);
pieces &= pieces - 1;
}
moves = kingMoves(bitboards[W_KING], bitboards[W_PIECES], bitboards);
addMoves(bitboards[W_KING], moves);
}
}
// Black player moves.
else
{
if (blackChecked(bitboards))
{
// Black player is checked.
pieces = bitboards[B_PAWN];
while (pieces != 0)
{
current = pieces & -pieces;
moves = bBlockCheck(current, pawnMoves(current, bitboards[EMPTYSQUARES], bitboards, BLACK), bitboards);
addMoves(current, moves);
pieces &= pieces - 1;
}
pieces = bitboards[B_KNIGHT];
while (pieces != 0)
{
current = pieces & -pieces;
moves = bBlockCheck(current, knightMoves(current, bitboards[B_PIECES]), bitboards);
addMoves(current, moves);
pieces &= pieces - 1;
}
pieces = bitboards[B_BISHOP];
while (pieces != 0)
{
current = pieces & -pieces;
moves = bBlockCheck(current, bishopMoves(current, bitboards[EMPTYSQUARES], bitboards[B_PIECES]), bitboards);
addMoves(current, moves);
pieces &= pieces - 1;
}
pieces = bitboards[B_ROOK];
while (pieces != 0)
{
current = pieces & -pieces;
moves = bBlockCheck(current, rookMoves(current, bitboards[EMPTYSQUARES], bitboards[B_PIECES]), bitboards);
addMoves(current, moves);
pieces &= pieces - 1;
}
pieces = bitboards[B_QUEEN];
while (pieces != 0)
{
current = pieces & -pieces;
moves = bBlockCheck(current, queenMoves(current, bitboards[EMPTYSQUARES], bitboards[B_PIECES]), bitboards);
addMoves(current, moves);
pieces &= pieces - 1;
}
moves = bEscapeMoves(bitboards);
addMoves(bitboards[B_KING], moves);
}
else
{
// Black player is not checked.
if ((bitboards[CASTLING] & A8_MASK) && !(D8C8B8_MASK & ~bitboards[EMPTYSQUARES]) && !(D8C8B8_MASK & wAttacks(bitboards)))
{
tmp.insert(tmp.end(), bitboards[B_KING]);
tmp.insert(tmp.end(), bitboards[B_KING] >> 2);
mMoves.insert(mMoves.end(), tmp);
}
if ((bitboards[CASTLING] & H8_MASK) && !(F8G8_MASK & ~bitboards[EMPTYSQUARES]) && !(F8G8_MASK & wAttacks(bitboards)))
{
tmp.insert(tmp.end(), bitboards[B_KING]);
tmp.insert(tmp.end(), bitboards[B_KING] << 2);
mMoves.insert(mMoves.end(), tmp);
}
pieces = bitboards[B_PAWN];
while (pieces != 0)
{
current = pieces & -pieces;
moves = pawnMoves(current, bitboards[EMPTYSQUARES], bitboards, BLACK);
moves = bPiecePinned(current, bitboards) ? bPinnedMoves(current, moves, bitboards) : moves;
addMoves(current, moves);
pieces &= pieces - 1;
}
pieces = bitboards[W_KNIGHT];
while (pieces != 0)
{
current = pieces & -pieces;
moves = knightMoves(current, bitboards[B_PIECES]);
moves = bPiecePinned(current, bitboards) ? bPinnedMoves(current, moves, bitboards) : moves;
addMoves(current, moves);
pieces &= pieces - 1;
}
pieces = bitboards[W_BISHOP];
while (pieces != 0)
{
current = pieces & -pieces;
moves = bishopMoves(current, bitboards[EMPTYSQUARES], bitboards[B_PIECES]);
moves = bPiecePinned(current, bitboards) ? bPinnedMoves(current, moves, bitboards) : moves;
addMoves(current, moves);
pieces &= pieces - 1;
}
pieces = bitboards[W_ROOK];
while (pieces != 0)
{
current = pieces & -pieces;
moves = rookMoves(current, bitboards[EMPTYSQUARES], bitboards[B_PIECES]);
moves = bPiecePinned(current, bitboards) ? bPinnedMoves(current, moves, bitboards) : moves;
addMoves(current, moves);
pieces &= pieces - 1;
}
pieces = bitboards[W_QUEEN];
while (pieces != 0)
{
current = pieces & -pieces;
moves = queenMoves(current, bitboards[EMPTYSQUARES], bitboards[B_PIECES]);
moves = bPiecePinned(current, bitboards) ? bPinnedMoves(current, moves, bitboards) : moves;
addMoves(current, moves);
pieces &= pieces - 1;
}
moves = kingMoves(bitboards[B_KING], bitboards[B_PIECES], bitboards);
addMoves(bitboards[B_KING], moves);
}
}
return mMoves;
}
/**
Returns whether the white player is checked.
@return The result.
*/
bool Position::whiteChecked(UI64 bitboards[])
{
return (bAttacks(bitboards) & bitboards[W_KING]) != 0;
}
/**
Returns whether the black player is checked.
@return The result.
*/
bool Position::blackChecked(UI64 bitboards[])
{
return (wAttacks(bitboards) & bitboards[B_KING]) != 0;
}
/**
Evaluates the game situation.
@param bitboards The bitboards.
@return The result.
*/
double Position::evaluate(UI64 bitboards[])
{
int wKingCount, wQueenCount, wRookCount, wBishopCount, wKnightCount, wPawnCount;
int wMoveCount, wDoublePawnCount, wIsolatedCount;
int bKingCount, bQueenCount, bRookCount, bBishopCount, bKnightCount, bPawnCount;
int bMoveCount, bDoublePawnCount, bIsolatedCount;
double material, mobility, doubled, isolated;
UI64 isolatedWest, isolatedEast;
wKingCount = 1;
wQueenCount = itemCount(bitboards[W_QUEEN]);
wRookCount = itemCount(bitboards[W_ROOK]);
wBishopCount = itemCount(bitboards[W_BISHOP]);
wKnightCount = itemCount(bitboards[W_KNIGHT]);
wPawnCount = itemCount(bitboards[W_PAWN]);
bKingCount = 1;
bQueenCount = itemCount(bitboards[B_QUEEN]);
bRookCount = itemCount(bitboards[B_ROOK]);
bBishopCount = itemCount(bitboards[B_BISHOP]);
bKnightCount = itemCount(bitboards[B_KNIGHT]);
bPawnCount = itemCount(bitboards[B_PAWN]);
// Material balance
material = 1000 * (wKingCount - bKingCount)
+ 9 * (wQueenCount - bQueenCount)
+ 5 * (wRookCount - bRookCount)
+ 3.25 * (wBishopCount - bBishopCount)
+ 3.00 * (wKnightCount - bKnightCount)
+ 1 * (wPawnCount - bPawnCount);
// Mobility
wMoveCount = itemCount(wMoves(bitboards));
bMoveCount = itemCount(bMoves(bitboards));
mobility = wMoveCount - bMoveCount;
// Double pawns
wDoublePawnCount = doublePawnCount(bitboards[W_PAWN]);
bDoublePawnCount = doublePawnCount(bitboards[B_PAWN]);
doubled = wDoublePawnCount - bDoublePawnCount;
// Isolated pawns
isolatedWest = bitboards[W_PAWN] & ~(fillNorth(bitboards[W_PAWN]) | fillSouth(bitboards[W_PAWN])) >> 1;
isolatedEast = bitboards[W_PAWN] & ~(fillNorth(bitboards[W_PAWN]) | fillSouth(bitboards[W_PAWN])) << 1;
wIsolatedCount = itemCount(isolatedWest & isolatedEast);
isolatedWest = bitboards[W_PAWN] & ~(fillNorth(bitboards[B_PAWN]) | fillSouth(bitboards[B_PAWN])) >> 1;
isolatedEast = bitboards[W_PAWN] & ~(fillNorth(bitboards[B_PAWN]) | fillSouth(bitboards[B_PAWN])) << 1;
bIsolatedCount = itemCount(isolatedWest & isolatedEast);
isolated = wIsolatedCount - bIsolatedCount;
return material + (0.3 * mobility) - 0.5 * (doubled + isolated);
}
/* -----------------------------------------------------------------------------------------------
MOVE GENERATION
----------------------------------------------------------------------------------------------- */
// KING
/**
Returns all possible king moves.
@param king The king.
@param own The own pieces.
@param bitboards The bitboards.
@return The moves.
*/
UI64 Position::kingMoves(UI64 king, UI64 own, UI64 bitboards[])
{
UI64 moves = ((king << 1) & ~A_FILE) | ((king >> 1) & ~H_FILE); // left-right
moves |= (king << 8) | (king >> 8); // up-down
moves |= ((king >> 7) & ~A_FILE) | ((king >> 9) & ~H_FILE); // diagonal down
moves |= ((king << 9) & ~A_FILE) | ((king << 7) & ~H_FILE); // diagonal up
return moves & ~own;
}
// QUEEN
/**
Returns all possible queen moves.
@param queen The queen.
@param emptySquares The emptySquares squares.
@param own The own pieces.
@return The moves.
*/
UI64 Position::queenMoves(UI64 queen, UI64 emptySquares, UI64 own)
{
return rookMoves(queen, emptySquares, own) | bishopMoves(queen, emptySquares, own);
}
/**
Returns all possible queen escape moves.
@param queen The queen.
@param emptySquares The emptySquares squares.
@return The moves.
*/
UI64 Position::queenEscapeMoves(UI64 queen, UI64 emptySquares)
{
return rookEscapeMoves(queen, emptySquares) | bishopEscapeMoves(queen, emptySquares);
}
// ROOK
/**
Returns all the rook east moves.
@param rooks The rooks.
@param emptySquares The emptySquares squares.
@return The moves.
*/
UI64 Position::rookEast(UI64 rooks, UI64 emptySquares)
{
emptySquares &= ~A_FILE;
rooks |= emptySquares & (rooks << 1);
rooks |= emptySquares & (rooks << 1);
rooks |= emptySquares & (rooks << 1);
rooks |= emptySquares & (rooks << 1);
rooks |= emptySquares & (rooks << 1);
rooks |= emptySquares & (rooks << 1);
return ~A_FILE & (rooks << 1);
}
/**
Returns all the rook west moves.
@param rooks The rooks.
@param emptySquares The emptySquares squares.
@return The moves.
*/
UI64 Position::rookWest(UI64 rooks, UI64 emptySquares)
{
emptySquares &= ~H_FILE;
rooks |= emptySquares & (rooks >> 1);
rooks |= emptySquares & (rooks >> 1);
rooks |= emptySquares & (rooks >> 1);
rooks |= emptySquares & (rooks >> 1);
rooks |= emptySquares & (rooks >> 1);
rooks |= emptySquares & (rooks >> 1);
return ~H_FILE & (rooks >> 1);
}
/**
Returns all the rook north moves.
@param rooks The rooks.
@param emptySquares The emptySquares squares.
@return The moves.
*/
UI64 Position::rookNorth(UI64 rooks, UI64 emptySquares)
{
rooks |= emptySquares & (rooks << 8);
rooks |= emptySquares & (rooks << 8);
rooks |= emptySquares & (rooks << 8);
rooks |= emptySquares & (rooks << 8);
rooks |= emptySquares & (rooks << 8);
rooks |= emptySquares & (rooks << 8);
return (rooks << 8);
}
/**
Returns all the rook south moves.
@param rooks The rooks.
@param emptySquares The emptySquares squares.
@return The moves.
*/
UI64 Position::rookSouth(UI64 rooks, UI64 emptySquares)
{
rooks |= emptySquares & (rooks >> 8);
rooks |= emptySquares & (rooks >> 8);
rooks |= emptySquares & (rooks >> 8);
rooks |= emptySquares & (rooks >> 8);
rooks |= emptySquares & (rooks >> 8);
rooks |= emptySquares & (rooks >> 8);
return (rooks >> 8);
}
/**
Returns all possible rook moves.
@param rooks The rooks.
@param emptySquares The emptySquares squares.
@param own The own pieces.
@return The moves.
*/
UI64 Position::rookMoves(UI64 rooks, UI64 emptySquares, UI64 own)
{
return rookEscapeMoves(rooks, emptySquares) & ~own;
}
/**
Returns all possible rook escape moves.
@param rooks The rooks.
@param emptySquares The emptySquares squares.
@return The moves.
*/
UI64 Position::rookEscapeMoves(UI64 rooks, UI64 emptySquares)
{
return rookWest(rooks, emptySquares) | rookEast(rooks, emptySquares) | rookNorth(rooks, emptySquares) | rookSouth(rooks, emptySquares);
}
// BISHOP
/**
Returns all the bishop north-east moves.
@param bishops The bishops.
@param emptySquares The emptySquares squares.
@return The moves.
*/
UI64 Position::bishopNE(UI64 bishops, UI64 emptySquares)
{
emptySquares &= ~A_FILE;
bishops |= emptySquares & (bishops << 9);
bishops |= emptySquares & (bishops << 9);
bishops |= emptySquares & (bishops << 9);
bishops |= emptySquares & (bishops << 9);
bishops |= emptySquares & (bishops << 9);
bishops |= emptySquares & (bishops << 9);
return ~A_FILE & (bishops << 9);
}
/**
Returns all the bishop north-west moves.
@param bishops The bishops.
@param emptySquares The emptySquares squares.
@return The moves.
*/
UI64 Position::bishopNW(UI64 bishops, UI64 emptySquares)
{
emptySquares &= ~H_FILE;
bishops |= emptySquares & (bishops << 7);
bishops |= emptySquares & (bishops << 7);
bishops |= emptySquares & (bishops << 7);
bishops |= emptySquares & (bishops << 7);
bishops |= emptySquares & (bishops << 7);
bishops |= emptySquares & (bishops << 7);
return ~H_FILE & (bishops << 7);
}
/**
Returns all the bishop south-west moves.
@param bishops The bishops.
@param emptySquares The emptySquares squares.
@return The moves.
*/
UI64 Position::bishopSW(UI64 bishops, UI64 emptySquares)
{
emptySquares &= ~H_FILE;
bishops |= emptySquares & (bishops >> 9);
bishops |= emptySquares & (bishops >> 9);
bishops |= emptySquares & (bishops >> 9);
bishops |= emptySquares & (bishops >> 9);
bishops |= emptySquares & (bishops >> 9);
bishops |= emptySquares & (bishops >> 9);
return ~H_FILE & (bishops >> 9);
}
/**
Returns all the bishop south-east moves.
@param bishops The bishops.
@param emptySquares The emptySquares squares.
@return The moves.
*/
UI64 Position::bishopSE(UI64 bishops, UI64 emptySquares)
{
emptySquares &= ~A_FILE;
bishops |= emptySquares & (bishops >> 7);
bishops |= emptySquares & (bishops >> 7);
bishops |= emptySquares & (bishops >> 7);
bishops |= emptySquares & (bishops >> 7);
bishops |= emptySquares & (bishops >> 7);
bishops |= emptySquares & (bishops >> 7);
return ~A_FILE & (bishops >> 7);
}
/**
Returns all possible bishop moves.
@param bishops The bishops.
@param emptySquares The emptySquares squares.
@param own The own pieces.
@return The moves.
*/
UI64 Position::bishopMoves(UI64 bishops, UI64 emptySquares, UI64 own)
{
return bishopEscapeMoves(bishops, emptySquares) & ~own;
}
/**
Returns all possible bishop escape moves.
@param bishops The bishops.
@param emptySquares The emptySquares squares.
@return The moves.
*/
UI64 Position::bishopEscapeMoves(UI64 bishops, UI64 emptySquares)
{
return bishopNE(bishops, emptySquares) | bishopNW(bishops, emptySquares) | bishopSE(bishops, emptySquares) | bishopSW(bishops, emptySquares);
}
// KNIGHT
/**
Returns all knight north-north-east moves.
@param knights The knights.
@return The moves.
*/
UI64 Position::knightNNE(UI64 knights)
{
return (knights << 17) & ~A_FILE;
}
/**
Returns all knight north-east-east moves.
@param knights The knights.
@return The moves.
*/
UI64 Position::knightNEE(UI64 knights)
{
return (knights << 10) & ~(A_FILE | B_FILE);
}
/**
Returns all knight south-east-east moves.
@param knights The knights.
@return The moves.
*/
UI64 Position::knightSEE(UI64 knights)
{
return (knights >> 6) & ~(A_FILE | B_FILE);
}
/**
Returns all knight south-south-east moves.
@param knights The knights.
@return The moves.
*/
UI64 Position::knightSSE(UI64 knights)
{
return (knights >> 15) & ~A_FILE;
}
/**
Returns all knight north-north-west moves.
@param knights The knights.
@return The moves.
*/
UI64 Position::knightNNW(UI64 knights)
{
return (knights << 15) & ~H_FILE;
}
/**
Returns all knight north-west-west moves.
@param knights The knights.
@return The moves.
*/
UI64 Position::knightNWW(UI64 knights)
{
return (knights << 6) & ~(G_FILE | H_FILE);
}
/**
Returns all knight south-west-west moves.
@param knights The knights.
@return The moves.
*/
UI64 Position::knightSWW(UI64 knights)
{
return (knights >> 10) & ~(G_FILE | H_FILE);
}
/**
Returns all knight south-south-west moves.
@param knights The knights.
@return The moves.
*/
UI64 Position::knightSSW(UI64 knights)
{
return (knights >> 17) & ~H_FILE;
}
/**
Returns all possible knight moves.
@param knights The knights.
@return The moves.
*/
UI64 Position::knightMoves(UI64 knights, UI64 own)
{
return knightEscapeMoves(knights) & ~own;
}
/**
Returns all possible knight escape moves.
@param knights The knights.
@return The moves.
*/
UI64 Position::knightEscapeMoves(UI64 knights)
{
return knightNNE(knights) | knightNEE(knights) | knightSEE(knights) | knightSSE(knights) | knightNNW(knights) | knightNWW(knights) | knightSWW(knights) | knightSSW(knights);
}
// PAWN
/**
Returns all single push targets for pawns of the given color.
@param pawns The pawns.
@param emptySquares The emptySquares squares.
@param color The piece color (0 = White, 1 = Black).
@return The push targets.
*/
UI64 Position::singlePushTargets(UI64 pawns, UI64 emptySquares, int color)
{
return color == WHITE
? (pawns << 8) & emptySquares
: (pawns >> 8) & emptySquares;
}
/**
Returns all double push targets for pawns of the given color.
@param wPawns The pawns.
@param emptySquares The emptySquares squares.
@param color The piece color (0 = White, 1 = Black).
@return The push targets.
*/
UI64 Position::doublePushTargets(UI64 pawns, UI64 emptySquares, int color)
{
return color == WHITE
? ((singlePushTargets(pawns, emptySquares, color) << 8) & emptySquares) & 0x00000000FF000000 // rank 4
: ((singlePushTargets(pawns, emptySquares, color) >> 8) & emptySquares) & 0x000000FF00000000; // rank 5
}
/**
Returns all pawn attacks for the given color.
@param pawns The pawns.
@param color The piece color (0 = White, 1 = Black).
@return The attacks.
*/
UI64 Position::pawnAttacks(UI64 pawns, int color)
{
return color == WHITE
? ((pawns << 9) & ~A_FILE) | ((pawns << 7) & ~H_FILE)
: ((pawns >> 7) & ~A_FILE) | ((pawns >> 9) & ~H_FILE);
}
/**
Returns all possible moves for pawns of the given color.
@param pawns The pawns.
@param emptySquares The emptySquares squares.
@param bitboards The bitboards.
@return The moves.
*/
UI64 Position::pawnMoves(UI64 pawns, UI64 emptySquares, UI64 bitboards[], int color)
{
UI64 moves = pawnAttacks(pawns, color) & (bitboards[B_PIECES] | bitboards[ENPASSANT]);
moves |= singlePushTargets(pawns, emptySquares, color);
moves |= doublePushTargets(pawns, emptySquares, color);
return moves;
}
/* -----------------------------------------------------------------------------------------------
AI
----------------------------------------------------------------------------------------------- */
/**
Returns all possible attacks for the white player.
@param bitboards The bitboards.
@return The attacks.
*/
UI64 Position::wAttacks(UI64 bitboards[])
{
UI64 attacks = pawnAttacks(bitboards[W_PAWN], WHITE);
attacks |= knightMoves(bitboards[W_KNIGHT], bitboards[W_PIECES]);
attacks |= rookMoves(bitboards[W_ROOK], bitboards[EMPTYSQUARES], bitboards[W_PIECES]);
attacks |= bishopMoves(bitboards[W_BISHOP], bitboards[EMPTYSQUARES], bitboards[W_PIECES]);
attacks |= queenMoves(bitboards[W_QUEEN], (bitboards[EMPTYSQUARES]), (bitboards[W_PIECES]));
attacks |= kingMoves(bitboards[W_KING], bitboards[W_PIECES], bitboards);
return attacks;
}
/**
Returns all possible attacks for the black player.
@param bitboards The bitboards.
@return The attacks.
*/
UI64 Position::bAttacks(UI64 bitboards[])
{
UI64 attacks = pawnAttacks(bitboards[B_PAWN], BLACK);
attacks |= knightMoves(bitboards[B_KNIGHT], bitboards[B_PIECES]);
attacks |= rookMoves(bitboards[B_ROOK], bitboards[EMPTYSQUARES], bitboards[B_PIECES]);
attacks |= bishopMoves(bitboards[B_BISHOP], bitboards[EMPTYSQUARES], bitboards[B_PIECES]);
attacks |= queenMoves(bitboards[B_QUEEN], (bitboards[EMPTYSQUARES]), (bitboards[B_PIECES]));
attacks |= kingMoves(bitboards[B_KING], bitboards[B_PIECES], bitboards);
return attacks;
}
/**
Returns all possible moves for the white player.
@param bitboards The bitboards.
@return The moves.
*/
UI64 Position::wMoves(UI64 bitboards[])
{
UI64 moves = pawnMoves(bitboards[W_PAWN], bitboards[EMPTYSQUARES], bitboards, WHITE);
moves |= knightMoves(bitboards[W_KNIGHT], bitboards[W_PIECES]);
moves |= rookMoves(bitboards[W_ROOK], bitboards[EMPTYSQUARES], bitboards[W_PIECES]);
moves |= bishopMoves(bitboards[W_BISHOP], bitboards[EMPTYSQUARES], bitboards[W_PIECES]);
moves |= queenMoves(bitboards[W_QUEEN], (bitboards[EMPTYSQUARES]), (bitboards[W_PIECES]));
moves |= kingMoves(bitboards[W_KING], bitboards[W_PIECES],bitboards);
return moves;
}
/**
Returns all possible moves for the black player.
@param bitboards The bitboards.
@return The moves.
*/
UI64 Position::bMoves(UI64 bitboards[])
{
UI64 moves = pawnMoves(bitboards[B_PAWN], bitboards[EMPTYSQUARES], bitboards, WHITE);
moves |= knightMoves(bitboards[B_KNIGHT], bitboards[B_PIECES]);
moves |= rookMoves(bitboards[B_ROOK], bitboards[EMPTYSQUARES], bitboards[B_PIECES]);
moves |= bishopMoves(bitboards[B_BISHOP], bitboards[EMPTYSQUARES], bitboards[B_PIECES]);
moves |= queenMoves(bitboards[B_QUEEN], (bitboards[EMPTYSQUARES]), (bitboards[B_PIECES]));
moves |= kingMoves(bitboards[B_KING], bitboards[B_PIECES],bitboards);
return moves;
}
/**
Returns all possible escape moves for the white player.
@param bitboards The bitboards.
@return The moves.
*/
UI64 Position::wEscapeMoves(UI64 bitboards[])
{
UI64 moves = kingMoves(bitboards[W_KING], bitboards[W_PIECES], bitboards);
UI64 attacks = pawnAttacks(bitboards[B_PAWN], BLACK);
attacks |= kingMoves(bitboards[B_KING], bitboards[B_PIECES], bitboards);
attacks |= knightEscapeMoves(bitboards[B_KNIGHT]);
attacks |= rookMoves(bitboards[B_ROOK], bitboards[EMPTYSQUARES] | bitboards[W_KING], bitboards[B_PIECES] & ~moves);
attacks |= bishopMoves(bitboards[B_BISHOP], bitboards[EMPTYSQUARES] | bitboards[W_KING], bitboards[B_PIECES] & ~moves);
attacks |= queenMoves(bitboards[B_QUEEN], bitboards[EMPTYSQUARES] | bitboards[W_KING], bitboards[B_PIECES] & ~moves);
return moves & ~attacks;
}
/**
Returns all possible escape moves for the black player.
@param bitboards The bitboards.
@return The moves.
*/
UI64 Position::bEscapeMoves(UI64 bitboards[])
{
UI64 moves = kingMoves(bitboards[B_KING], bitboards[B_PIECES], bitboards);
UI64 attacks = pawnAttacks(bitboards[W_PAWN], WHITE);
attacks |= kingMoves(bitboards[W_KING], bitboards[W_PIECES], bitboards);
attacks |= knightEscapeMoves(bitboards[W_KNIGHT]);
attacks |= rookMoves(bitboards[W_ROOK], bitboards[EMPTYSQUARES] | bitboards[B_KING], bitboards[W_PIECES] & ~moves);
attacks |= bishopMoves(bitboards[W_BISHOP], bitboards[EMPTYSQUARES] | bitboards[B_KING], bitboards[W_PIECES] & ~moves);
attacks |= queenMoves(bitboards[W_QUEEN], bitboards[EMPTYSQUARES] | bitboards[B_KING], bitboards[W_PIECES] & ~moves);
return moves & ~attacks;
}
/**
Returns the moves for a pinned white piece.
@param piece The pinned piece.
@param moves The moves.
@param bitboards The bitboards.
@return The moves.
*/
UI64 Position::wPinnedMoves(UI64 piece, UI64 moves, UI64 bitboards[])
{
return pinnedAttacks(piece, bitboards[W_KING], bitboards[B_ROOK], bitboards[B_BISHOP], bitboards[B_QUEEN], bitboards[EMPTYSQUARES]) & moves;
}
/**
Returns the moves for a pinned black piece.
@param piece The pinned piece.
@param moves The moves.
@param bitboards The bitboards.
@return The moves.
*/
UI64 Position::bPinnedMoves(UI64 piece, UI64 moves, UI64 bitboards[])
{
return pinnedAttacks(piece, bitboards[B_KING], bitboards[W_ROOK], bitboards[W_BISHOP], bitboards[W_QUEEN], bitboards[EMPTYSQUARES]) & moves;
}
/**
Returns all the possible attacks against a pinned piece.
@param piece The pinned piece.
@param king The own king.
@param rooks The enemy rooks.
@param bishops The enemy bishops.
@param queen The enemy queen.
@param emptySquares The emptySquares squares.
@return The attacks.
*/
UI64 Position::pinnedAttacks(UI64 piece, UI64 king, UI64 rooks, UI64 bishops, UI64 queen, UI64 emptySquares)
{
UI64 attacks, current;
// Rook attacks.
while (rooks != 0)
{
current = rooks & -rooks;
attacks |= pieceAttacks(current, rookNorth(current, emptySquares | piece), king);
attacks |= pieceAttacks(current, rookSouth(current, emptySquares | piece), king);
attacks |= pieceAttacks(current, rookWest(current, emptySquares | piece), king);
attacks |= pieceAttacks(current, rookEast(current, emptySquares | piece), king);
rooks &= rooks - 1;
}
// Bishop attacks.
while (bishops != 0)
{
current = bishops & -bishops;
attacks |= pieceAttacks(current, bishopNE(current, emptySquares | piece), king);
attacks |= pieceAttacks(current, bishopNW(current, emptySquares | piece), king);
attacks |= pieceAttacks(current, bishopSW(current, emptySquares | piece), king);
attacks |= pieceAttacks(current, bishopSE(current, emptySquares | piece), king);
bishops &= bishops - 1;
}
// Queen attacks.
while (queen != 0)
{
current = queen & -queen;
attacks |= pieceAttacks(current, rookNorth(current, emptySquares | piece), king);
attacks |= pieceAttacks(current, rookSouth(current, emptySquares | piece), king);
attacks |= pieceAttacks(current, rookWest(current, emptySquares | piece), king);
attacks |= pieceAttacks(current, rookEast(current, emptySquares | piece), king);
attacks |= pieceAttacks(current, bishopNE(current, emptySquares | piece), king);
attacks |= pieceAttacks(current, bishopNW(current, emptySquares | piece), king);
attacks |= pieceAttacks(current, bishopSW(current, emptySquares | piece), king);
attacks |= pieceAttacks(current, bishopSE(current, emptySquares | piece), king);
queen &= queen -1;
}
return attacks;
}
/**
Returns the attacks for the given piece.
@param pieces The current positions of the attacking pieces.
@param attacks The possible attacks.
@return The attacks.
*/
UI64 Position::pieceAttacks(UI64 piece, UI64 attacks, UI64 king)
{
return (attacks & king) != 0 ? piece | attacks : 0;
}
/**
Returns the moves for blocking check for the given white piece.
@param piece The piece.
@param moves The moves.
@param bitboards The bitboards.
@return The moves.
*/
UI64 Position::wBlockCheck(UI64 piece, UI64 moves, UI64 bitboards[])
{
return blockAttacks(piece, bitboards[W_KING], bitboards[W_PIECES], bitboards[B_PAWN], bitboards[B_KNIGHT], bitboards[B_BISHOP], bitboards[B_ROOK], bitboards[B_QUEEN], bitboards[EMPTYSQUARES], WHITE) & moves;
}
/**
Returns the moves for blocking check for the given black piece.
@param piece The piece.
@param moves The moves.
@param bitboards The bitboards.
@return The moves.
*/
UI64 Position::bBlockCheck(UI64 piece, UI64 moves, UI64 bitboards[])
{
return blockAttacks(piece, bitboards[B_KING], bitboards[B_PIECES], bitboards[W_PAWN], bitboards[W_KNIGHT], bitboards[W_BISHOP], bitboards[W_ROOK], bitboards[W_QUEEN], bitboards[EMPTYSQUARES], BLACK) & moves;
}
/**
Returns the moves for blicking attaccks for the given piece.
@param piece The piece.
@param king The own king.
@param own The own pieces.
@param pawns The enemy pawns.
@param knights The enemy knights.
@param bishops The enemy bishops.
@param rooks The enemy rooks.
@param queen The enemy queen.
@param emptySquares The emptySquares squares.
@param color The piece color (0 = White, 1 = Black).
@return The moves.
*/
UI64 Position::blockAttacks(UI64 piece, UI64 king, UI64 own, UI64 pawns, UI64 knights, UI64 bishops, UI64 rooks, UI64 queen, UI64 emptySquares, int color)
{
int attackerCount = 0;
UI64 attacks, current, result;
// Pawn attacks.
while (pawns != 0)
{
current = pawns & -pawns;
result = pieceAttacks(current, pawnAttacks(current, color), king);
if (result != 0)
attackerCount++;
attacks |= result;
pawns &= pawns - 1;
}
// Knight attacks.
while (knights != 0)
{
current = knights & -knights;
result = pieceAttacks(current, knightMoves(current, own), king);
if (result != 0)
attackerCount++;
attacks |= result;
knights &= knights - 1;
}
// Rook attacks.
while (rooks != 0)
{
current = rooks & -rooks;
result = pieceAttacks(current, rookNorth(rooks, emptySquares), king);
if (result != 0)
attackerCount++;
attacks |= result;
result = pieceAttacks(current, rookSouth(rooks, emptySquares), king);
if (result != 0)
attackerCount++;
attacks |= result;
result = pieceAttacks(current, rookWest(rooks, emptySquares), king);
if (result != 0)
attackerCount++;
attacks |= result;
result = pieceAttacks(current, rookEast(rooks, emptySquares), king);
if (result != 0)
attackerCount++;
attacks |= result;
rooks &= rooks - 1;
}
// Bishop attacks.
while (bishops != 0)
{
current = bishops & -bishops;
result = pieceAttacks(current, bishopNE(bishops, emptySquares), king);
if (result != 0)
attackerCount++;
attacks |= result;
result = pieceAttacks(current, bishopNW(bishops, emptySquares), king);
if (result != 0)
attackerCount++;
attacks |= result;
result = pieceAttacks(current, bishopSW(bishops, emptySquares), king);
if (result != 0)
attackerCount++;
attacks |= result;
result = pieceAttacks(current, bishopSE(bishops, emptySquares), king);
if (result != 0)
attackerCount++;
attacks |= result;
bishops &= bishops - 1;
}
// Queen attacks.
while (queen != 0)
{
current = queen & -queen;
result = pieceAttacks(current, rookNorth(queen, emptySquares), king);
if (result != 0)
attackerCount++;
attacks |= result;
result = pieceAttacks(current, rookSouth(queen, emptySquares), king);
if (result != 0)
attackerCount++;
attacks |= result;
result = pieceAttacks(current, rookWest(queen, emptySquares), king);
if (result != 0)
attackerCount++;
attacks |= result;
result = pieceAttacks(current, rookEast(queen, emptySquares), king);
if (result != 0)
attackerCount++;
attacks |= result;
result = pieceAttacks(current, bishopNE(queen, emptySquares), king);
if (result != 0)
attackerCount++;
attacks |= result;
result = pieceAttacks(current, bishopNW(queen, emptySquares), king);
if (result != 0)
attackerCount++;
attacks |= result;
result = pieceAttacks(current, bishopSW(queen, emptySquares), king);
if (result != 0)
attackerCount++;
attacks |= result;
result = pieceAttacks(current, bishopSE(queen, emptySquares), king);
if (result != 0)
attackerCount++;
attacks |= result;
queen &= queen -1;
}
return attackerCount == 1 ? attacks : 0;
}
/**
Returns whether the given white piece is pinned.
@param piece The piece.
@param bitboards The bitboards.
@return The result.
*/
bool Position::wPiecePinned(UI64 piece, UI64 bitboards[])
{
UI64 attacks = rookMoves(bitboards[B_ROOK], bitboards[EMPTYSQUARES] | piece, bitboards[B_PIECES]);
attacks |= bishopMoves(bitboards[B_BISHOP], bitboards[EMPTYSQUARES] | piece, bitboards[B_PIECES]);
attacks |= queenMoves(bitboards[B_QUEEN], bitboards[EMPTYSQUARES] | piece, bitboards[B_PIECES]);
return (attacks & bitboards[W_KING]) != 0;
}
/**
Returns whether the given black piece is pinned.
@param piece The piece.
@param bitboards The bitboards.
@return The result.
*/
bool Position::bPiecePinned(UI64 piece, UI64 bitboards[])
{
UI64 attacks = rookMoves(bitboards[W_ROOK], bitboards[EMPTYSQUARES] | piece, bitboards[W_PIECES]);
attacks |= bishopMoves(bitboards[W_BISHOP], bitboards[EMPTYSQUARES] | piece, bitboards[W_PIECES]);
attacks |= queenMoves(bitboards[W_QUEEN], bitboards[EMPTYSQUARES] | piece, bitboards[W_PIECES]);
return (attacks & bitboards[B_KING]) != 0;
}
/**
todo: docblock
*/
UI64 Position::fillNorth(UI64 bitboard)
{
return (bitboard << 8) | (bitboard << 16) | (bitboard << 32);
}
/**
todo: docblock
*/
UI64 Position::fillSouth(UI64 bitboard)
{
return (bitboard >> 8) | (bitboard >> 16) | (bitboard >> 32);
}
/**
Returns the number of items on the given bitboard.
@param bitboard The bitboard.
@return The count.
*/
int Position::itemCount(UI64 bitboard) const
{
int count = 0;
while (bitboard != 0)
{
count++;
bitboard &= bitboard - 1;
}
return count;
}
/**
Returns the number of files with at least two pawns.
@param pawns The pawns.
@return The count.
*/
int Position::doublePawnCount(UI64 pawns) const
{
int count = 0;
if ((itemCount(pawns) & A_FILE) >= 2)
count++;
if ((itemCount(pawns) & B_FILE) >= 2)
count++;
if ((itemCount(pawns) & C_FILE) >= 2)
count++;
if ((itemCount(pawns) & D_FILE) >= 2)
count++;
if ((itemCount(pawns) & E_FILE) >= 2)
count++;
if ((itemCount(pawns) & F_FILE) >= 2)
count++;
if ((itemCount(pawns) & G_FILE) >= 2)
count++;
if ((itemCount(pawns) & H_FILE) >= 2)
count++;
return count;
}
/**
Adds moves for the given pieces.
@param pieces The pieces.
@param moves The moves.
@return void
*/
void Position::addMoves(UI64 pieces, UI64 moves)
{
while (moves != 0)
{
std::vector<UI64> tmp;
tmp.insert(tmp.end(), pieces);
tmp.insert(tmp.end(), moves & -moves);
mMoves.insert(mMoves.end(), tmp);
moves &= moves - 1;
}
}
int Position::getTurn() const
{
return mTurn;
}
void Position::setTurn(int turn)
{
mTurn = turn;
}
#pragma once
class Position
{
public:
Position(void);
~Position(void);
void setup(void);
std::vector<std::vector<UI64>> genLegalMoves(UI64 bitboards[]);
bool whiteChecked(UI64 bitboards[]);
bool blackChecked(UI64 bitboards[]);
UI64 wAttacks(UI64 bitboards[]);
UI64 bAttacks(UI64 bitboards[]);
double evaluate(UI64 bitboards[]);
int getTurn() const;
void setTurn(int turn);
private:
int mTurn;
std::vector<Move> mLegalMoves;
std::vector<std::vector<UI64>> mMoves;
bool mWhiteCastleShortAllowed;
bool mWhiteCastleLongAllowed;
bool mBlackCastleShortAllowed;
bool mBlackCastleLongAllowed;
// Move generation
UI64 kingMoves(UI64 king, UI64 own, UI64 bitboards[]);
UI64 queenMoves(UI64 queen, UI64 empty, UI64 own);
UI64 queenEscapeMoves(UI64 queen, UI64 empty);
UI64 rookEast(UI64 rooks, UI64 empty);
UI64 rookWest(UI64 rooks, UI64 empty);
UI64 rookNorth(UI64 rooks, UI64 empty);
UI64 rookSouth(UI64 rooks, UI64 empty);
UI64 rookMoves(UI64 rooks, UI64 empty, UI64 own);
UI64 rookEscapeMoves(UI64 rooks, UI64 empty);
UI64 bishopNE(UI64 bishops, UI64 empty);
UI64 bishopNW(UI64 bishops, UI64 empty);
UI64 bishopSW(UI64 bishops, UI64 empty);
UI64 bishopSE(UI64 bishops, UI64 empty);
UI64 bishopMoves(UI64 bishops, UI64 empty, UI64 own);
UI64 bishopEscapeMoves(UI64 bishops, UI64 empty);
UI64 knightNNE(UI64 knights);
UI64 knightNEE(UI64 knights);
UI64 knightSEE(UI64 knights);
UI64 knightSSE(UI64 knights);
UI64 knightNNW(UI64 knights);
UI64 knightNWW(UI64 knights);
UI64 knightSWW(UI64 knights);
UI64 knightSSW(UI64 knights);
UI64 knightMoves(UI64 knights, UI64 own);
UI64 knightEscapeMoves(UI64 knights);
UI64 singlePushTargets(UI64 pawns, UI64 empty, int color);
UI64 doublePushTargets(UI64 pawns, UI64 empty, int color);
UI64 pawnAttacks(UI64 pawns, int color);
UI64 pawnMoves(UI64 pawns, UI64 empty, UI64 bitboards[], int color);
// AI
UI64 wMoves(UI64 bitboards[]);
UI64 bMoves(UI64 bitboards[]);
UI64 wEscapeMoves(UI64 bitboards[]);
UI64 bEscapeMoves(UI64 bitboards[]);
UI64 wPinnedMoves(UI64 piece, UI64 moves, UI64 bitboards[]);
UI64 bPinnedMoves(UI64 piece, UI64 moves, UI64 bitboards[]);
UI64 pinnedAttacks(UI64 piece, UI64 king, UI64 rooks, UI64 bishops, UI64 queen, UI64 empty);
UI64 pieceAttacks(UI64 pieces, UI64 attacks, UI64 king);
UI64 wBlockCheck(UI64 piece, UI64 moves, UI64 bitboards[]);
UI64 bBlockCheck(UI64 piece, UI64 moves, UI64 bitboards[]);
UI64 blockAttacks(UI64 piece, UI64 king, UI64 own, UI64 pawns, UI64 knights, UI64 bishops, UI64 rooks, UI64 queen, UI64 empty, int color);
bool wPiecePinned(UI64 piece, UI64 bitboards[]);
bool bPiecePinned(UI64 piece, UI64 bitboards[]);
// Utils
UI64 fillNorth(UI64 bitboard);
UI64 fillSouth(UI64 bitboard);
int itemCount(UI64 bitboard) const;
int doublePawnCount(UI64 pawns) const;
void addMoves(UI64 pieces, UI64 moves);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment