174 changes: 108 additions & 66 deletions texellib/src/moveGen.cpp

Large diffs are not rendered by default.

38 changes: 16 additions & 22 deletions texellib/src/moveGen.hpp
Expand Up @@ -112,14 +112,22 @@ class MoveGen {
* Return true if a square is attacked by the opposite side.
*/
static bool sqAttacked(const Position& pos, int sq) {
if (pos.whiteMove) {
U64 occupied = pos.whiteBB | pos.blackBB;
return sqAttacked(pos, sq, occupied);
}
static bool sqAttacked(const Position& pos, int sq, U64 occupied) {
return pos.whiteMove ? sqAttacked<true>(pos, sq, occupied)
: sqAttacked<false>(pos, sq, occupied);
}
template <bool wtm>
static bool sqAttacked(const Position& pos, int sq, U64 occupied) {
if (wtm) {
if ((BitBoard::knightAttacks[sq] & pos.pieceTypeBB[Piece::BKNIGHT]) != 0)
return true;
if ((BitBoard::kingAttacks[sq] & pos.pieceTypeBB[Piece::BKING]) != 0)
return true;
if ((BitBoard::wPawnAttacks[sq] & pos.pieceTypeBB[Piece::BPAWN]) != 0)
return true;
U64 occupied = pos.whiteBB | pos.blackBB;
U64 bbQueen = pos.pieceTypeBB[Piece::BQUEEN];
if ((BitBoard::bishopAttacks(sq, occupied) & (pos.pieceTypeBB[Piece::BBISHOP] | bbQueen)) != 0)
return true;
Expand All @@ -132,7 +140,6 @@ class MoveGen {
return true;
if ((BitBoard::bPawnAttacks[sq] & pos.pieceTypeBB[Piece::WPAWN]) != 0)
return true;
U64 occupied = pos.whiteBB | pos.blackBB;
U64 bbQueen = pos.pieceTypeBB[Piece::WQUEEN];
if ((BitBoard::bishopAttacks(sq, occupied) & (pos.pieceTypeBB[Piece::WBISHOP] | bbQueen)) != 0)
return true;
Expand All @@ -149,6 +156,9 @@ class MoveGen {
*/
static void removeIllegal(Position& pos, MoveList& moveList);

/** Return true if the pseudo-legal move "move" is legal is position "pos". */
static bool isLegal(Position& pos, const Move& move);

private:
/**
* Return the next piece in a given direction, starting from sq.
Expand Down Expand Up @@ -193,17 +203,10 @@ class MoveGen {
return -1;
}

static bool addPawnMovesByMask(MoveList& moveList, const Position& pos, U64 mask,
static void addPawnMovesByMask(MoveList& moveList, const Position& pos, U64 mask,
int delta, bool allPromotions) {
if (mask == 0)
return false;
U64 oKingMask = pos.pieceTypeBB[pos.whiteMove ? Piece::BKING : Piece::WKING];
if ((mask & oKingMask) != 0) {
int sq = BitBoard::numberOfTrailingZeros(mask & oKingMask);
moveList.size = 0;
moveList.addMove(sq + delta, sq, Piece::EMPTY);
return true;
}
return;
U64 promMask = mask & BitBoard::maskRow1Row8;
mask &= ~promMask;
while (promMask != 0) {
Expand Down Expand Up @@ -231,7 +234,6 @@ class MoveGen {
moveList.addMove(sq + delta, sq, Piece::EMPTY);
mask &= (mask - 1);
}
return false;
}

static void addPawnDoubleMovesByMask(MoveList& moveList, const Position& pos,
Expand All @@ -243,20 +245,12 @@ class MoveGen {
}
}

static bool addMovesByMask(MoveList& moveList, const Position& pos, int sq0, U64 mask) {
U64 oKingMask = pos.pieceTypeBB[pos.whiteMove ? Piece::BKING : Piece::WKING];
if ((mask & oKingMask) != 0) {
int sq = BitBoard::numberOfTrailingZeros(mask & oKingMask);
moveList.size = 0;
moveList.addMove(sq0, sq, Piece::EMPTY);
return true;
}
static void addMovesByMask(MoveList& moveList, const Position& pos, int sq0, U64 mask) {
while (mask != 0) {
int sq = BitBoard::numberOfTrailingZeros(mask);
moveList.addMove(sq0, sq, Piece::EMPTY);
mask &= (mask - 1);
}
return false;
}

/** Not implemented. */
Expand Down
34 changes: 7 additions & 27 deletions texellib/src/search.cpp
Expand Up @@ -404,11 +404,6 @@ Search::negaScout(int alpha, int beta, int ply, int depth, int recaptureSquare,

// Draw tests
if (canClaimDraw50(pos)) {
if (MoveGen::canTakeKing(pos)) {
int score = MATE0 - ply;
log.logNodeEnd(searchTreeInfo[ply].nodeIdx, score, TType::T_EXACT, UNKNOWN_SCORE, hKey);
return score;
}
if (inCheck) {
MoveGen::MoveList moves;
MoveGen::pseudoLegalMoves(pos, moves);
Expand Down Expand Up @@ -480,7 +475,7 @@ Search::negaScout(int alpha, int beta, int ply, int depth, int recaptureSquare,
if (evalScore == UNKNOWN_SCORE) {
evalScore = eval.evalPos(pos);
}
const int razorMargin = 250;
const int razorMargin = 250; // FIXME!! Try making depth-dependant
if (evalScore < beta - razorMargin) {
q0Eval = evalScore;
int score = quiesce(alpha-razorMargin, beta-razorMargin, ply, 0, inCheck);
Expand Down Expand Up @@ -524,11 +519,6 @@ Search::negaScout(int alpha, int beta, int ply, int depth, int recaptureSquare,
sti.currentMove = emptyMove;
if ( (depth >= 3*plyScale) && !inCheck && sti.allowNullMove &&
(std::abs(beta) <= MATE0 / 2)) {
if (MoveGen::canTakeKing(pos)) {
int score = MATE0 - ply;
log.logNodeEnd(sti.nodeIdx, score, TType::T_EXACT, evalScore, hKey);
return score;
}
bool nullOk;
if (pos.whiteMove) {
nullOk = (pos.wMtrl > pos.wMtrlPawns) && (pos.wMtrlPawns > 0);
Expand Down Expand Up @@ -647,11 +637,6 @@ Search::negaScout(int alpha, int beta, int ply, int depth, int recaptureSquare,
if ((mi > 0) || !hashMoveSelected)
selectBest(moves, mi);
Move& m = moves[mi];
if (pos.getPiece(m.to()) == (pos.whiteMove ? Piece::BKING : Piece::WKING)) {
int score = MATE0-ply;
log.logNodeEnd(sti.nodeIdx, score, TType::T_EXACT, evalScore, hKey);
return score; // King capture
}
int newCaptureSquare = -1;
bool isCapture = (pos.getPiece(m.to()) != Piece::EMPTY);
bool isPromotion = (m.promoteTo() != Piece::EMPTY);
Expand All @@ -678,6 +663,8 @@ Search::negaScout(int alpha, int beta, int ply, int depth, int recaptureSquare,
if (doFutility) {
score = futilityScore;
} else {
if (!MoveGen::isLegal(pos, m))
continue;
int moveExtend = 0;
if (posExtend == 0) {
const int pV = Evaluate::pV;
Expand Down Expand Up @@ -851,15 +838,8 @@ Search::quiesce(int alpha, int beta, int ply, int depth, const bool inCheck) {
q0Eval = score;
}
}
if (score >= beta) {
if ((depth == 0) && (score < MATE0 - ply)) {
if (MoveGen::canTakeKing(pos)) {
// To make stale-mate detection work
score = MATE0 - ply;
}
}
if (score >= beta)
return score;
}
const int evalScore = score;
if (score > alpha)
alpha = score;
Expand All @@ -882,8 +862,6 @@ Search::quiesce(int alpha, int beta, int ply, int depth, const bool inCheck) {
selectBest(moves, mi);
}
const Move& m = moves[mi];
if (pos.getPiece(m.to()) == (pos.whiteMove ? Piece::BKING : Piece::WKING))
return MATE0-ply; // King capture
bool givesCheck = false;
bool givesCheckComputed = false;
if (inCheck) {
Expand All @@ -904,7 +882,7 @@ Search::quiesce(int alpha, int beta, int ply, int depth, const bool inCheck) {
continue;
int capt = Evaluate::pieceValue[pos.getPiece(m.to())];
int prom = Evaluate::pieceValue[m.promoteTo()];
int optimisticScore = evalScore + capt + prom + 200;
int optimisticScore = evalScore + capt + prom + 200; // FIXME!! Try lower value (50-75?)
if (optimisticScore < alpha) { // Delta pruning
if ((pos.wMtrlPawns > 0) && (pos.wMtrl > capt + pos.wMtrlPawns) &&
(pos.bMtrlPawns > 0) && (pos.bMtrl > capt + pos.bMtrlPawns)) {
Expand All @@ -921,6 +899,8 @@ Search::quiesce(int alpha, int beta, int ply, int depth, const bool inCheck) {
}
}
}
if (!MoveGen::isLegal(pos, m))
continue;

if (!givesCheckComputed && (depth - 1 > -2))
givesCheck = MoveGen::givesCheck(pos, m);
Expand Down
33 changes: 2 additions & 31 deletions texellibtest/src/moveGenTest.cpp
Expand Up @@ -104,12 +104,8 @@ getMoveList0(Position& pos, bool onlyLegal) {
for (size_t i = 0; i < strMoves.size(); i++) {
const std::string& sm = strMoves[i];
Move m = TextIO::uciStringToMove(sm);
if (!m.isEmpty()) {
pos.makeMove(m, ui);
bool invalid = MoveGen::canTakeKing(pos);
pos.unMakeMove(m, ui);
if (invalid) m.setMove(0,0,0,0);
}
if (!m.isEmpty() && !MoveGen::isLegal(pos, m))
m.setMove(0,0,0,0);
if (m.isEmpty()) // Move was illegal (but pseudo-legal)
continue;
bool qProm = false; // Promotion types considered in qsearch
Expand Down Expand Up @@ -467,30 +463,6 @@ testRemoveIllegal() {
ASSERT_EQUAL(1, strMoves.size());
}

/**
* Test that if king capture is possible, only a king capture move is returned in the move list.
*/
static void
testKingCapture() {
Position pos = TextIO::readFEN("8/4k3/8/8/8/8/8/4RK2 b - - 0 1");
pos.setWhiteMove(true);
std::vector<std::string> strMoves = getMoveList(pos, false);
ASSERT_EQUAL(1, strMoves.size());
ASSERT_EQUAL("e1e7", strMoves[0]);

pos.setPiece(Position::getSquare(0, 2), Piece::WBISHOP);
pos.setPiece(Position::getSquare(4, 1), Piece::WPAWN);
strMoves = getMoveList(pos, false);
ASSERT_EQUAL(1, strMoves.size());
ASSERT_EQUAL("a3e7", strMoves[0]);

pos.setPiece(Position::getSquare(1, 3), Piece::WPAWN);
pos.setPiece(Position::getSquare(5, 5), Piece::WPAWN);
strMoves = getMoveList(pos, false);
ASSERT_EQUAL(1, strMoves.size());
ASSERT_EQUAL("f6e7", strMoves[0]);
}

/** Test that captureList and captureAndcheckList are generated correctly. */
static void
testCaptureList() {
Expand Down Expand Up @@ -548,7 +520,6 @@ MoveGenTest::getSuite() const {
s.push_back(CUTE(testInCheck));
s.push_back(CUTE(testGivesCheck));
s.push_back(CUTE(testRemoveIllegal));
s.push_back(CUTE(testKingCapture));
s.push_back(CUTE(testCaptureList));
s.push_back(CUTE(testCheckEvasions));
return s;
Expand Down