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