1. First don't generate any move and just try hash move if exists.
2. Generate all capture moves and sort them with MVA/LVV (later maybe SEE and only the winning captures here) and try them all.
3. Try if we have first or second killer move and try them.
4. Generate all quiet moves and sort them according to my history heuristics (maybe later something smarter)
The problem is I have no clue how to implement this in my current framework. I have tried to search for examples but it is very hard to find any literature or posts about it. Very simplified I use code such as this now:
Code: Select all
public Move IterativeDeepening()
{
// Reset killer, history, and PV collecting tables
ResetSortingTables();
ResetPVTables();
for (int depth = 1; depth <= _maxDepth; depth++)
{
int score = Negamax(depth, ply, alpha, beta, true);
if (!stopSearch)
{
bestMove = pvTable[0][0];
}
}
return bestMove;
}
private int Negamax(int depth, int ply, int alpha, int beta, bool nullMoveAllowed)
{
// Init variables
int score;
Move _bestMove = Move.Empty;
if (depth == 0)
{
score = QuiescenceSearch(ply, alpha, beta);
return score;
}
if (boardState.CheckForDraw()) return 0;
// Init PV table
pvTable[ply][ply] = Move.Empty;
pvLength[ply] = 0;
// TT lookup
if (Transpositions.ReadTT(boardState.ZobristKey, depth, ply, alpha, beta, out _bestMove, out int _score))
{
if (!isPV && ply != 0)
{
return _score;
}
}
// Move generation and sorting
Move[] children = boardState.GetAllMoves();
if (followPV) EnablePVScoring(ply, children);
SortMoves(ply, children, _bestMove);
// Loop through all moves
int legalMoves = 0;
foreach (Move move in children)
{
// Check if move is legal
if (move == Move.Empty) break;
if (!boardState.MakeMove(move)) continue;
legalMoves++;
// PVS search
if (foundPV)
{
score = -Negamax(depth - 1, ply + 1, -alpha - 1, -alpha, true);
if ((score > alpha) && (score < beta))
{
score = -Negamax(depth - 1, ply + 1, -beta, -alpha, true);
}
}
else
{
score = -Negamax(depth - 1, ply + 1, -beta, -alpha, true);
}
// Unmake the move
boardState.UnmakeMove(move);
if (score > alpha)
{
// Update variables
foundPV = true;
alpha = score;
_bestMove = move;
// Store history moves
if (!MoveFunctions.IsCapture(move.flag))
{
historyMoves[move.pieceMoved][move.toSquare] += depth;
}
// ----- Save PV ----------------------------------------------
// Write PV move to PV table for the given ply
pvTable[ply][ply] = move;
// Loop over the next ply and update PV table accordingly
for (int j = 0; j < pvLength[ply + 1]; j++)
{
// Copy move from deeper ply into current ply's line
pvTable[ply][ply + 1 + j] = pvTable[ply + 1][ply + 1 + j];
}
// Adjust PV lenght
pvLength[ply] = 1 + pvLength[ply + 1];
// -------------------------------------------------------------
// Fail hard beta cutoff (node fails high)
if (score >= beta)
{
// Store transposition tabel entry with score = beta
Transpositions.WriteTT(boardState.ZobristKey, depth, ply, alpha, beta, beta, _bestMove);
// Store killer moves
if (!MoveFunctions.IsCapture(move.flag))
{
killerMoves[1][ply] = killerMoves[0][ply];
killerMoves[0][ply] = move;
}
return beta;
}
}
}
// Check if we had any legal moves
if (legalMoves == 0)
{
if (isInCheck)
{
return -SearchConstants.mateValue + ply;
}
else
{
return 0;
}
}
// Write to transposition table wih score = alpha
Transpositions.WriteTT(boardState.ZobristKey, depth, ply, alpha, beta, alpha, _bestMove);
// Node fails low
return alpha;
}
