@@ -109,6 +109,7 @@ namespace {
109109 void update_pv (Move* pv, Move move, Move* childPv);
110110 void update_continuation_histories (Stack* ss, Piece pc, Square to, int bonus);
111111 void update_stats (const Position& pos, Stack* ss, Move move, Move* quiets, int quietsCnt, int bonus);
112+ void update_capture_stats (const Position& pos, Move move, Move* captures, int captureCnt, int bonus);
112113 bool pv_is_draw (Position& pos);
113114
114115 // perft() is our utility to verify move generation. All the leaf nodes up
@@ -500,7 +501,7 @@ namespace {
500501 assert (!(PvNode && cutNode));
501502 assert (depth / ONE_PLY * ONE_PLY == depth);
502503
503- Move pv[MAX_PLY+1 ], quietsSearched[64 ];
504+ Move pv[MAX_PLY+1 ], capturesSearched[ 32 ], quietsSearched[64 ];
504505 StateInfo st;
505506 TTEntry* tte;
506507 Key posKey;
@@ -510,12 +511,12 @@ namespace {
510511 bool ttHit, inCheck, givesCheck, singularExtensionNode, improving;
511512 bool captureOrPromotion, doFullDepthSearch, moveCountPruning, skipQuiets, ttCapture, pvExact;
512513 Piece movedPiece;
513- int moveCount, quietCount;
514+ int moveCount, captureCount, quietCount;
514515
515516 // Step 1. Initialize node
516517 Thread* thisThread = pos.this_thread ();
517518 inCheck = pos.checkers ();
518- moveCount = quietCount = ss->moveCount = 0 ;
519+ moveCount = captureCount = quietCount = ss->moveCount = 0 ;
519520 ss->statScore = 0 ;
520521 bestValue = -VALUE_INFINITE;
521522
@@ -579,6 +580,8 @@ namespace {
579580 {
580581 if (!pos.capture_or_promotion (ttMove))
581582 update_stats (pos, ss, ttMove, nullptr , 0 , stat_bonus (depth));
583+ else
584+ update_capture_stats (pos, ttMove, nullptr , 0 , stat_bonus (depth));
582585
583586 // Extra penalty for a quiet TT move in previous ply when it gets refuted
584587 if ((ss-1 )->moveCount == 1 && !pos.captured_piece ())
@@ -729,7 +732,7 @@ namespace {
729732
730733 assert (is_ok ((ss-1 )->currentMove ));
731734
732- MovePicker mp (pos, ttMove, rbeta - ss->staticEval );
735+ MovePicker mp (pos, ttMove, rbeta - ss->staticEval , &thisThread-> captureHistory );
733736
734737 while ((move = mp.next_move ()) != MOVE_NONE)
735738 if (pos.legal (move))
@@ -763,7 +766,7 @@ namespace {
763766 const PieceToHistory* contHist[] = { (ss-1 )->contHistory , (ss-2 )->contHistory , nullptr , (ss-4 )->contHistory };
764767 Move countermove = thisThread->counterMoves [pos.piece_on (prevSq)][prevSq];
765768
766- MovePicker mp (pos, ttMove, depth, &thisThread->mainHistory , contHist, countermove, ss->killers );
769+ MovePicker mp (pos, ttMove, depth, &thisThread->mainHistory , &thisThread-> captureHistory , contHist, countermove, ss->killers );
767770 value = bestValue; // Workaround a bogus 'uninitialized' warning under gcc
768771 improving = ss->staticEval >= (ss-2 )->staticEval
769772 /* || ss->staticEval == VALUE_NONE Already implicit in the previous condition */
@@ -1054,6 +1057,8 @@ namespace {
10541057
10551058 if (!captureOrPromotion && move != bestMove && quietCount < 64 )
10561059 quietsSearched[quietCount++] = move;
1060+ else if (captureOrPromotion && move != bestMove && captureCount < 32 )
1061+ capturesSearched[captureCount++] = move;
10571062 }
10581063
10591064 // The following condition would detect a stop only after move loop has been
@@ -1079,6 +1084,8 @@ namespace {
10791084 // Quiet best move: update move sorting heuristics
10801085 if (!pos.capture_or_promotion (bestMove))
10811086 update_stats (pos, ss, bestMove, quietsSearched, quietCount, stat_bonus (depth));
1087+ else
1088+ update_capture_stats (pos, bestMove, capturesSearched, captureCount, stat_bonus (depth));
10821089
10831090 // Extra penalty for a quiet TT move in previous ply when it gets refuted
10841091 if ((ss-1 )->moveCount == 1 && !pos.captured_piece ())
@@ -1207,7 +1214,7 @@ namespace {
12071214 // to search the moves. Because the depth is <= 0 here, only captures,
12081215 // queen promotions and checks (only if depth >= DEPTH_QS_CHECKS) will
12091216 // be generated.
1210- MovePicker mp (pos, ttMove, depth, &pos.this_thread ()->mainHistory , to_sq ((ss-1 )->currentMove ));
1217+ MovePicker mp (pos, ttMove, depth, &pos.this_thread ()->mainHistory , &pos. this_thread ()-> captureHistory , to_sq ((ss-1 )->currentMove ));
12111218
12121219 // Loop through the moves until no moves remain or a beta cutoff occurs
12131220 while ((move = mp.next_move ()) != MOVE_NONE)
@@ -1362,6 +1369,26 @@ namespace {
13621369 }
13631370
13641371
1372+ // update_capture_stats() updates move sorting heuristics when a new capture best move is found
1373+
1374+ void update_capture_stats (const Position& pos, Move move,
1375+ Move* captures, int captureCnt, int bonus) {
1376+
1377+ CapturePieceToHistory& captureHistory = pos.this_thread ()->captureHistory ;
1378+ Piece moved_piece = pos.moved_piece (move);
1379+ PieceType captured = type_of (pos.piece_on (to_sq (move)));
1380+ captureHistory.update (moved_piece,to_sq (move), captured, bonus);
1381+
1382+ // Decrease all the other played capture moves
1383+ for (int i = 0 ; i < captureCnt; ++i)
1384+ {
1385+ moved_piece = pos.moved_piece (captures[i]);
1386+ captured = type_of (pos.piece_on (to_sq (captures[i])));
1387+ captureHistory.update (moved_piece, to_sq (captures[i]), captured, -bonus);
1388+ }
1389+ }
1390+
1391+
13651392 // update_stats() updates move sorting heuristics when a new quiet best move is found
13661393
13671394 void update_stats (const Position& pos, Stack* ss, Move move,
0 commit comments