1 #include "chess.h"
2 #include "data.h"
3 /* last modified 08/03/16 */
4 /*
5  *******************************************************************************
6  *                                                                             *
7  *   Ponder() is the driver for "pondering" (thinking on the opponent's time.) *
8  *   its operation is simple:  Find a predicted move by (a) taking the second  *
9  *   move from the principal variation, or (b) call lookup to see if it finds  *
10  *   a suggested move from the transposition table.  Then, make this move and  *
11  *   do a search from the resulting position.  While pondering, one of three   *
12  *   things can happen:  (1) A move is entered, and it matches the predicted   *
13  *   move.  We then switch from pondering to thinking and search as normal;    *
14  *   (2) A move is entered, but it does not match the predicted move.  We then *
15  *   abort the search, unmake the pondered move, and then restart with the     *
16  *   move entered.  (3) A command is entered.  If it is a simple command, it   *
17  *   can be done without aborting the search or losing time.  If not, we abort *
18  *   the search, execute the command, and then attempt to restart pondering if *
19  *   the command didn't make that impossible.                                  *
20  *                                                                             *
21  *******************************************************************************
22  */
Ponder(int wtm)23 int Ponder(int wtm) {
24   TREE *const tree = block[0];
25   int dalpha = -999999, dbeta = 999999, i;
26   unsigned *n_ponder_moves, *mv;
27   int save_move_number, tlom, value, illegal = 0;
28 
29 /*
30  ************************************************************
31  *                                                          *
32  *  First, let's check to see if pondering is allowed, or   *
33  *  if we should avoid pondering on this move since it is   *
34  *  the first move of a game, or if the game is over, or    *
35  *  "force" mode is active, or there is input in the queue  *
36  *  that needs to be read and processed.                    *
37  *                                                          *
38  ************************************************************
39  */
40   if (!ponder || force || over || CheckInput())
41     return 0;
42   save_move_number = move_number;
43 /*
44  ************************************************************
45  *                                                          *
46  *  Check the ponder move for legality.  If it is not a     *
47  *  legal move, we have to take action to find something to *
48  *  ponder.                                                 *
49  *                                                          *
50  ************************************************************
51  */
52   strcpy(ponder_text, "none");
53   if (ponder_move) {
54     if (!VerifyMove(tree, 1, wtm, ponder_move)) {
55       ponder_move = 0;
56       Print(4095, "ERROR.  ponder_move is illegal (1).\n");
57       Print(4095, "ERROR.  PV pathl=%d\n", last_pv.pathl);
58       Print(4095, "ERROR.  move=%d  %x\n", ponder_move, ponder_move);
59     }
60   }
61 /*
62  ************************************************************
63  *                                                          *
64  *  First attempt, do a hash probe.  However, since a hash  *
65  *  collision is remotely possible, we still need to verify *
66  *  that the transposition/refutation best move is actually *
67  *  legal.                                                  *
68  *                                                          *
69  ************************************************************
70  */
71   if (!ponder_move) {
72     HashProbe(tree, 0, 0, wtm, dalpha, dbeta, &value);
73     if (tree->hash_move[0])
74       ponder_move = tree->hash_move[0];
75     if (ponder_move) {
76       if (!VerifyMove(tree, 1, wtm, ponder_move)) {
77         Print(4095, "ERROR.  ponder_move is illegal (2).\n");
78         Print(4095, "ERROR.  move=%d  %x\n", ponder_move, ponder_move);
79         ponder_move = 0;
80       }
81     }
82   }
83 /*
84  ************************************************************
85  *                                                          *
86  *  Second attempt.  If that didn't work, then we try what  *
87  *  I call a "puzzling" search.  Which is simply a shorter  *
88  *  time-limit search for the other side, to find something *
89  *  to ponder.                                              *
90  *                                                          *
91  ************************************************************
92  */
93   if (!ponder_move) {
94     TimeSet(puzzle);
95     if (time_limit < 20)
96       return 0;
97     puzzling = 1;
98     Print(32, "              puzzling over a move to ponder.\n");
99     last_pv.pathl = 0;
100     last_pv.pathd = 0;
101     for (i = 0; i < MAXPLY; i++) {
102       tree->killers[i].move1 = 0;
103       tree->killers[i].move2 = 0;
104     }
105     Iterate(wtm, puzzle, 0);
106     for (i = 0; i < MAXPLY; i++) {
107       tree->killers[i].move1 = 0;
108       tree->killers[i].move2 = 0;
109     }
110     puzzling = 0;
111     if (tree->pv[0].pathl)
112       ponder_move = tree->pv[0].path[1];
113     if (!ponder_move)
114       return 0;
115     for (i = 1; i < (int) tree->pv[0].pathl; i++)
116       last_pv.path[i] = tree->pv[0].path[i + 1];
117     last_pv.pathl = tree->pv[0].pathl - 1;
118     last_pv.pathd = 0;
119     if (!VerifyMove(tree, 1, wtm, ponder_move)) {
120       ponder_move = 0;
121       Print(4095, "ERROR.  ponder_move is illegal (3).\n");
122       Print(4095, "ERROR.  PV pathl=%d\n", last_pv.pathl);
123       return 0;
124     }
125   }
126 /*
127  ************************************************************
128  *                                                          *
129  *  Display the move we are going to "ponder".              *
130  *                                                          *
131  ************************************************************
132  */
133   if (wtm)
134     Print(32, "White(%d): %s [pondering]\n", move_number, OutputMove(tree, 0,
135             wtm, ponder_move));
136   else
137     Print(32, "Black(%d): %s [pondering]\n", move_number, OutputMove(tree, 0,
138             wtm, ponder_move));
139   sprintf(ponder_text, "%s", OutputMove(tree, 0, wtm, ponder_move));
140   if (post)
141     printf("Hint: %s\n", ponder_text);
142 /*
143  ************************************************************
144  *                                                          *
145  *  Set the ponder move list and eliminate illegal moves.   *
146  *  This list is used to test the move entered while we are *
147  *  pondering, since we need a move list for the input      *
148  *  screening process.                                      *
149  *                                                          *
150  ************************************************************
151  */
152   n_ponder_moves = GenerateCaptures(tree, 0, wtm, ponder_moves);
153   num_ponder_moves =
154       GenerateNoncaptures(tree, 0, wtm, n_ponder_moves) - ponder_moves;
155   for (mv = ponder_moves; mv < ponder_moves + num_ponder_moves; mv++) {
156     MakeMove(tree, 0, wtm, *mv);
157     illegal = Check(wtm);
158     UnmakeMove(tree, 0, wtm, *mv);
159     if (illegal)
160       *mv = 0;
161   }
162 /*
163  ************************************************************
164  *                                                          *
165  *  Now, perform an iterated search, but with the special   *
166  *  "pondering" flag set which changes the time controls    *
167  *  since there is no need to stop searching until the      *
168  *  opponent makes a move.                                  *
169  *                                                          *
170  ************************************************************
171  */
172   MakeMove(tree, 0, wtm, ponder_move);
173   tree->curmv[0] = ponder_move;
174   tree->rep_list[++rep_index] = HashKey;
175   tlom = last_opponent_move;
176   last_opponent_move = ponder_move;
177   if (kibitz)
178     strcpy(kibitz_text, "n/a");
179   thinking = 0;
180   pondering = 1;
181   if (!wtm)
182     move_number++;
183   ponder_value = Iterate(Flip(wtm), think, 0);
184   rep_index--;
185   move_number = save_move_number;
186   pondering = 0;
187   thinking = 0;
188   last_opponent_move = tlom;
189   UnmakeMove(tree, 0, wtm, ponder_move);
190 /*
191  ************************************************************
192  *                                                          *
193  *  Search completed. the possible return values are:       *
194  *                                                          *
195  *  (0) No pondering was done, period.                      *
196  *                                                          *
197  *  (1) Pondering was done, opponent made the predicted     *
198  *      move, and we searched until time ran out in a       *
199  *      normal manner.                                      *
200  *                                                          *
201  *  (2) Pondering was done, but the ponder search           *
202  *      terminated due to either finding a mate, or the     *
203  *      maximum search depth was reached.  The result of    *
204  *      this ponder search are valid, but only if the       *
205  *      opponent makes the correct (predicted) move.        *
206  *                                                          *
207  *  (3) Pondering was done, but the opponent either made a  *
208  *      different move, or entered a command that has to    *
209  *      interrupt the pondering search before the command   *
210  *      (or move) can be processed.  This forces Main() to  *
211  *      avoid reading in a move/command since one has been  *
212  *      read into the command buffer already.               *
213  *                                                          *
214  ************************************************************
215  */
216   if (input_status == 1)
217     return 1;
218   if (input_status == 2)
219     return 3;
220   return 2;
221 }
222