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;
        }           
      
 I know I can check if I have a has move and then test it, but how to know if that caused a cut and that I don't need to generate captures etc? Do I need to rebuild my "standard" negamax layout for this?
 I know I can check if I have a has move and then test it, but how to know if that caused a cut and that I don't need to generate captures etc? Do I need to rebuild my "standard" negamax layout for this?

