Rev 108 | Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
33 | pmbaty | 1 | #include "chess.h" |
2 | #include "data.h" |
||
3 | /* last modified 02/23/14 */ |
||
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 move* |
||
16 | * entered. (3) A command is entered. If it is a simple command, it can be * |
||
17 | * done without aborting the search or losing time. If not, we abort the * |
||
18 | * search, execute the command, and then attempt to restart pondering if the * |
||
19 | * command didn't make that impossible. * |
||
20 | * * |
||
21 | ******************************************************************************* |
||
22 | */ |
||
23 | int Ponder(int wtm) { |
||
24 | int dalpha = -999999, dbeta = 999999, i, *n_ponder_moves, *mv; |
||
25 | int save_move_number, tlom, value; |
||
26 | TREE *const tree = block[0]; |
||
27 | |||
28 | /* |
||
29 | ************************************************************ |
||
30 | * * |
||
31 | * First, let's check to see if pondering is allowed, or * |
||
32 | * if we should avoid pondering on this move since it is * |
||
33 | * the first move of a game, or if the game is over, or * |
||
34 | * "force" mode is active, or there is input in the queue * |
||
35 | * that needs to be read and processed. * |
||
36 | * * |
||
37 | ************************************************************ |
||
38 | */ |
||
39 | if (!ponder || force || over || CheckInput()) |
||
40 | return 0; |
||
41 | save_move_number = move_number; |
||
42 | /* |
||
43 | ************************************************************ |
||
44 | * * |
||
45 | * Check the ponder move for legality. If it is not a * |
||
46 | * legal move, we have to take action to find something to * |
||
47 | * ponder. * |
||
48 | * * |
||
49 | ************************************************************ |
||
50 | */ |
||
51 | strcpy_s(hint, sizeof (hint), "none"); // Pierre-Marie Baty -- use safe version |
||
52 | if (ponder_move) { |
||
53 | if (!VerifyMove(tree, 1, wtm, ponder_move)) { |
||
54 | ponder_move = 0; |
||
55 | Print(4095, "ERROR. ponder_move is illegal (1).\n"); |
||
56 | Print(4095, "ERROR. PV pathl=%d\n", last_pv.pathl); |
||
57 | Print(4095, "ERROR. move=%d %x\n", ponder_move, ponder_move); |
||
58 | } |
||
59 | } |
||
60 | /* |
||
61 | ************************************************************ |
||
62 | * * |
||
63 | * First attempt, do a hash probe. However, since a hash * |
||
64 | * collision is remotely possible, we still need to verify * |
||
65 | * that the transposition/refutation best move is actually * |
||
66 | * legal. * |
||
67 | * * |
||
68 | ************************************************************ |
||
69 | */ |
||
70 | if (!ponder_move) { |
||
71 | (void) HashProbe(tree, 0, 0, wtm, dalpha, dbeta, &value); |
||
72 | if (tree->hash_move[0]) |
||
73 | ponder_move = tree->hash_move[0]; |
||
74 | if (ponder_move) { |
||
75 | if (!VerifyMove(tree, 1, wtm, ponder_move)) { |
||
76 | Print(4095, "ERROR. ponder_move is illegal (2).\n"); |
||
77 | Print(4095, "ERROR. move=%d %x\n", ponder_move, ponder_move); |
||
78 | ponder_move = 0; |
||
79 | } |
||
80 | } |
||
81 | } |
||
82 | /* |
||
83 | ************************************************************ |
||
84 | * * |
||
85 | * Second attempt. If that didn't work, then we try what * |
||
86 | * I call a "puzzling" search. Which is simply a shorter * |
||
87 | * time-limit search for the other side, to find something * |
||
88 | * to ponder. * |
||
89 | * * |
||
90 | ************************************************************ |
||
91 | */ |
||
92 | if (!ponder_move) { |
||
93 | TimeSet(puzzle); |
||
94 | if (time_limit < 20) |
||
95 | return 0; |
||
96 | puzzling = 1; |
||
97 | tree->status[1] = tree->status[0]; |
||
98 | Print(128, " 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 | (void) 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(128, "White(%d): %s [pondering]\n", move_number, OutputMove(tree, |
||
135 | ponder_move, 0, wtm)); |
||
136 | else |
||
137 | Print(128, "Black(%d): %s [pondering]\n", move_number, OutputMove(tree, |
||
138 | ponder_move, 0, wtm)); |
||
139 | sprintf_s(hint, sizeof (hint), "%s", OutputMove(tree, ponder_move, 0, wtm)); // Pierre-Marie Baty -- use safe version |
||
140 | if (post) |
||
141 | printf("Hint: %s\n", hint); |
||
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, *mv, wtm); |
||
157 | if (Check(wtm)) { |
||
158 | UnmakeMove(tree, 0, *mv, wtm); |
||
159 | *mv = 0; |
||
160 | } else |
||
161 | UnmakeMove(tree, 0, *mv, wtm); |
||
162 | } |
||
163 | /* |
||
164 | ************************************************************ |
||
165 | * * |
||
166 | * Now, perform an iterated search, but with the special * |
||
167 | * "pondering" flag set which changes the time controls * |
||
168 | * since there is no need to stop searching until the * |
||
169 | * opponent makes a move. * |
||
170 | * * |
||
171 | ************************************************************ |
||
172 | */ |
||
173 | MakeMove(tree, 0, ponder_move, wtm); |
||
174 | tree->rep_list[++(tree->rep_index)] = HashKey; |
||
175 | tlom = last_opponent_move; |
||
176 | last_opponent_move = ponder_move; |
||
177 | if (kibitz) |
||
178 | strcpy_s(kibitz_text, sizeof (kibitz_text), "n/a"); // Pierre-Marie Baty -- use safe version |
||
179 | thinking = 0; |
||
180 | pondering = 1; |
||
181 | if (!wtm) |
||
182 | move_number++; |
||
183 | ponder_value = Iterate(Flip(wtm), think, 0); |
||
184 | tree->rep_index--; |
||
185 | move_number = save_move_number; |
||
186 | pondering = 0; |
||
187 | thinking = 0; |
||
188 | last_opponent_move = tlom; |
||
189 | UnmakeMove(tree, 0, ponder_move, wtm); |
||
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 * |
||
208 | * a 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 | } |