 Create a piece-type | square history table.

static int H [ 12 ] [ 64 ];              // declare history table H [piece] [destination square]

Table is cleared at the start of the search.

During search the history table H is updated for each move as follows:

if (ply <= 8 && move_is_no_capture)

{ if (move produces a better score) H[piece][square] += depth*depth;

else H[piece][square] -= depth;

if (abs(H[piece][square]) >= 2000) H[piece][square] /= 2; }

And so the values will always be in the range of -2000 | +2000.

Then LMR becomes really simple.

void lmr()

{       if (depth < 3) return;             // no LMR in the last 3 plies before the horizon

if (move_count <= 3) return;  // no LMR for the first 3 moves

if (TT move) return;               // no LMR when TT move

if (capture) return;

if (queen promotion) return;

if (king_in_check) return;

if (move_gives_check) return;

if (white_pawn_moves_to_sixth_row_or_beyond) return;

if (black_pawn_moves_to_third_row_or_beyond) return;

reduction();                                            // reduce the search by one ply.

if (we_are_at_the_root) return;                 // we reduce root moves only once.

conditions for double and triple LMR

value = H [piece] [square];

if (value < -500) reduction();                     // reduce double

if (value < -1500) reduction();                    // reduce triple

}

Note: This simple approach should be good for some 30-50 elo.

As one can see from the code the history table is only updated for the first 8 plies because research from the past (somewhere in the 90's) learned me that using higher values the level of noise rapidly contaminates the values in the table.

__________________________________________________________________________________________________

LMR

There a practically a zillion of possibilities to improve on the above simple system and I will describe those additions to the above I am currently working on and things rapidly become complicated in the sense of finding the right combinations as most of the below instructions (marked with a *) are controlled by an on or off option.

void lmr()

{       if (depth < 3) return;             // no LMR in the last 3 plies before the horizon

//      Root moves:

//      we maintain a list with the best moves during search. From iteration 8 and on moves that have been best

//      are never reduced.

if (TT move) return;               // no LMR when TT move

if (king_in_check) return;

if (queen promotion) return;

if (white_pawn_moves_to_sixth_row_or_beyond) return;

if (black_pawn_moves_to_third_row_or_beyond) return;

if (good capture) return;                               // SEE >=0

*     if (bad capture) { reduce one ply; return; }     // SEE <0

if (move_gives_check && good) return;

*      if (move_gives_check && bad) { reduce one ply; return; }

//      Evaluate R (the number of reductions)

//      Step-1: get the initial R from a table [depth] [movecount], view, copy&paste the table from here.

a=depth; b=movecount; if (b>63) b=63;

R=lmr_tab[a][b];

//      Step-2: get the value of the history table and based on the value modify R

value = H [piece] [square];

*      if (value > 0) R--;                              // reduce less if the history move is positive

*      if (value > 500) R--;                           // reduce less

*      if (value > 1000) R--;                         // reduce less

*      if (value > 1500) R--;                         // reduce less

*      if (value < 0) R++;                            // reduce more if the history move is bad

*      if (value < -500) R++;                        // reduce more

*      if (value < -1000) R++;                      // reduce more

*      if (value < -1500) R++;                      // reduce more

//     Step-3: reduce less if the evaluation score of the position - a (small) margin is (still) better than ALPHA.

*      if (evaluation score > ALPHA+margin) R--;

//     Step-4: reduce less if the evaluation score - the board material is greater than a margin, currently set to 0.50.

//                The idea is that if the color to move has a positional advantage of half a pawn then maybe it's not a

//                good idea to reduce the move too much despite the material on the board.

*      if (evaluation score - board_material > margin) R--;

//      Step-5: reduce less if the current move itself creates a new threat such as h3 attacking the black knight on

//                 G4 with the white pawn.  Attacking pawns don't count, only major pieces (N,B,R,Q). The move itself

//                 should not be bad (SEE<0)

*      if (new_attacking_move) R--;

//      Step-6: reduce less if the move escapes from a threat such as the example in step-5. Subtracting moves

//                  like Nf6 or moves that simply eliminate the threat on G4 should not be reduced too much. Pawns

//                  don't count, only major pieces (N,B,R,Q). The move itself should not be bad (SEE<0)

*        if (hanging piece resolved) R--;

//       Step-7: reduce less if the passed pawn evaluation has increased with a considerable margin in comparison

//                  to the previous ply, currently set to 0.25.

*        if (passed_pawn_eval [current ply] - passed_pawn_eval [previous ply] >= margin) R--;

//       Step-8: Do the same for King Safety, reduce less if the KS evaluation has increased with a considerable margin

//                  in comparison to the previous ply, currently set to 0.25.

*        if (KS_eval [current ply] - KS_eval [previous ply] >= margin) R--;

//      Step-9: reduce less if the overall evaluation (thus evaluation score - board material) has increased with a

//                  considerable margin in comparison to the previous ply, currently set to 0.50. Note the correlation

//                  with step 7 and 8.

*        if (evaluation score [current ply] - evauation scorel [previous ply] >= margin) R--;

//       Step-10: reduce more if the overall evaluation has decreased with a considerable margin in comparison to

//                    the previous ply, currently set to 0.50. Note the reverse correlation with step-9.

*        if (evaluation score [previos ply] - evauation scorel [current ply] >= margin) R++;

//       Step-11: reduce less if the current move is a killer move.

*        if (move = killer_one || killer_two)  R--;

//       Step-12: reduce less if move has an excellent PST score.

*        if (PST [piece_type] [to] - PST [piece_type] [from] >= margin) R--;

//       We finally are there for the last step to calculate the final number of reductions for this move. We apply a

//       percentage (P) for R currently set to 50% which makes R flexible.

P=50;

if (R>0) { printf("Reduce this move with %d plies", (R*P)/100);

That's it.

And a lot to test.

Notes:

The system can be improved by applying priorities for each of the 12 ingredients (steps). Instead of using R-- or R++ one can use R+=10 or R-=6 based on a multiply factor of 10 and then in the final calculation use (R*P)/1000);

The if (R>0) is actually needed else if R would end up negative the move will be extended instead of reduced. It would be fun to try that anyway.

__________________________________________________________________________________________________

LMR

expert

Mail me your LMR pseudo code and I will create a separate page for it.

or use the contact form to contact me.

LMR for starters

pseudo code