Skip to content

Commit

Permalink
Fixing Illegal Moves (#47) bench: 6188363
Browse files Browse the repository at this point in the history
* temporary fix, bench: 6188363

* Actually Clear Qsearch History, bench: 6188363

* Double extension Limit, bench: 6039065

* Fix double extension cap, bench: 6188363

* Revert "Double extension Limit, bench: 6039065"

This reverts commit fa2f278.

* Revert "Revert "Double extension Limit, bench: 6039065""

This reverts commit 5051cfa.

* Revert "temporary fix, bench: 6188363"

This reverts commit 316ca5f.

* Revert "Revert "temporary fix, bench: 6188363""

This reverts commit 2b1facc.
  • Loading branch information
Vast342 authored Feb 20, 2024
1 parent 8c02a20 commit 80b1d97
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 39 deletions.
4 changes: 2 additions & 2 deletions src/datagen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ double runGame(Engine &engine, std::vector<std::string>& fenVector, Board board)
int colorMultiplier = 2 * board.getColorToMove() - 1;
if(board.isInCheck()) {
// checkmate! opponent wins, so if black wins it's -1000000 * -(-1)
score = mateScore * -colorMultiplier;
score = matedScore * -colorMultiplier;
} else {
score = 0;
}
Expand All @@ -163,7 +163,7 @@ double runGame(Engine &engine, std::vector<std::string>& fenVector, Board board)
outOfBounds = true;
}
if(((1ULL << result.first.getEndSquare()) & board.getOccupiedBitboard()) == 0 && result.first.getFlag() != EnPassant) {
if(abs(score) < abs(mateScore + 256)) {
if(abs(score) < abs(matedScore + 256)) {
if(!board.isInCheck()) {
// non-mate, not in check, add fen string to vector
fenVector.push_back(board.getFenString() + " | " + std::to_string(score));
Expand Down
1 change: 1 addition & 0 deletions src/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@ extern Tunable qhsSubtractor;
extern Tunable qhpDepthMultiplier;

extern Tunable dexMargin;
extern Tunable dexLimit;

extern std::vector<Tunable *> tunables;

Expand Down
123 changes: 89 additions & 34 deletions src/search.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ void Engine::clearHistory() {
std::memset(historyTable.data(), 0, sizeof(historyTable));
std::memset(noisyHistoryTable.data(), 0, sizeof(noisyHistoryTable));
std::memset(conthistTable.get(), 0, sizeof(conthistTable));
std::memset(qsHistoryTable.data(), 0, sizeof(qsHistoryTable));
}

Move Engine::getBestMove() {
Expand All @@ -52,6 +53,7 @@ Move Engine::getBestMove() {

// resets the engine, done when ucinewgame is sent
void Engine::resetEngine() {
stack = {};
TT->clearTable();
clearHistory();
}
Expand Down Expand Up @@ -447,6 +449,8 @@ int Engine::negamax(Board &board, int depth, int alpha, int beta, int ply, bool
}
}

if(ply > 0) stack[ply].doubleExtensions = stack[ply - 1].doubleExtensions;

// get the moves
std::array<Move, 256> moves;
std::array<Move, 256> testedMoves;
Expand All @@ -456,18 +460,17 @@ int Engine::negamax(Board &board, int depth, int alpha, int beta, int ply, bool
scoreMoves(board, moves, moveValues, totalMoves, inSingularSearch ? Move() : entry->bestMove, ply);

// values useful for writing to TT later
int bestScore = mateScore;
int bestScore = matedScore;
Move bestMove;
int flag = FailLow;

// extensions, currently only extending if you are in check
depth += inCheck;

// Mate Distance Pruning (I will test it at some point I swear)
if(!isPV) {
// my mateScore is a large negative number and that is what I return, people seem to get confused by that when I talk with other devs.
const auto mdAlpha = std::max(alpha, mateScore + ply);
const auto mdBeta = std::min(beta, -mateScore - ply - 1);
if(!isPV) {
const auto mdAlpha = std::max(alpha, matedScore + ply);
const auto mdBeta = std::min(beta, -matedScore - ply - 1);
if(mdAlpha >= mdBeta) {
return mdAlpha;
}
Expand Down Expand Up @@ -497,11 +500,11 @@ int Engine::negamax(Board &board, int depth, int alpha, int beta, int ply, bool

// move loop prunings:
// futility pruning
if(bestScore > mateScore && !inCheck && depth <= fpDepthCondition.value && staticEval + fpBase.value + depth * fpMultiplier.value <= alpha) break;
if(bestScore > matedScore && !inCheck && depth <= fpDepthCondition.value && staticEval + fpBase.value + depth * fpMultiplier.value <= alpha) break;
// Late Move Pruning
if(!isPV && isQuiet && bestScore > mateScore + 256 && quietCount > lmpBase.value + depth * depth / (2 - improving)) continue;
if(!isPV && isQuiet && bestScore > matedScore + 256 && quietCount > lmpBase.value + depth * depth / (2 - improving)) continue;
// see pruning
if(depth <= sprDepthCondition.value && isQuietOrBadCapture && bestScore > mateScore + 256 && !see(board, move, depth * (isCapture ? sprCaptureThreshold.value : sprQuietThreshold.value))) continue;
if(depth <= sprDepthCondition.value && isQuietOrBadCapture && bestScore > matedScore + 256 && !see(board, move, depth * (isCapture ? sprCaptureThreshold.value : sprQuietThreshold.value))) continue;
// History Pruning
if(ply > 0 && !isPV && isQuiet && depth <= hipDepthCondition.value && moveValues[i] < hipDepthMultiplier.value * depth) break;

Expand All @@ -512,15 +515,16 @@ int Engine::negamax(Board &board, int depth, int alpha, int beta, int ply, bool
int TTExtensions = 0;
// determine whether or not to extend TT move (Singular Extensions)
if(!inSingularSearch && entry->bestMove == move && depth >= sinDepthCondition.value && entry->depth >= depth - sinDepthMargin.value && entry->flag != FailLow) {
const auto sBeta = std::max(mateScore, entry->score - depth * int(sinDepthScale.value) / 16);
const auto sBeta = std::max(matedScore, entry->score - depth * int(sinDepthScale.value) / 16);
const auto sDepth = (depth - 1) / 2;

stack[ply].excluded = entry->bestMove;
const auto score = negamax(board, sDepth, sBeta - 1, sBeta, ply, true);
stack[ply].excluded = Move();
if(score < sBeta) {
if (!isPV && score < sBeta - dexMargin.value) {
if (!isPV && score < sBeta - dexMargin.value && stack[ply].doubleExtensions <= dexLimit.value) {
TTExtensions = 2;
stack[ply].doubleExtensions++;
} else {
TTExtensions = 1;
}
Expand Down Expand Up @@ -636,7 +640,7 @@ int Engine::negamax(Board &board, int depth, int alpha, int beta, int ply, bool
return alpha;
}
if(inCheck) {
return mateScore + ply;
return matedScore + ply;
}
return 0;
}
Expand Down Expand Up @@ -675,16 +679,16 @@ std::string Engine::getPV(Board board, std::vector<uint64_t> &hashVector, int nu

void Engine::outputInfo(const Board& board, int score, int depth, int elapsedTime) {
std::string scoreString = " score ";
if(abs(score) < abs(mateScore + 256)) {
if(abs(score) < abs(matedScore + 256)) {
scoreString += "cp ";
scoreString += std::to_string(normalize(score, board.getPlyCount()));
} else {
// score is checkmate in score - mateScore ply
// score is checkmate in score - matedScore ply
// position fen rn1q2rk/pp3p1p/2p4Q/3p4/7P/2NP2R1/PPP3P1/4RK2 w - - 0 1
// ^^ mate in 3 test position
int colorMultiplier = score > 0 ? 1 : -1;
scoreString += "mate ";
scoreString += std::to_string((abs(abs(score) + mateScore) / 2 + board.getColorToMove()) * colorMultiplier);
scoreString += std::to_string((abs(abs(score) + matedScore) / 2 + board.getColorToMove()) * colorMultiplier);
}
if(depth > 6) {
std::vector<uint64_t> hashVector;
Expand All @@ -696,6 +700,7 @@ void Engine::outputInfo(const Board& board, int score, int depth, int elapsedTim

// the usual search function, where you give it the amount of time it has left, and it will search in increasing depth steps until it runs out of time
Move Engine::think(Board board, int softBound, int hardBound, bool info) {
stack[0].doubleExtensions = 0;
//ageHistory();
//clearHistory();
std::memset(nodeTMTable.data(), 0, sizeof(nodeTMTable));
Expand All @@ -714,24 +719,24 @@ Move Engine::think(Board board, int softBound, int hardBound, bool info) {
// Aspiration Windows, searches with reduced bounds until it doesn't fail high or low
seldepth = depth;
int delta = aspBaseDelta.value;
int alpha = std::max(mateScore, score - delta);
int beta = std::min(-mateScore, score + delta);
int alpha = std::max(matedScore, score - delta);
int beta = std::min(-matedScore, score + delta);
const Move previousBest = rootBestMove;
if(depth > aspDepthCondition.value) {
while(true) {
score = negamax(board, depth, alpha, beta, 0, true);
if(timesUp) break;
if(score >= beta) {
beta = std::min(beta + delta, -mateScore);
beta = std::min(beta + delta, -matedScore);
} else if(score <= alpha) {
beta = (alpha + beta) / 2;
alpha = std::max(alpha - delta, mateScore);
alpha = std::max(alpha - delta, matedScore);
} else break;

delta *= aspDeltaMultiplier.value;
}
} else {
score = negamax(board, depth, mateScore, -mateScore, 0, true);
score = negamax(board, depth, matedScore, -matedScore, 0, true);
}
if(timesUp) rootBestMove = previousBest;
const auto elapsedTime = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - begin).count();
Expand All @@ -742,12 +747,36 @@ Move Engine::think(Board board, int softBound, int hardBound, bool info) {
if(info) outputInfo(board, score, depth, elapsedTime);
//if(elapsedTime > softBound) break;
}

if(rootBestMove == Move()) {
std::array<Move, 256> moves;
int totalMoves = board.getMoves(moves);
std::array<int, 256> moveValues;
Transposition* entry = TT->getEntry(board.getZobristHash());
scoreMoves(board, moves, moveValues, totalMoves, entry->bestMove, 0);

for(int i = 0; i < totalMoves; i++) {
for(int j = i + 1; j < totalMoves; j++) {
if(moveValues[j] > moveValues[i]) {
std::swap(moveValues[j], moveValues[i]);
std::swap(moves[j], moves[i]);
}
}
if(board.makeMove(moves[i])) {
board.undoMove();
rootBestMove = moves[i];
break;
}
}
}

if(info) std::cout << "bestmove " << toLongAlgebraic(rootBestMove) << std::endl;
return rootBestMove;
}

// searches done for bench, returns the number of nodes searched.
int Engine::benchSearch(Board board, int depthToSearch) {
stack[0].doubleExtensions = 0;
//clearHistory();
nodes = 0;
hardLimit = 1215752192;
Expand All @@ -763,33 +792,35 @@ int Engine::benchSearch(Board board, int depthToSearch) {
// Aspiration Windows, searches with reduced bounds until it doesn't fail high or low
seldepth = depth;
int delta = aspBaseDelta.value;
int alpha = std::max(mateScore, score - delta);
int beta = std::min(-mateScore, score + delta);
int alpha = std::max(matedScore, score - delta);
int beta = std::min(-matedScore, score + delta);
if(depth > aspDepthCondition.value) {
while(true) {
score = negamax(board, depth, alpha, beta, 0, true);

if(score >= beta) {
beta = std::min(beta + delta, -mateScore);
beta = std::min(beta + delta, -matedScore);
} else if(score <= alpha) {
beta = (alpha + beta) / 2;
alpha = std::max(alpha - delta, mateScore);
alpha = std::max(alpha - delta, matedScore);
} else break;

delta *= aspDeltaMultiplier.value;
}
} else {
score = negamax(board, depth, mateScore, -mateScore, 0, true);
score = negamax(board, depth, matedScore, -matedScore, 0, true);
}
//const auto elapsedTime = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - begin).count();
// outputs info which is picked up by the user
//outputInfo(board, score, depth, elapsedTime);
}
if(rootBestMove == Move()) std::cout << "bench returned null move" << std::endl;
return nodes;
}

// searches to a fixed depth when the user says go depth x
Move Engine::fixedDepthSearch(Board board, int depthToSearch, bool info) {
stack[0].doubleExtensions = 0;
//ageHistory();
//clearHistory();
nodes = 0;
Expand All @@ -805,23 +836,23 @@ Move Engine::fixedDepthSearch(Board board, int depthToSearch, bool info) {
for(int depth = 1; depth <= depthToSearch; depth++) {
seldepth = 0;
int delta = aspBaseDelta.value;
int alpha = std::max(mateScore, score - delta);
int beta = std::min(-mateScore, score + delta);
int alpha = std::max(matedScore, score - delta);
int beta = std::min(-matedScore, score + delta);
if(depth > aspDepthCondition.value) {
while(true) {
score = negamax(board, depth, alpha, beta, 0, true);

if(score >= beta) {
beta = std::min(beta + delta, -mateScore);
beta = std::min(beta + delta, -matedScore);
} else if(score <= alpha) {
beta = (alpha + beta) / 2;
alpha = std::max(alpha - delta, mateScore);
alpha = std::max(alpha - delta, matedScore);
} else break;

delta *= aspDeltaMultiplier.value;
}
} else {
score = negamax(board, depth, mateScore, -mateScore, 0, true);
score = negamax(board, depth, matedScore, -matedScore, 0, true);
}
if(timesUp) {
rootBestMove = previousBest;
Expand All @@ -831,11 +862,35 @@ Move Engine::fixedDepthSearch(Board board, int depthToSearch, bool info) {
if(info) outputInfo(board, score, depth, elapsedTime);
previousBest = rootBestMove;
}

if(rootBestMove == Move()) {
std::array<Move, 256> moves;
int totalMoves = board.getMoves(moves);
std::array<int, 256> moveValues;
Transposition* entry = TT->getEntry(board.getZobristHash());
scoreMoves(board, moves, moveValues, totalMoves, entry->bestMove, 0);

for(int i = 0; i < totalMoves; i++) {
for(int j = i + 1; j < totalMoves; j++) {
if(moveValues[j] > moveValues[i]) {
std::swap(moveValues[j], moveValues[i]);
std::swap(moves[j], moves[i]);
}
}
if(board.makeMove(moves[i])) {
board.undoMove();
rootBestMove = moves[i];
break;
}
}
}

if(info) std::cout << "bestmove " << toLongAlgebraic(rootBestMove) << std::endl;
return rootBestMove;
}

std::pair<Move, int> Engine::dataGenSearch(Board board, int nodeCap) {
stack[0].doubleExtensions = 0;
//clearHistory();
dataGeneration = true;
nodes = 0;
Expand All @@ -852,23 +907,23 @@ std::pair<Move, int> Engine::dataGenSearch(Board board, int nodeCap) {
// Aspiration Windows, searches with reduced bounds until it doesn't fail high or low
seldepth = depth;
int delta = aspBaseDelta.value;
int alpha = std::max(mateScore, score - delta);
int beta = std::min(-mateScore, score + delta);
int alpha = std::max(matedScore, score - delta);
int beta = std::min(-matedScore, score + delta);
if(depth > aspDepthCondition.value) {
while(true) {
score = negamax(board, depth, alpha, beta, 0, true);

if(score >= beta) {
beta = std::min(beta + delta, -mateScore);
beta = std::min(beta + delta, -matedScore);
} else if(score <= alpha) {
beta = (alpha + beta) / 2;
alpha = std::max(alpha - delta, mateScore);
alpha = std::max(alpha - delta, matedScore);
} else break;
if(nodes > nodeCap) break;
delta *= aspDeltaMultiplier.value;
}
} else {
score = negamax(board, depth, mateScore, -mateScore, 0, true);
score = negamax(board, depth, matedScore, -matedScore, 0, true);
}
//const auto elapsedTime = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - begin).count();
// outputs info which is picked up by the user
Expand Down
3 changes: 2 additions & 1 deletion src/search.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ extern bool timesUp;

constexpr int depthLimit = 120;

constexpr int mateScore = -10000000;
constexpr int matedScore = -10000000;

extern int badCaptureScore;

Expand All @@ -38,6 +38,7 @@ struct StackEntry {
bool inCheck;
// excluded move
Move excluded;
int doubleExtensions;
};

struct Engine {
Expand Down
1 change: 1 addition & 0 deletions src/tunables.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ Tunable qhsSubtractor("QHS_Subtractor", 107, 1);
Tunable qhpDepthMultiplier("QHP_DepthMultiplier", -1872, -1);

Tunable dexMargin("DEX_Margin", 50, 1);
Tunable dexLimit("DEX_Limit", 20, 1);

// Declaration of pointers to tunables

Expand Down
4 changes: 2 additions & 2 deletions src/wdldatagen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ double runGame(Engine &engine, std::vector<std::string>& fenVector, Board board)
int colorMultiplier = 2 * board.getColorToMove() - 1;
if(board.isInCheck()) {
// checkmate! opponent wins, so if black wins it's -1000000 * -(-1)
score = mateScore * -colorMultiplier;
score = matedScore * -colorMultiplier;
} else {
score = 0;
}
Expand All @@ -160,7 +160,7 @@ double runGame(Engine &engine, std::vector<std::string>& fenVector, Board board)
if(abs(score) > 7500) {
break;
}
if(abs(score) < abs(mateScore + 256)) {
if(abs(score) < abs(matedScore + 256)) {
if(!board.isInCheck()) {
// non-mate, not in check, add fen string to vectoractua
fenVector.push_back(std::to_string(i) + ' ' + std::to_string(score));
Expand Down

0 comments on commit 80b1d97

Please sign in to comment.