#include "chess.h"
#include "data.h"
#include "epdglue.h"
/* last modified 01/17/09 */
/*
*******************************************************************************
* *
* RootMoveList() is used to set up the ply one move list. It is a more *
* accurate ordering of the move list than that done for plies deeper than *
* one. Briefly, Quiesce() is used to obtain the positional score plus the *
* expected gain/loss for pieces that can be captured. *
* *
*******************************************************************************
*/
void RootMoveList(int wtm) {
int *mvp, *lastm, rmoves[256], sort_value[256];
int i, done, temp, value;
TREE *const tree = block[0];
#if !defined(NOEGTB)
int mating_via_tb = 0, tb_value;
#endif
/*
************************************************************
* *
* If the position at the root is a draw, based on EGTB *
* results, we are going to behave differently. We will *
* extract the root moves that are draws, and toss the *
* losers out. Then, we will do a normal search on the *
* moves that draw to try and chose the drawing move that *
* gives our opponent the best chance to make an error. *
* This search will be done sans EGTB probes since we al- *
* ready know this is a draw at the root. We simply find *
* the best move (based on search/eval) that preserves the *
* draw. *
* *
************************************************************
*/
#if !defined(NOEGTB)
EGTB_draw = 0;
if (EGTBlimit && TotalAllPieces <= EGTBlimit &&
Castle(1, white) + Castle(1, black) == 0 &&
EGTBProbe(tree, 1, wtm, &tb_value)) {
if (swindle_mode && (tb_value == DrawScore(wtm)))
if ((wtm && Material > 0) || (!wtm && Material < 0))
EGTB_draw = 1;
if (tb_value > 32000)
mating_via_tb = -tb_value - 1;
}
#endif
/*
************************************************************
* *
* First, use GenerateMoves() to generate the set of legal *
* moves from the root position. *
* *
************************************************************
*/
lastm = GenerateCaptures(tree, 1, wtm, rmoves);
lastm = GenerateNoncaptures(tree, 1, wtm, lastm);
n_root_moves = lastm - rmoves;
/*
************************************************************
* *
* Now make each move and use Quiesce() to analyze the *
* potential captures and return a minimax score. *
* *
* Special case: if this is an egtb draw at the root, *
* then this is where we cull the non-drawing moves by *
* doing an EGTB probe for each move. Any moves that lose *
* are left with a very bad sorting score to move them to *
* the end of the root move list. *
* *
************************************************************
*/
for (mvp = rmoves; mvp < lastm; mvp++) {
value = -4000000;
#if defined(TRACE)
if (trace_level >= 1) {
tree->curmv[1] = *mvp;
tree->phase[1] = HASH_MOVE;
Trace(tree, 1, 0, wtm, -MATE, MATE, "RootMoves()", tree->phase[1]);
}
#endif
MakeMove(tree, 1, *mvp, wtm);
tree->nodes_searched++;
if (!Check(wtm))
do {
tree->curmv[1] = *mvp;
#if !defined(NOEGTB)
if (TotalAllPieces <= EGTBlimit && EGTB_draw &&
Castle(1, white) + Castle(1, black) == 0) {
i = EGTBProbe(tree, 2, Flip(wtm), &tb_value);
if (i && tb_value != DrawScore(Flip(wtm)))
break;
}
if (mating_via_tb && TotalAllPieces <= EGTBlimit &&
Castle(1, white) + Castle(1, black) == 0) {
i = EGTBProbe(tree, 2, Flip(wtm), &tb_value);
if (i && ((mating_via_tb > DrawScore(Flip(wtm))
&& tb_value < mating_via_tb)
|| (mating_via_tb < DrawScore(Flip(wtm))
&& tb_value > mating_via_tb)))
break;
}
#endif
value = -Quiesce(tree, -MATE, MATE, Flip(wtm), 2, 0);
/*
************************************************************
* *
* Add in a bonus if this move is part of the previous *
* principal variation. It was good in the search, we *
* should try it first now. *
* *
************************************************************
*/
if ((Piece(*mvp) == Piece(last_pv.path[1]))
&& (From(*mvp) == From(last_pv.path[1]))
&& (To(*mvp) == To(last_pv.path[1]))
&& (Captured(*mvp) == Captured(last_pv.path[1]))
&& (Promote(*mvp) == Promote(last_pv.path[1])))
value += 2000000;
/*
************************************************************
* *
* Fudge the score for promotions so that promotion to a *
* queen is tried first. *
* *
************************************************************
*/
if (Promote(*mvp) && (Promote(*mvp) != queen))
value -= 50;
} while (0);
sort_value[mvp - rmoves] = value;
UnmakeMove(tree, 1, *mvp, wtm);
}
/*
************************************************************
* *
* Sort the moves into order based on the scores returned *
* by Quiesce() which includes evaluation + captures. *
* *
************************************************************
*/
do {
done = 1;
for (i = 0; i < lastm - rmoves - 1; i++) {
if (sort_value[i] < sort_value[i + 1]) {
temp = sort_value[i];
sort_value[i] = sort_value[i + 1];
sort_value[i + 1] = temp;
temp = rmoves[i];
rmoves[i] = rmoves[i + 1];
rmoves[i + 1] = temp;
done = 0;
}
}
} while (!done);
/*
************************************************************
* *
* Trim the move list to eliminate those moves that hang *
* the king and are illegal. This also culls any non- *
* drawing moves when we are in the swindle-mode situation *
* and want to do a normal search but only on moves that *
* preserve the draw. *
* *
************************************************************
*/
for (; n_root_moves; n_root_moves--)
if (sort_value[n_root_moves - 1] > -3000000)
break;
if (sort_value[0] > 1000000)
sort_value[0] -= 2000000;
/*
************************************************************
* *
* Debugging output to dump root move list and the stuff *
* used to sort them, for testing and debugging. *
* *
************************************************************
*/
if (display_options & 512) {
Print(512, "%d moves at root\n", n_root_moves);
Print(512, " move score\n");
for (i = 0; i < n_root_moves; i++) {
tree->curmv[1] = rmoves[i];
Print(512, "%12s", OutputMove(tree, rmoves[i], 1, wtm));
Print(512, "%8d\n", sort_value[i]);
}
}
/*
************************************************************
* *
* Check to see if we are in the special mode where moves *
* need to be searched because of missing EGTBs. This is *
* sorto fo a hack that handles the case where we have an *
* EGTB file like KRPKR, but we don't have the files for *
* promotions for the pawn. The program would avoid any *
* pawn promotion since it likely could not see the mate, *
* because the EGTB position does have a mate score. In *
* this case, we turn EGTBs off for this search so that we *
* can see a reason to promote the pawn and make progress *
* rather than just sitting on our pawn advantage. *
* *
************************************************************
*/
#if !defined(NOEGTB)
if (mating_via_tb) {
for (i = 0; i < n_root_moves; i++) {
tree->curmv[1] = rmoves[i];
MakeMove(tree, 1, rmoves[i], wtm);
if (mating_via_tb && TotalAllPieces <= EGTBlimit &&
Castle(1, white) + Castle(1, black) == 0)
temp =
(EGTBProbe(tree, 2, Flip(wtm),
&tb_value) != DrawScore(Flip(wtm)));
else
temp = 0;
UnmakeMove(tree, 1, rmoves[i], wtm);
if (temp)
break;
}
EGTB_search = (i == n_root_moves);
} else
EGTB_search = 0;
#endif
/*
************************************************************
* *
* Copy the root moves into the root_move structure array *
* for use by NextRootMove(). *
* *
************************************************************
*/
for (i = 0; i < n_root_moves; i++) {
root_moves[i].move = rmoves[i];
root_moves[i].status = 4;
root_moves[i].bm_age = 0;
}
root_moves[0].status = 0;
return;
}