Rev 33 | Rev 154 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
| Rev 33 | Rev 108 | ||
|---|---|---|---|
| Line 1... | Line 1... | ||
| 1 | #include "chess.h" |
1 | #include "chess.h" |
| 2 | #include "data.h" |
2 | #include "data.h" |
| 3 | /* last modified 05/15/14 */ |
- | |
| 4 | /* |
- | |
| 5 | ******************************************************************************* |
- | |
| 6 | * * |
- | |
| 7 | * NextEvasion() is used to select the next move from the current move list * |
- | |
| 8 | * when the king is in check. We use GenerateEvasions() (in movgen.c) to * |
- | |
| 9 | * generate a list of moves that get us out of check. The only unusual * |
- | |
| 10 | * feature is that these moves are all legal and do not need to be vetted * |
- | |
| 11 | * with the usual Check() function to test for legality. * |
- | |
| 12 | * * |
- | |
| 13 | ******************************************************************************* |
- | |
| 14 | */ |
- | |
| 15 | int NextEvasion(TREE * RESTRICT tree, int ply, int wtm) { |
- | |
| 16 | int *movep, *sortv; |
- | |
| 17 | - | ||
| 18 | switch (tree->next_status[ply].phase) { |
- | |
| 19 | /* |
- | |
| 20 | ************************************************************ |
- | |
| 21 | * * |
- | |
| 22 | * First try the transposition table move (which might be * |
- | |
| 23 | * the principal variation move as we first move down the * |
- | |
| 24 | * tree). If it is good enough to cause a cutoff, we * |
- | |
| 25 | * avoided the overhead of generating legal moves. * |
- | |
| 26 | * * |
- | |
| 27 | ************************************************************ |
- | |
| 28 | */ |
- | |
| 29 | case HASH_MOVE: |
- | |
| 30 | if (tree->hash_move[ply]) { |
- | |
| 31 | tree->next_status[ply].phase = GENERATE_ALL_MOVES; |
- | |
| 32 | tree->curmv[ply] = tree->hash_move[ply]; |
- | |
| 33 | if (ValidMove(tree, ply, wtm, tree->curmv[ply])) |
- | |
| 34 | return HASH_MOVE; |
- | |
| 35 | #if defined(DEBUG) |
- | |
| 36 | else |
- | |
| 37 | Print(128, "bad move from hash table, ply=%d\n", ply); |
- | |
| 38 | #endif |
- | |
| 39 | } |
- | |
| 40 | /* |
- | |
| 41 | ************************************************************ |
- | |
| 42 | * * |
- | |
| 43 | * Now generate all legal moves by using the special * |
- | |
| 44 | * GenerateCheckEvasions() procedure. Then sort the moves * |
- | |
| 45 | * based on the expected gain or loss. this is deferred * |
- | |
| 46 | * until now to see if the hash move is good enough to * |
- | |
| 47 | * produce a cutoff and avoid this effort. * |
- | |
| 48 | * * |
- | |
| 49 | * Once we confirm that the move does not lose any * |
- | |
| 50 | * material, we sort these non-losing moves into MVV/LVA * |
- | |
| 51 | * order which appears to be a slightly faster move * |
- | |
| 52 | * ordering idea. Unsafe evasion moves are sorted using * |
- | |
| 53 | * the original Swap() score to keep them last in the move * |
- | |
| 54 | * list. Note that this move list contains both captures * |
- | |
| 55 | * and non-captures. We try the safe captures first due * |
- | |
| 56 | * to the way the sort score is computed. * |
- | |
| 57 | * * |
- | |
| 58 | ************************************************************ |
- | |
| 59 | */ |
- | |
| 60 | case GENERATE_ALL_MOVES: |
- | |
| 61 | tree->last[ply] = |
- | |
| 62 | GenerateCheckEvasions(tree, ply, wtm, tree->last[ply - 1]); |
- | |
| 63 | tree->next_status[ply].phase = REMAINING_MOVES; |
- | |
| 64 | for (movep = tree->last[ply - 1], sortv = tree->sort_value; |
- | |
| 65 | movep < tree->last[ply]; movep++, sortv++) |
- | |
| 66 | if (tree->hash_move[ply] && *movep == tree->hash_move[ply]) { |
- | |
| 67 | *sortv = -999999; |
- | |
| 68 | *movep = 0; |
- | |
| 69 | } else { |
- | |
| 70 | if (pcval[Piece(*movep)] <= pcval[Captured(*movep)]) |
- | |
| 71 | *sortv = 128 * pcval[Captured(*movep)] - pcval[Piece(*movep)]; |
- | |
| 72 | else { |
- | |
| 73 | *sortv = Swap(tree, *movep, wtm); |
- | |
| 74 | if (*sortv >= 0) |
- | |
| 75 | *sortv = 128 * pcval[Captured(*movep)] - pcval[Piece(*movep)]; |
- | |
| 76 | } |
- | |
| 77 | } |
- | |
| 78 | /* |
- | |
| 79 | ************************************************************ |
- | |
| 80 | * * |
- | |
| 81 | * This is a simple insertion sort algorithm. It seems be * |
- | |
| 82 | * be no faster than a normal bubble sort, but using this * |
- | |
| 83 | * eliminated a lot of explaining about "why?". :) * |
- | |
| 84 | * * |
- | |
| 85 | ************************************************************ |
- | |
| 86 | */ |
- | |
| 87 | if (tree->last[ply] > tree->last[ply - 1] + 1) { |
- | |
| 88 | int temp1, temp2, *tmovep, *tsortv, *end; |
- | |
| 89 | - | ||
| 90 | sortv = tree->sort_value + 1; |
- | |
| 91 | end = tree->last[ply]; |
- | |
| 92 | for (movep = tree->last[ply - 1] + 1; movep < end; movep++, sortv++) { |
- | |
| 93 | temp1 = *movep; |
- | |
| 94 | temp2 = *sortv; |
- | |
| 95 | tmovep = movep - 1; |
- | |
| 96 | tsortv = sortv - 1; |
- | |
| 97 | while (tmovep >= tree->last[ply - 1] && *tsortv < temp2) { |
- | |
| 98 | *(tsortv + 1) = *tsortv; |
- | |
| 99 | *(tmovep + 1) = *tmovep; |
- | |
| 100 | tmovep--; |
- | |
| 101 | tsortv--; |
- | |
| 102 | } |
- | |
| 103 | *(tmovep + 1) = temp1; |
- | |
| 104 | *(tsortv + 1) = temp2; |
- | |
| 105 | } |
- | |
| 106 | } |
- | |
| 107 | tree->next_status[ply].last = tree->last[ply - 1]; |
- | |
| 108 | /* |
- | |
| 109 | ************************************************************ |
- | |
| 110 | * * |
- | |
| 111 | * Now try the moves in sorted order. * |
- | |
| 112 | * * |
- | |
| 113 | ************************************************************ |
- | |
| 114 | */ |
- | |
| 115 | case REMAINING_MOVES: |
- | |
| 116 | for (; tree->next_status[ply].last < tree->last[ply]; |
- | |
| 117 | tree->next_status[ply].last++) |
- | |
| 118 | if (*tree->next_status[ply].last) { |
- | |
| 119 | tree->curmv[ply] = *tree->next_status[ply].last++; |
- | |
| 120 | return REMAINING_MOVES; |
- | |
| 121 | } |
- | |
| 122 | return NONE; |
- | |
| 123 | default: |
- | |
| 124 | printf("oops! next_status.phase is bad! [evasion %d]\n", |
- | |
| 125 | tree->next_status[ply].phase); |
- | |
| 126 | } |
- | |
| 127 | return NONE; |
- | |
| 128 | } |
- | |
| 129 | - | ||
| 130 | /* last modified |
3 | /* last modified 12/29/15 */ |
| 131 | /* |
4 | /* |
| 132 | ******************************************************************************* |
5 | ******************************************************************************* |
| 133 | * * |
6 | * * |
| 134 | * NextMove() is used to select the next move from the current move list. * |
7 | * NextMove() is used to select the next move from the current move list. * |
| 135 | * * |
8 | * * |
| Line 138... | Line 11... | ||
| 138 | * save them in the NEXT structure and make sure to exclude them when * |
11 | * save them in the NEXT structure and make sure to exclude them when * |
| 139 | * searching after a move generation to avoid the duplicated effort. * |
12 | * searching after a move generation to avoid the duplicated effort. * |
| 140 | * * |
13 | * * |
| 141 | ******************************************************************************* |
14 | ******************************************************************************* |
| 142 | */ |
15 | */ |
| 143 | int NextMove(TREE * RESTRICT tree, int ply, int |
16 | int NextMove(TREE * RESTRICT tree, int ply, int depth, int side, int in_check) { |
| 144 |
|
17 | unsigned *movep, *bestp; |
| - | 18 | int hist, bestval, possible; |
|
| 145 | 19 | ||
| - | 20 | /* |
|
| - | 21 | ************************************************************ |
|
| - | 22 | * * |
|
| - | 23 | * The following "big switch" controls the finate state * |
|
| - | 24 | * machine that selects moves. The "phase" value in the * |
|
| - | 25 | * next_status[ply] structure is always set after a move * |
|
| - | 26 | * is selected, and it defines the next state of the FSM * |
|
| - | 27 | * so select the next move in a sequenced order. * |
|
| - | 28 | * * |
|
| - | 29 | ************************************************************ |
|
| - | 30 | */ |
|
| 146 | switch (tree->next_status[ply].phase) { |
31 | switch (tree->next_status[ply].phase) { |
| 147 | /* |
32 | /* |
| 148 | ************************************************************ |
33 | ************************************************************ |
| 149 | * * |
34 | * * |
| 150 | * First, try the transposition table move (which will be * |
35 | * First, try the transposition table move (which will be * |
| 151 | * the principal variation move as we first move down the * |
36 | * the principal variation move as we first move down the * |
| - | 37 | * tree) or the best move found in this position during a * |
|
| 152 | * |
38 | * prior search. * |
| 153 | * * |
39 | * * |
| 154 | ************************************************************ |
40 | ************************************************************ |
| 155 | */ |
41 | */ |
| 156 | case |
42 | case HASH: |
| 157 | tree->next_status[ply]. |
43 | tree->next_status[ply].order = 0; |
| - | 44 | tree->next_status[ply].exclude = &tree->next_status[ply].done[0]; |
|
| 158 | tree->next_status[ply].phase = |
45 | tree->next_status[ply].phase = GENERATE_CAPTURES; |
| 159 | if (tree->hash_move[ply]) { |
46 | if (tree->hash_move[ply]) { |
| 160 | tree->curmv[ply] = tree->hash_move[ply]; |
47 | tree->curmv[ply] = tree->hash_move[ply]; |
| 161 | tree->next_status[ply]. |
48 | *(tree->next_status[ply].exclude++) = tree->curmv[ply]; |
| 162 |
|
49 | if (ValidMove(tree, ply, side, tree->curmv[ply])) { |
| 163 |
|
50 | tree->phase[ply] = HASH; |
| 164 |
|
51 | return ++tree->next_status[ply].order; |
| 165 |
|
52 | } |
| 166 | #if defined(DEBUG) |
53 | #if defined(DEBUG) |
| 167 | else |
54 | else |
| 168 | Print( |
55 | Print(2048, "ERROR: bad move from hash table, ply=%d\n", ply); |
| 169 | #endif |
56 | #endif |
| 170 | } |
57 | } |
| 171 | /* |
58 | /* |
| 172 | ************************************************************ |
59 | ************************************************************ |
| 173 | * * |
60 | * * |
| Line 175... | Line 62... | ||
| 175 | * MVV/LVA ordering where we try to capture the most * |
62 | * MVV/LVA ordering where we try to capture the most * |
| 176 | * valuable victim piece possible, using the least * |
63 | * valuable victim piece possible, using the least * |
| 177 | * valuable attacking piece possible. Later we will test * |
64 | * valuable attacking piece possible. Later we will test * |
| 178 | * to see if the capture appears to lose material and we * |
65 | * to see if the capture appears to lose material and we * |
| 179 | * will defer searching it until later. * |
66 | * will defer searching it until later. * |
| - | 67 | * * |
|
| - | 68 | * Or, if in check, generate all the legal moves that * |
|
| - | 69 | * escape check by using GenerateCheckEvasions(). After * |
|
| - | 70 | * we do this, we sort them using MVV/LVA to move captures * |
|
| - | 71 | * to the front of the list in the correct order. * |
|
| 180 | * * |
72 | * * |
| 181 | ************************************************************ |
73 | ************************************************************ |
| 182 | */ |
74 | */ |
| 183 | case |
75 | case GENERATE_CAPTURES: |
| 184 | tree->next_status[ply].phase = |
76 | tree->next_status[ply].phase = CAPTURES; |
| 185 | tree->last[ply] = GenerateCaptures(tree, ply, wtm, tree->last[ply - 1]); |
- | |
| 186 | tree->next_status[ply].remaining = 0; |
- | |
| 187 | for (movep = tree->last[ply - 1], sortv = tree->sort_value; |
- | |
| 188 | movep < tree->last[ply]; movep++, sortv++) |
- | |
| 189 | if (*movep == tree->hash_move[ply]) { |
- | |
| 190 |
|
77 | if (!in_check) |
| 191 |
|
78 | tree->last[ply] = |
| 192 | tree-> |
79 | GenerateCaptures(tree, ply, side, tree->last[ply - 1]); |
| 193 |
|
80 | else |
| 194 |
|
81 | tree->last[ply] = |
| 195 | tree-> |
82 | GenerateCheckEvasions(tree, ply, side, tree->last[ply - 1]); |
| 196 | } |
- | |
| 197 | /* |
83 | /* |
| 198 | ************************************************************ |
84 | ************************************************************ |
| 199 | * * |
85 | * * |
| - | 86 | * Now make a pass over the moves to assign the sort value * |
|
| 200 | * |
87 | * for each. We simply use MVV/LVA move order here. A * |
| 201 | * |
88 | * simple optimization is to use the pre-computed array * |
| - | 89 | * MVV_LVA[victim][attacker] which returns a simple value * |
|
| 202 | * |
90 | * that indicates MVV/LVA order. * |
| 203 | * * |
91 | * * |
| 204 | ************************************************************ |
92 | ************************************************************ |
| 205 | */ |
93 | */ |
| 206 |
|
94 | tree->next_status[ply].remaining = 0; |
| 207 | int temp1, temp2, *tmovep, *tsortv, *end; |
- | |
| 208 | - | ||
| 209 | sortv = tree->sort_value + 1; |
- | |
| 210 | end = tree->last[ply]; |
- | |
| 211 |
|
95 | for (movep = tree->last[ply - 1]; movep < tree->last[ply]; movep++) |
| 212 |
|
96 | if (*movep == tree->hash_move[ply]) { |
| 213 | temp2 = *sortv; |
- | |
| 214 |
|
97 | *movep = 0; |
| 215 | tsortv = sortv - 1; |
- | |
| 216 |
|
98 | tree->next_status[ply].exclude = &tree->next_status[ply].done[0]; |
| 217 | *(tsortv + 1) = *tsortv; |
- | |
| 218 | *(tmovep + 1) = *tmovep; |
- | |
| 219 | tmovep--; |
- | |
| 220 | tsortv--; |
- | |
| 221 |
|
99 | } else { |
| 222 | * |
100 | *movep += MVV_LVA[Captured(*movep)][Piece(*movep)]; |
| 223 |
|
101 | tree->next_status[ply].remaining++; |
| 224 | } |
102 | } |
| 225 | |
103 | NextSort(tree, ply); |
| 226 | tree->next_status[ply].last = tree->last[ply - 1]; |
104 | tree->next_status[ply].last = tree->last[ply - 1]; |
| - | 105 | if (in_check) |
|
| - | 106 | goto remaining_moves; |
|
| 227 | /* |
107 | /* |
| 228 | ************************************************************ |
108 | ************************************************************ |
| 229 | * * |
109 | * * |
| 230 | * Try the captures moves, which are in order based on * |
110 | * Try the captures moves, which are in order based on * |
| 231 | * MVV/LVA ordering. If a larger-valued piece captures a * |
111 | * MVV/LVA ordering. If a larger-valued piece captures a * |
| 232 | * lesser-valued piece, and |
112 | * lesser-valued piece, and SEE() says it loses material, * |
| 233 | * this capture will be deferred until later. * |
113 | * this capture will be deferred until later. * |
| - | 114 | * * |
|
| - | 115 | * If we are in check, we jump down to the history moves * |
|
| - | 116 | * phase (we don't need to generate any more moves as * |
|
| - | 117 | * GenerateCheckEvasions has already generated all legal * |
|
| - | 118 | * moves. * |
|
| 234 | * * |
119 | * * |
| 235 | ************************************************************ |
120 | ************************************************************ |
| 236 | */ |
121 | */ |
| 237 | case |
122 | case CAPTURES: |
| 238 | while (tree->next_status[ply].remaining) { |
123 | while (tree->next_status[ply].remaining) { |
| 239 | tree->curmv[ply] = *(tree->next_status[ply].last++); |
124 | tree->curmv[ply] = Move(*(tree->next_status[ply].last++)); |
| 240 | if (!--tree->next_status[ply].remaining) |
125 | if (!--tree->next_status[ply].remaining) |
| 241 | tree->next_status[ply].phase = |
126 | tree->next_status[ply].phase = KILLER1; |
| 242 | if (pcval[Piece(tree->curmv[ply])] |
127 | if (pcval[Piece(tree->curmv[ply])] <= |
| 243 |
|
128 | pcval[Captured(tree->curmv[ply])] |
| 244 |
|
129 | || SEE(tree, side, tree->curmv[ply]) >= 0) { |
| 245 | *(tree->next_status[ply].last - 1) = 0; |
130 | *(tree->next_status[ply].last - 1) = 0; |
| 246 |
|
131 | tree->phase[ply] = CAPTURES; |
| - | 132 | return ++tree->next_status[ply].order; |
|
| - | 133 | } |
|
| 247 | } |
134 | } |
| 248 | /* |
135 | /* |
| 249 | ************************************************************ |
136 | ************************************************************ |
| 250 | * * |
137 | * * |
| 251 | * Now, try the killer moves. This phase tries the two * |
138 | * Now, try the killer moves. This phase tries the two * |
| Line 255... | Line 142... | ||
| 255 | * back since they have greater depth and might produce a * |
142 | * back since they have greater depth and might produce a * |
| 256 | * cutoff if the current two do not. * |
143 | * cutoff if the current two do not. * |
| 257 | * * |
144 | * * |
| 258 | ************************************************************ |
145 | ************************************************************ |
| 259 | */ |
146 | */ |
| 260 | case |
147 | case KILLER1: |
| - | 148 | possible = tree->killers[ply].move1; |
|
| 261 | if (!Exclude(tree, ply, |
149 | if (!Exclude(tree, ply, possible) && |
| 262 | ValidMove(tree, ply, |
150 | ValidMove(tree, ply, side, possible)) { |
| 263 | tree->curmv[ply] = |
151 | tree->curmv[ply] = possible; |
| 264 |
|
152 | *(tree->next_status[ply].exclude++) = possible; |
| 265 | num_excluded++] |
- | |
| 266 |
|
153 | tree->next_status[ply].phase = KILLER2; |
| 267 | tree-> |
154 | tree->phase[ply] = KILLER1; |
| 268 | return |
155 | return ++tree->next_status[ply].order; |
| 269 | } |
156 | } |
| 270 | case |
157 | case KILLER2: |
| - | 158 | possible = tree->killers[ply].move2; |
|
| 271 | if (!Exclude(tree, ply, |
159 | if (!Exclude(tree, ply, possible) && |
| 272 | ValidMove(tree, ply, |
160 | ValidMove(tree, ply, side, possible)) { |
| 273 | tree->curmv[ply] = |
161 | tree->curmv[ply] = possible; |
| 274 |
|
162 | *(tree->next_status[ply].exclude++) = possible; |
| 275 | num_excluded++] |
- | |
| 276 | = tree->curmv[ply]; |
- | |
| 277 | if (ply < 3) { |
- | |
| 278 |
|
163 | tree->next_status[ply].phase = (ply < 3) ? COUNTER_MOVE1 : KILLER3; |
| 279 | } else |
- | |
| 280 |
|
164 | tree->phase[ply] = KILLER2; |
| 281 | return |
165 | return ++tree->next_status[ply].order; |
| 282 | } |
166 | } |
| 283 | case |
167 | case KILLER3: |
| 284 |
|
168 | possible = tree->killers[ply - 2].move1; |
| - | 169 | if (!Exclude(tree, ply, possible) && |
|
| 285 | ValidMove(tree, ply, |
170 | ValidMove(tree, ply, side, possible)) { |
| - | 171 | tree->curmv[ply] = possible; |
|
| - | 172 | *(tree->next_status[ply].exclude++) = possible; |
|
| - | 173 | tree->next_status[ply].phase = KILLER4; |
|
| - | 174 | tree->phase[ply] = KILLER3; |
|
| - | 175 | return ++tree->next_status[ply].order; |
|
| - | 176 | } |
|
| - | 177 | case KILLER4: |
|
| 286 |
|
178 | possible = tree->killers[ply - 2].move2; |
| - | 179 | if (!Exclude(tree, ply, possible) && |
|
| - | 180 | ValidMove(tree, ply, side, possible)) { |
|
| - | 181 | tree->curmv[ply] = possible; |
|
| 287 |
|
182 | *(tree->next_status[ply].exclude++) = possible; |
| - | 183 | tree->next_status[ply].phase = COUNTER_MOVE1; |
|
| 288 |
|
184 | tree->phase[ply] = KILLER4; |
| - | 185 | return ++tree->next_status[ply].order; |
|
| - | 186 | } |
|
| - | 187 | /* |
|
| - | 188 | ************************************************************ |
|
| - | 189 | * * |
|
| - | 190 | * Now, before we give up and generate moves, try the * |
|
| - | 191 | * counter-move which was a move that failed high in the * |
|
| - | 192 | * past when the move at the previous ply was played. * |
|
| - | 193 | * * |
|
| - | 194 | ************************************************************ |
|
| - | 195 | */ |
|
| - | 196 | case COUNTER_MOVE1: |
|
| - | 197 | possible = counter_move[tree->curmv[ply - 1] & 4095].move1; |
|
| - | 198 | if (!Exclude(tree, ply, possible) && |
|
| - | 199 | ValidMove(tree, ply, side, possible)) { |
|
| 289 |
|
200 | tree->curmv[ply] = possible; |
| - | 201 | *(tree->next_status[ply].exclude++) = possible; |
|
| 290 | tree->next_status[ply].phase = |
202 | tree->next_status[ply].phase = COUNTER_MOVE2; |
| - | 203 | tree->phase[ply] = COUNTER_MOVE1; |
|
| - | 204 | return ++tree->next_status[ply].order; |
|
| - | 205 | } |
|
| 291 |
|
206 | case COUNTER_MOVE2: |
| - | 207 | possible = counter_move[tree->curmv[ply - 1] & 4095].move2; |
|
| - | 208 | if (!Exclude(tree, ply, possible) && |
|
| - | 209 | ValidMove(tree, ply, side, possible)) { |
|
| - | 210 | tree->curmv[ply] = possible; |
|
| - | 211 | *(tree->next_status[ply].exclude++) = possible; |
|
| - | 212 | tree->next_status[ply].phase = MOVE_PAIR1; |
|
| - | 213 | tree->phase[ply] = COUNTER_MOVE2; |
|
| - | 214 | return ++tree->next_status[ply].order; |
|
| - | 215 | } |
|
| - | 216 | /* |
|
| - | 217 | ************************************************************ |
|
| - | 218 | * * |
|
| - | 219 | * Finally we try paired moves, which are simply moves * |
|
| - | 220 | * that were good when played after the other move in the * |
|
| - | 221 | * pair was played two plies back. * |
|
| - | 222 | * * |
|
| - | 223 | ************************************************************ |
|
| - | 224 | */ |
|
| - | 225 | case MOVE_PAIR1: |
|
| - | 226 | possible = move_pair[tree->curmv[ply - 2] & 4095].move1; |
|
| - | 227 | if (!Exclude(tree, ply, possible) && |
|
| - | 228 | ValidMove(tree, ply, side, possible)) { |
|
| - | 229 | tree->curmv[ply] = possible; |
|
| - | 230 | *(tree->next_status[ply].exclude++) = possible; |
|
| - | 231 | tree->next_status[ply].phase = MOVE_PAIR2; |
|
| - | 232 | tree->phase[ply] = MOVE_PAIR1; |
|
| - | 233 | return ++tree->next_status[ply].order; |
|
| 292 | } |
234 | } |
| 293 | case |
235 | case MOVE_PAIR2: |
| - | 236 | possible = move_pair[tree->curmv[ply - 2] & 4095].move2; |
|
| 294 | if (!Exclude(tree, ply, |
237 | if (!Exclude(tree, ply, possible) && |
| 295 | ValidMove(tree, ply, |
238 | ValidMove(tree, ply, side, possible)) { |
| 296 | tree->curmv[ply] = |
239 | tree->curmv[ply] = possible; |
| 297 |
|
240 | *(tree->next_status[ply].exclude++) = possible; |
| 298 | num_excluded++] |
- | |
| 299 |
|
241 | tree->next_status[ply].phase = GENERATE_QUIET; |
| 300 | tree-> |
242 | tree->phase[ply] = MOVE_PAIR2; |
| 301 | return |
243 | return ++tree->next_status[ply].order; |
| 302 | } |
244 | } |
| 303 | /* |
245 | /* |
| 304 | ************************************************************ |
246 | ************************************************************ |
| 305 | * * |
247 | * * |
| 306 | * Now, generate all non-capturing moves, which get added * |
248 | * Now, generate all non-capturing moves, which get added * |
| 307 | * to the move list behind any captures we did not search. * |
249 | * to the move list behind any captures we did not search. * |
| 308 | * * |
250 | * * |
| 309 | ************************************************************ |
251 | ************************************************************ |
| 310 | */ |
252 | */ |
| 311 | case |
253 | case GENERATE_QUIET: |
| - | 254 | if (!in_check) |
|
| 312 | tree->last[ply] = |
255 | tree->last[ply] = |
| 313 | tree-> |
256 | GenerateNoncaptures(tree, ply, side, tree->last[ply]); |
| 314 | tree->next_status[ply].last = tree->last[ply - 1]; |
257 | tree->next_status[ply].last = tree->last[ply - 1]; |
| 315 | /* |
258 | /* |
| 316 | ************************************************************ |
259 | ************************************************************ |
| 317 | * * |
260 | * * |
| 318 | * |
261 | * Now, try the history moves. This phase takes the * |
| - | 262 | * complete move list, and passes over them in a classic * |
|
| 319 | * |
263 | * selection-sort, choosing the move with the highest * |
| - | 264 | * history score. This phase is only done one time, as it * |
|
| - | 265 | * also purges the hash, killer, counter and paired moves * |
|
| 320 | * |
266 | * from the list. * |
| 321 | * * |
267 | * * |
| 322 | ************************************************************ |
268 | ************************************************************ |
| 323 | */ |
269 | */ |
| - | 270 | tree->next_status[ply].remaining = 0; |
|
| - | 271 | tree->next_status[ply].phase = HISTORY; |
|
| - | 272 | bestval = -99999999; |
|
| - | 273 | bestp = 0; |
|
| - | 274 | for (movep = tree->last[ply - 1]; movep < tree->last[ply]; movep++) |
|
| - | 275 | if (*movep) { |
|
| - | 276 | if (Exclude(tree, ply, *movep)) |
|
| - | 277 | *movep = 0; |
|
| - | 278 | else if (depth >= 6) { |
|
| - | 279 | tree->next_status[ply].remaining++; |
|
| - | 280 | hist = history[HistoryIndex(side, *movep)]; |
|
| - | 281 | if (hist > bestval) { |
|
| - | 282 | bestval = hist; |
|
| - | 283 | bestp = movep; |
|
| - | 284 | } |
|
| - | 285 | } |
|
| - | 286 | } |
|
| - | 287 | tree->next_status[ply].remaining /= 2; |
|
| - | 288 | if (bestp) { |
|
| - | 289 | tree->curmv[ply] = Move(*bestp); |
|
| - | 290 | *bestp = 0; |
|
| - | 291 | tree->phase[ply] = HISTORY; |
|
| - | 292 | return ++tree->next_status[ply].order; |
|
| - | 293 | } |
|
| - | 294 | goto remaining_moves; |
|
| - | 295 | /* |
|
| - | 296 | ************************************************************ |
|
| - | 297 | * * |
|
| - | 298 | * Now, continue with the history moves, but since one * |
|
| - | 299 | * pass has been made over the complete move list, there * |
|
| - | 300 | * are no hash/killer moves left in the list, so the tests * |
|
| - | 301 | * for these can be avoided. * |
|
| - | 302 | * * |
|
| - | 303 | ************************************************************ |
|
| - | 304 | */ |
|
| - | 305 | case HISTORY: |
|
| - | 306 | if (depth >= 6) { |
|
| - | 307 | bestval = -99999999; |
|
| - | 308 | bestp = 0; |
|
| - | 309 | for (movep = tree->last[ply - 1]; movep < tree->last[ply]; movep++) |
|
| - | 310 | if (*movep) { |
|
| - | 311 | hist = history[HistoryIndex(side, *movep)]; |
|
| - | 312 | if (hist > bestval) { |
|
| - | 313 | bestval = hist; |
|
| - | 314 | bestp = movep; |
|
| - | 315 | } |
|
| - | 316 | } |
|
| - | 317 | if (bestp) { |
|
| - | 318 | tree->curmv[ply] = Move(*bestp); |
|
| - | 319 | *bestp = 0; |
|
| - | 320 | if (--(tree->next_status[ply].remaining) <= 0) { |
|
| - | 321 | tree->next_status[ply].phase = REMAINING; |
|
| - | 322 | tree->next_status[ply].last = tree->last[ply - 1]; |
|
| - | 323 | } |
|
| - | 324 | tree->phase[ply] = HISTORY; |
|
| - | 325 | return ++tree->next_status[ply].order; |
|
| - | 326 | } |
|
| - | 327 | } |
|
| - | 328 | /* |
|
| - | 329 | ************************************************************ |
|
| - | 330 | * * |
|
| - | 331 | * Then we try the rest of the set of moves, and we do not * |
|
| - | 332 | * use Exclude() function to skip any moves we have * |
|
| - | 333 | * already searched (hash or killers) since the history * |
|
| - | 334 | * phase above has already done that. * |
|
| - | 335 | * * |
|
| - | 336 | ************************************************************ |
|
| - | 337 | */ |
|
| - | 338 | remaining_moves: |
|
| - | 339 | tree->next_status[ply].phase = REMAINING; |
|
| - | 340 | tree->next_status[ply].last = tree->last[ply - 1]; |
|
| 324 | case |
341 | case REMAINING: |
| 325 | for (; tree->next_status[ply].last < tree->last[ply]; |
342 | for (; tree->next_status[ply].last < tree->last[ply]; |
| 326 | tree->next_status[ply].last++) |
343 | tree->next_status[ply].last++) |
| 327 | if (*tree->next_status[ply].last) { |
344 | if (*tree->next_status[ply].last) { |
| 328 |
|
345 | tree->curmv[ply] = Move(*tree->next_status[ply].last++); |
| 329 |
|
346 | tree->phase[ply] = REMAINING; |
| 330 |
|
347 | return ++tree->next_status[ply].order; |
| 331 | } |
- | |
| 332 | } |
348 | } |
| 333 | return NONE; |
349 | return NONE; |
| 334 | default: |
350 | default: |
| 335 | Print(4095, "oops! next_status.phase is bad! [ |
351 | Print(4095, "oops! next_status.phase is bad! [phase=%d]\n", |
| 336 | tree->next_status[ply].phase); |
352 | tree->next_status[ply].phase); |
| 337 | } |
353 | } |
| 338 | return NONE; |
354 | return NONE; |
| 339 | } |
355 | } |
| 340 | 356 | ||
| 341 | /* last modified |
357 | /* last modified 07/03/14 */ |
| 342 | /* |
358 | /* |
| 343 | ******************************************************************************* |
359 | ******************************************************************************* |
| 344 | * * |
360 | * * |
| 345 | * NextRootMove() is used to select the next move from the root move list. * |
361 | * NextRootMove() is used to select the next move from the root move list. * |
| - | 362 | * * |
|
| - | 363 | * There is one subtle trick here that must not be broken. Crafty does LMR * |
|
| - | 364 | * at the root, and the reduction amount is dependent on the order in which * |
|
| - | 365 | * a specific move is searched. With the recent changes dealing with this * |
|
| - | 366 | * issue in non-root moves, NextRootMove() now simply returns the move's * |
|
| - | 367 | * order within the move list. This might be a problem if the last move in * |
|
| - | 368 | * the list fails high, because it would be reduced on the re-search, which * |
|
| - | 369 | * is something we definitely don't want. The solution is found in the code * |
|
| - | 370 | * inside Iterate(). When a move fails high, it is moved to the top of the * |
|
| - | 371 | * move list so that (a) it is searched first on the re-search (more on this * |
|
| - | 372 | * in a moment) and (b) since its position in the move list is now #1, it * |
|
| - | 373 | * will get an order value of 1 which is never reduced. The only warning is * |
|
| - | 374 | * that Iterate() MUST re-sort the ply-1 move list after a fail high, even * |
|
| - | 375 | * though it seems like a very tiny computational waste. * |
|
| - | 376 | * * |
|
| - | 377 | * The other reason for doing the re-sort has to do with the parallel search * |
|
| - | 378 | * algorithm. When one thread fails high at the root, it stops the others. * |
|
| - | 379 | * they have to carefully undo the "this move has been searched" flag since * |
|
| - | 380 | * these incomplete searches need to be re-done after the fail-high move is * |
|
| - | 381 | * finished. But it is possible some of those interrupted moves appear * |
|
| - | 382 | * before the fail high move in the move list. Which would lead Crafty to * |
|
| - | 383 | * fail high, then produce a different best move's PV. By re-sorting, now * |
|
| - | 384 | * the fail-high move is always searched first since here we just start at * |
|
| - | 385 | * the top of the move list and look for the first "not yet searched" move * |
|
| - | 386 | * to return. It solves several problems, but if that re-sort is not done, * |
|
| - | 387 | * things go south quickly. The voice of experience is all I will say here. * |
|
| 346 | * * |
388 | * * |
| 347 | ******************************************************************************* |
389 | ******************************************************************************* |
| 348 | */ |
390 | */ |
| 349 | int NextRootMove(TREE * RESTRICT tree, TREE * RESTRICT mytree, int |
391 | int NextRootMove(TREE * RESTRICT tree, TREE * RESTRICT mytree, int side) { |
| 350 | int which, i; |
- | |
| 351 | uint64_t total_nodes; |
392 | uint64_t total_nodes; |
| - | 393 | int which, i, t; |
|
| 352 | 394 | ||
| 353 | /* |
395 | /* |
| 354 | ************************************************************ |
396 | ************************************************************ |
| 355 | * * |
397 | * * |
| 356 | * First, we check to see if we only have one legal move. * |
398 | * First, we check to see if we only have one legal move. * |
| Line 359... | Line 401... | ||
| 359 | * to ponder. * |
401 | * to ponder. * |
| 360 | * * |
402 | * * |
| 361 | ************************************************************ |
403 | ************************************************************ |
| 362 | */ |
404 | */ |
| 363 | if (!annotate_mode && !pondering && !booking && n_root_moves == 1 && |
405 | if (!annotate_mode && !pondering && !booking && n_root_moves == 1 && |
| 364 |
|
406 | iteration > 10) { |
| 365 | abort_search = 1; |
407 | abort_search = 1; |
| 366 | return NONE; |
408 | return NONE; |
| 367 | } |
409 | } |
| 368 | /* |
410 | /* |
| 369 | ************************************************************ |
411 | ************************************************************ |
| Line 377... | Line 419... | ||
| 377 | * return so that it won't be searched again in another * |
419 | * return so that it won't be searched again in another * |
| 378 | * thread. * |
420 | * thread. * |
| 379 | * * |
421 | * * |
| 380 | ************************************************************ |
422 | ************************************************************ |
| 381 | */ |
423 | */ |
| 382 | for (which = 0; which < n_root_moves; which++) |
424 | for (which = 0; which < n_root_moves; which++) { |
| 383 | if (!(root_moves[which].status & 8)) { |
425 | if (!(root_moves[which].status & 8)) { |
| 384 | if (search_move) { |
426 | if (search_move) { |
| 385 | if (root_moves[which].move != search_move) { |
427 | if (root_moves[which].move != search_move) { |
| 386 | root_moves[which].status |= 8; |
428 | root_moves[which].status |= 8; |
| 387 | continue; |
429 | continue; |
| Line 403... | Line 445... | ||
| 403 | * the search, simply for information about how fast the * |
445 | * the search, simply for information about how fast the * |
| 404 | * machine is running. * |
446 | * machine is running. * |
| 405 | * * |
447 | * * |
| 406 | ************************************************************ |
448 | ************************************************************ |
| 407 | */ |
449 | */ |
| 408 | if ( |
450 | if (ReadClock() - start_time > noise_level && display_options & 16) { |
| 409 | Lock(lock_io); |
- | |
| 410 |
|
451 | sprintf(mytree->remaining_moves_text, "%d/%d", which + 1, |
| 411 | n_root_moves); |
452 | n_root_moves); |
| 412 | end_time = ReadClock(); |
453 | end_time = ReadClock(); |
| - | 454 | Lock(lock_io); |
|
| 413 | if (pondering) |
455 | if (pondering) |
| 414 | printf(" %2i %s%7s? ", |
456 | printf(" %2i %s%7s? ", iteration, |
| 415 | Display2Times(end_time - start_time), |
457 | Display2Times(end_time - start_time), |
| 416 | mytree->remaining_moves_text); |
458 | mytree->remaining_moves_text); |
| 417 | else |
459 | else |
| 418 | printf(" %2i %s%7s* ", |
460 | printf(" %2i %s%7s* ", iteration, |
| 419 | Display2Times(end_time - start_time), |
461 | Display2Times(end_time - start_time), |
| 420 | mytree->remaining_moves_text); |
462 | mytree->remaining_moves_text); |
| 421 | if (display_options & 32 && display_options & 64) |
- | |
| 422 |
|
463 | printf("%d. ", move_number); |
| 423 | if ( |
464 | if (Flip(side)) |
| 424 | printf("... "); |
465 | printf("... "); |
| 425 |
|
466 | strcpy(mytree->root_move_text, OutputMove(tree, 1, side, |
| 426 |
|
467 | tree->curmv[1])); |
| 427 | total_nodes = block[0]->nodes_searched; |
468 | total_nodes = block[0]->nodes_searched; |
| - | 469 | for (t = 0; t < (int) smp_max_threads; t++) // Pierre-Marie Baty -- added type cast |
|
| 428 | for (i = |
470 | for (i = 0; i < 64; i++) |
| 429 | if ( |
471 | if (!(thread[t].blocks & SetMask(i))) |
| 430 | total_nodes += block[i]->nodes_searched; |
472 | total_nodes += block[t * 64 + 1 + i]->nodes_searched; |
| 431 | nodes_per_second = (unsigned int) (total_nodes * 100 / Max(end_time - start_time, 1)); // Pierre-Marie Baty -- added type cast |
473 | nodes_per_second = (unsigned int) (total_nodes * 100 / Max(end_time - start_time, 1)); // Pierre-Marie Baty -- added type cast |
| 432 | i = strlen(mytree->root_move_text); |
474 | i = strlen(mytree->root_move_text); |
| 433 | i = (i < 8) ? i : 8; |
475 | i = (i < 8) ? i : 8; |
| 434 |
|
476 | strncat(mytree->root_move_text, " ", 8 - i); |
| 435 | printf("%s", mytree->root_move_text); |
477 | printf("%s", mytree->root_move_text); |
| 436 | printf("(%snps) \r", DisplayKMB(nodes_per_second)); |
478 | printf("(%snps) \r", DisplayKMB(nodes_per_second, 0)); |
| 437 | fflush(stdout); |
479 | fflush(stdout); |
| 438 | Unlock(lock_io); |
480 | Unlock(lock_io); |
| 439 | } |
481 | } |
| 440 | /* |
482 | /* |
| 441 | ************************************************************ |
483 | ************************************************************ |
| 442 | * * |
484 | * * |
| 443 | * Bit of a tricky exit. If the move is not flagged as * |
485 | * Bit of a tricky exit. If the move is not flagged as * |
| 444 | * "OK to search in parallel or reduce" then we return * |
486 | * "OK to search in parallel or reduce" then we return * |
| 445 | * " |
487 | * "DO_NOT_REDUCE" which will prevent Search() from * |
| 446 | * the move (LMR). Otherwise we return the more |
488 | * reducing the move (LMR). Otherwise we return the more * |
| 447 | * " |
489 | * common "REMAINING" value which allows LMR to be used on * |
| 448 | * those root moves. * |
490 | * those root moves. * |
| 449 | * * |
491 | * * |
| 450 | ************************************************************ |
492 | ************************************************************ |
| 451 | */ |
493 | */ |
| 452 | if |
494 | if (root_moves[which].status & 4) |
| 453 |
|
495 | tree->phase[1] = DO_NOT_REDUCE; |
| 454 | else |
496 | else |
| 455 |
|
497 | tree->phase[1] = REMAINING; |
| - | 498 | return which + 1; |
|
| 456 | } |
499 | } |
| - | 500 | } |
|
| 457 | return NONE; |
501 | return NONE; |
| 458 | } |
502 | } |
| 459 | 503 | ||
| 460 | /* last modified |
504 | /* last modified 11/13/14 */ |
| 461 | /* |
505 | /* |
| 462 | ******************************************************************************* |
506 | ******************************************************************************* |
| 463 | * * |
507 | * * |
| 464 | * NextRootMoveParallel() is used to determine if the next root move can be * |
508 | * NextRootMoveParallel() is used to determine if the next root move can be * |
| 465 | * searched in parallel. If it appears to Iterate() that one of the moves * |
509 | * searched in parallel. If it appears to Iterate() that one of the moves * |
| 466 | * following the first move might become the best move, the 'no parallel' * |
510 | * following the first move might become the best move, the 'no parallel' * |
| 467 | * flag is set to speed up finding the new best move. This flag is set if * |
511 | * flag is set to speed up finding the new best move. This flag is set if * |
| 468 | * this root move has an "age" value > 0 which indicates this move was the * |
512 | * this root move has an "age" value > 0 which indicates this move was the * |
| 469 | * "best move" within the previous 3 search |
513 | * "best move" within the previous 3 search iterations. We want to search * |
| 470 | * moves as quickly as possible, prior to starting a parallel search at |
514 | * such moves as quickly as possible, prior to starting a parallel search at * |
| 471 | * root, in case this move once again becomes the best move and provides |
515 | * the root, in case this move once again becomes the best move and provides * |
| 472 | * better alpha bound. |
516 | * a better alpha bound. * |
| 473 | * * |
517 | * * |
| 474 | ******************************************************************************* |
518 | ******************************************************************************* |
| 475 | */ |
519 | */ |
| 476 | int NextRootMoveParallel(void) { |
520 | int NextRootMoveParallel(void) { |
| 477 | int which; |
521 | int which; |
| Line 480... | Line 524... | ||
| 480 | ************************************************************ |
524 | ************************************************************ |
| 481 | * * |
525 | * * |
| 482 | * Here we simply check the root_move status flag that is * |
526 | * Here we simply check the root_move status flag that is * |
| 483 | * set in Iterate() after each iteration is completed. A * |
527 | * set in Iterate() after each iteration is completed. A * |
| 484 | * value of "1" indicates this move has to be searched by * |
528 | * value of "1" indicates this move has to be searched by * |
| 485 | * all |
529 | * all processors together, splitting at the root must * |
| 486 | * |
530 | * wait until we have searched all moves that have been * |
| - | 531 | * "best" during the previous three plies. * |
|
| - | 532 | * * |
|
| - | 533 | * The root move list has a flag, bit 3, used to indicate * |
|
| - | 534 | * that this move has been best recently. If this bit is * |
|
| - | 535 | * set, we are forced to use all processors to search this * |
|
| - | 536 | * move so that it is completed quickly rather than being * |
|
| - | 537 | * searched by just one processor, and taking much longer * |
|
| - | 538 | * to get a score back. We do this to give the search the * |
|
| - | 539 | * best opportunity to fail high on this move before we * |
|
| - | 540 | * run out of time. * |
|
| 487 | * * |
541 | * * |
| 488 | ************************************************************ |
542 | ************************************************************ |
| 489 | */ |
543 | */ |
| 490 | for (which = 0; which < n_root_moves; which++) |
544 | for (which = 0; which < n_root_moves; which++) |
| 491 | if (!(root_moves[which].status & 8)) |
545 | if (!(root_moves[which].status & 8)) |
| 492 | break; |
546 | break; |
| 493 | if (which < n_root_moves && root_moves[which].status & 4) |
547 | if (which < n_root_moves && !(root_moves[which].status & 4)) |
| 494 | return 1; |
548 | return 1; |
| 495 | return 0; |
549 | return 0; |
| 496 | } |
550 | } |
| 497 | 551 | ||
| 498 | /* last modified |
552 | /* last modified 09/11/15 */ |
| 499 | /* |
553 | /* |
| 500 | ******************************************************************************* |
554 | ******************************************************************************* |
| 501 | * * |
555 | * * |
| 502 | * Exclude() searches the list of moves searched prior to generating a move * |
556 | * Exclude() searches the list of moves searched prior to generating a move * |
| 503 | * list to exclude those that were searched via a hash table best move or * |
557 | * list to exclude those that were searched via a hash table best move or * |
| 504 | * through the killer moves for the current ply and two plies back. * |
558 | * through the killer moves for the current ply and two plies back. * |
| 505 | * * |
559 | * * |
| 506 | * The variable next_status[]. |
560 | * The variable next_status[].excluded is the total number of non-generated * |
| 507 | * |
561 | * moves we searched. next_status[].remaining is initially set to excluded, * |
| 508 | * |
562 | * but each time an excluded move is found, the counter is decremented. * |
| 509 | * |
563 | * Once all excluded moves have been found, we avoid running through the * |
| 510 | * |
564 | * list of excluded moves on each call and simply return. * |
| 511 | * * |
565 | * * |
| 512 | ******************************************************************************* |
566 | ******************************************************************************* |
| 513 | */ |
567 | */ |
| 514 | int Exclude(TREE * RESTRICT tree, int ply, int move) { |
568 | int Exclude(TREE * RESTRICT tree, int ply, int move) { |
| 515 |
|
569 | unsigned *i; |
| 516 | 570 | ||
| 517 | if (tree->next_status[ply]. |
571 | if (tree->next_status[ply].exclude > &tree->next_status[ply].done[0]) |
| 518 | for (i = |
572 | for (i = &tree->next_status[ply].done[0]; |
| 519 |
|
573 | i < tree->next_status[ply].exclude; i++) |
| 520 |
|
574 | if (move == *i) |
| 521 | return 1; |
575 | return 1; |
| 522 | } |
- | |
| 523 | return 0; |
576 | return 0; |
| - | 577 | } |
|
| - | 578 | ||
| - | 579 | /* last modified 05/20/15 */ |
|
| - | 580 | /* |
|
| - | 581 | ******************************************************************************* |
|
| - | 582 | * * |
|
| - | 583 | * NextSort() is used to sort the move list. This is a list of 32 bit * |
|
| - | 584 | * values where the rightmost 21 bits is the compressed move, and the left- * |
|
| - | 585 | * most 11 bits are the sort key (MVV/LVA values). * |
|
| - | 586 | * * |
|
| - | 587 | ******************************************************************************* |
|
| - | 588 | */ |
|
| - | 589 | void NextSort(TREE * RESTRICT tree, int ply) { |
|
| - | 590 | unsigned temp, *movep, *tmovep; |
|
| - | 591 | ||
| - | 592 | /* |
|
| - | 593 | ************************************************************ |
|
| - | 594 | * * |
|
| - | 595 | * This is a simple insertion sort algorithm. * |
|
| - | 596 | * * |
|
| - | 597 | ************************************************************ |
|
| - | 598 | */ |
|
| - | 599 | if (tree->last[ply] > tree->last[ply - 1] + 1) { |
|
| - | 600 | for (movep = tree->last[ply - 1] + 1; movep < tree->last[ply]; movep++) { |
|
| - | 601 | temp = *movep; |
|
| - | 602 | tmovep = movep - 1; |
|
| - | 603 | while (tmovep >= tree->last[ply - 1] && SortV(*tmovep) < SortV(temp)) { |
|
| - | 604 | *(tmovep + 1) = *tmovep; |
|
| - | 605 | tmovep--; |
|
| - | 606 | } |
|
| - | 607 | *(tmovep + 1) = temp; |
|
| - | 608 | } |
|
| - | 609 | } |
|
| 524 | } |
610 | } |