Rev 108 | Details | Compare with Previous | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 33 | pmbaty | 1 | #include "chess.h" |
| 2 | #include "data.h" |
||
| 154 | pmbaty | 3 | /* last modified 08/03/16 */ |
| 33 | pmbaty | 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 * |
||
| 108 | pmbaty | 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. * |
||
| 33 | pmbaty | 20 | * * |
| 21 | ******************************************************************************* |
||
| 22 | */ |
||
| 23 | int Ponder(int wtm) { |
||
| 108 | pmbaty | 24 | TREE *const tree = block[0]; |
| 25 | int dalpha = -999999, dbeta = 999999, i; |
||
| 26 | unsigned *n_ponder_moves, *mv; |
||
| 154 | pmbaty | 27 | int save_move_number, tlom, value, illegal = 0; |
| 33 | pmbaty | 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 | */ |
||
| 108 | pmbaty | 52 | strcpy(ponder_text, "none"); |
| 33 | pmbaty | 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) { |
||
| 108 | pmbaty | 72 | HashProbe(tree, 0, 0, wtm, dalpha, dbeta, &value); |
| 33 | pmbaty | 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; |
||
| 108 | pmbaty | 98 | Print(32, " puzzling over a move to ponder.\n"); |
| 33 | pmbaty | 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 | } |
||
| 108 | pmbaty | 105 | Iterate(wtm, puzzle, 0); |
| 33 | pmbaty | 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) |
||
| 108 | pmbaty | 134 | Print(32, "White(%d): %s [pondering]\n", move_number, OutputMove(tree, 0, |
| 135 | wtm, ponder_move)); |
||
| 33 | pmbaty | 136 | else |
| 108 | pmbaty | 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)); |
||
| 33 | pmbaty | 140 | if (post) |
| 108 | pmbaty | 141 | printf("Hint: %s\n", ponder_text); |
| 33 | pmbaty | 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++) { |
||
| 108 | pmbaty | 156 | MakeMove(tree, 0, wtm, *mv); |
| 154 | pmbaty | 157 | illegal = Check(wtm); |
| 158 | UnmakeMove(tree, 0, wtm, *mv); |
||
| 159 | if (illegal) |
||
| 33 | pmbaty | 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 | */ |
||
| 108 | pmbaty | 172 | MakeMove(tree, 0, wtm, ponder_move); |
| 173 | tree->curmv[0] = ponder_move; |
||
| 174 | tree->rep_list[++rep_index] = HashKey; |
||
| 33 | pmbaty | 175 | tlom = last_opponent_move; |
| 176 | last_opponent_move = ponder_move; |
||
| 177 | if (kibitz) |
||
| 108 | pmbaty | 178 | strcpy(kibitz_text, "n/a"); |
| 33 | pmbaty | 179 | thinking = 0; |
| 180 | pondering = 1; |
||
| 181 | if (!wtm) |
||
| 182 | move_number++; |
||
| 183 | ponder_value = Iterate(Flip(wtm), think, 0); |
||
| 108 | pmbaty | 184 | rep_index--; |
| 33 | pmbaty | 185 | move_number = save_move_number; |
| 186 | pondering = 0; |
||
| 187 | thinking = 0; |
||
| 188 | last_opponent_move = tlom; |
||
| 108 | pmbaty | 189 | UnmakeMove(tree, 0, wtm, ponder_move); |
| 33 | pmbaty | 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 | * * |
||
| 108 | pmbaty | 207 | * (3) Pondering was done, but the opponent either made a * |
| 208 | * different move, or entered a command that has to * |
||
| 33 | pmbaty | 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 | } |