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/22/14 */ | ||
| 4 | /* | ||
| 5 |  ******************************************************************************* | ||
| 6 |  *                                                                             * | ||
| 7 |  *   HashProbe() is used to retrieve entries from the transposition table so   * | ||
| 8 |  *   this sub-tree won't have to be searched again if we reach a position that * | ||
| 9 |  *   has been searched previously.  A transposition table position contains    * | ||
| 10 |  *   the following data packed into 128 bits with each item taking the number  * | ||
| 11 |  *   of bits given in the table below:                                         * | ||
| 12 |  *                                                                             * | ||
| 13 |  *     shr  bits     name description                                          * | ||
| 14 |  *      55   9       age  search id to identify old trans/ref entries.         * | ||
| 15 |  *      53   2      type  0->value is worthless; 1-> value represents a        * | ||
| 16 |  *                        fail-low bound; 2-> value represents a fail-high     * | ||
| 17 |  *                        bound; 3-> value is an exact score.                  * | ||
| 18 |  *      32  21      move  best move from the current position, according to    * | ||
| 19 |  *                        the search at the time this position was stored.     * | ||
| 20 |  *      17  15     draft  the depth of the search below this position, which   * | ||
| 21 |  *                        is used to see if we can use this entry at the       * | ||
| 22 |  *                        current position.                                    * | ||
| 23 |  *       0  17     value  unsigned integer value of this position + 65536.     * | ||
| 24 |  *                        this might be a good score or search bound.          * | ||
| 25 |  *       0  64       key  64 bit hash signature, used to verify that this      * | ||
| 26 |  *                        entry goes with the current board position.          * | ||
| 27 |  *                                                                             * | ||
| 28 |  *   The underlying scheme here is that we use a "bucket" of N entries.  In    * | ||
| 29 |  *   HashProbe() we simply compare against each of the four entries for a      * | ||
| 30 |  *   match.  Each "bucket" is carefully aligned to a 64-byte boundary so that  * | ||
| 31 |  *   the bucket fits into a single cache line for efficiency.  The bucket size * | ||
| 32 |  *   (N) is currently set to 4.                                                * | ||
| 33 |  *                                                                             * | ||
| 34 |  *   Crafty uses the lockless hashing approach to avoid lock overhead in the   * | ||
| 35 |  *   hash table accessing (reading or writing).  What we do is store the key   * | ||
| 36 |  *   and the information in two successive writes to memory.  But since there  * | ||
| 37 |  *   is nothing that prevents another CPU from interlacing its writes with     * | ||
| 38 |  *   ours, we want to make sure that the bound/draft/etc really goes with the  * | ||
| 39 |  *   key.  Consider thread 1 trying to store A1 and A2 in two successive 64    * | ||
| 40 |  *   words, while thread 2 is trying to store B1 and B2.  Since the two cpus   * | ||
| 41 |  *   are fully independent, we could end up with {A1,A2}, {A1,B2}, {B1,A2} or  * | ||
| 42 |  *   {B1,B2}.  The two cases with one word of entry A and one word of entry B  * | ||
| 43 |  *   are problematic since the information part does not belong with the       * | ||
| 44 |  *   signature part, and a hash hit (signature match) will retrieve data that  * | ||
| 45 |  *   does not match the position.  Let's assume that the first word is the     * | ||
| 46 |  *   signature (A1 or B1) and the second word is the data (A2 or B2).  What we * | ||
| 47 |  *   do is store A1^A2 (exclusive-or the two parts) in the 1 (key) slot of the * | ||
| 48 |  *   entry, and store A2 in the data part.  Now, before we try to compare the  * | ||
| 49 |  *   signatures, we have to "un-corrupt" the stored signature by again using   * | ||
| 50 |  *   xor, since A1^A2^A2 gives us the original A1 signature again.  But if we  * | ||
| 51 |  *   store A1^A2, and the data part gets replaced by B2, then we try to match  * | ||
| 52 |  *   against A1^A2^B2 and that won't match unless we are lucky and A2 == B2    * | ||
| 53 |  *   which means the match is OK anyway.  This eliminates the need to lock the * | ||
| 54 |  *   hash table while storing the two values, which would be a big performance * | ||
| 55 |  *   hit since hash entries are probed/stored in almost every node of the tree * | ||
| 56 |  *   except for the quiescence search.                                         * | ||
| 57 |  *                                                                             * | ||
| 58 |  ******************************************************************************* | ||
| 59 |  */ | ||
| 60 | int HashProbe(TREE * RESTRICT tree, int ply, int depth, int side, int alpha, | ||
| 61 | int beta, int *value) { | ||
| 62 | HASH_ENTRY *htable; | ||
| 63 | HPATH_ENTRY *ptable; | ||
| 64 | uint64_t word1, word2, temp_hashkey; | ||
| 65 | int type, draft, avoid_null = 0, val, entry, i, j; | ||
| 66 | |||
| 67 | /* | ||
| 68 |  ************************************************************ | ||
| 69 |  *                                                          * | ||
| 70 |  *  All we have to do is loop through four entries to see   * | ||
| 71 |  *  if there is a signature match.  There can only be one   * | ||
| 72 |  *  instance of any single signature, so the first match is * | ||
| 73 |  *  all we need.                                            * | ||
| 74 |  *                                                          * | ||
| 75 |  ************************************************************ | ||
| 76 |  */ | ||
| 77 | tree->hash_move[ply] = 0; | ||
| 78 | temp_hashkey = (side) ? HashKey : ~HashKey; | ||
| 79 | htable = trans_ref + (temp_hashkey & hash_mask); | ||
| 80 | for (entry = 0; entry < 4; entry++, htable++) { | ||
| 81 | word1 = htable->word1; | ||
| 82 | word2 = htable->word2 ^ word1; | ||
| 83 | if (word2 == temp_hashkey) | ||
| 84 | break; | ||
| 85 |   } | ||
| 86 | /* | ||
| 87 |  ************************************************************ | ||
| 88 |  *                                                          * | ||
| 89 |  *  If we found a match, we have to verify that the draft   * | ||
| 90 |  *  is at least equal to the current depth, if not higher,  * | ||
| 91 |  *  and that the bound/score will let us terminate the      * | ||
| 92 |  *  search early.                                           * | ||
| 93 |  *                                                          * | ||
| 94 |  *  We also return an "avoid_null" status if the matched    * | ||
| 95 |  *  entry does not have enough draft to terminate the       * | ||
| 96 |  *  current search but does have enough draft to prove that * | ||
| 97 |  *  a null-move search would not fail high.  This avoids    * | ||
| 98 |  *  the null-move search overhead in positions where it is  * | ||
| 99 |  *  simply a waste of time to try it.                       * | ||
| 100 |  *                                                          * | ||
| 101 |  *  If this is an EXACT entry, we are going to store the PV * | ||
| 102 |  *  in a safe place so that if we get a hit on this entry,  * | ||
| 103 |  *  we can recover the PV and see the complete path rather  * | ||
| 104 |  *  rather than one that is incomplete.                     * | ||
| 105 |  *                                                          * | ||
| 106 |  *  One other issue is to update the age field if we get a  * | ||
| 107 |  *  hit on an old position, so that it won't be replaced    * | ||
| 108 |  *  just because it came from a previous search.            * | ||
| 109 |  *                                                          * | ||
| 110 |  ************************************************************ | ||
| 111 |  */ | ||
| 112 | if (entry < 4) { | ||
| 113 | if (word1 >> 55 != transposition_age) { | ||
| 114 |       word1 = | ||
| 115 | (word1 & 0x007fffffffffffffull) | ((uint64_t) transposition_age << | ||
| 116 | 55); | ||
| 117 | htable->word1 = word1; | ||
| 118 | htable->word2 = word1 ^ word2; | ||
| 119 |     } | ||
| 120 | val = (word1 & 0x1ffff) - 65536; | ||
| 121 | draft = (word1 >> 17) & 0x7fff; | ||
| 122 | tree->hash_move[ply] = (word1 >> 32) & 0x1fffff; | ||
| 123 | type = (word1 >> 53) & 3; | ||
| 124 | if ((type & UPPER) && depth - null_depth - 1 <= draft && val < beta) | ||
| 125 | avoid_null = AVOID_NULL_MOVE; | ||
| 126 | if (depth <= draft) { | ||
| 127 | if (val > 32000) | ||
| 128 | val -= ply - 1; | ||
| 129 | else if (val < -32000) | ||
| 130 | val += ply - 1; | ||
| 131 | *value = val; | ||
| 132 | /* | ||
| 133 |  ************************************************************ | ||
| 134 |  *                                                          * | ||
| 135 |  *  We have three types of results.  An EXACT entry was     * | ||
| 136 |  *  stored when val > alpha and val < beta, and represents  * | ||
| 137 |  *  an exact score.  An UPPER entry was stored when val <   * | ||
| 138 |  *  alpha, which represents an upper bound with the score   * | ||
| 139 |  *  likely being even lower.  A LOWER entry was stored when * | ||
| 140 |  *  val > beta, which represents alower bound with the      * | ||
| 141 |  *  score likely being even higher.                         * | ||
| 142 |  *                                                          * | ||
| 143 |  *  For EXACT entries, we save the path from the position   * | ||
| 144 |  *  to the terminal node that produced the backed-up score  * | ||
| 145 |  *  so that we can complete the PV if we get a hash hit on  * | ||
| 146 |  *  this entry.                                             * | ||
| 147 |  *                                                          * | ||
| 148 |  ************************************************************ | ||
| 149 |  */ | ||
| 150 | switch (type) { | ||
| 151 | case EXACT: | ||
| 152 | if (val > alpha && val < beta) { | ||
| 153 | SavePV(tree, ply, 1 + (draft == MAX_DRAFT)); | ||
| 154 | ptable = hash_path + (temp_hashkey & hash_path_mask); | ||
| 155 | for (i = 0; i < 16; i++, ptable++) | ||
| 156 | if (ptable->path_sig == temp_hashkey) { | ||
| 157 | for (j = ply; j < Min(MAXPLY - 1, ptable->hash_pathl + ply); | ||
| 158 | j++) | ||
| 159 | tree->pv[ply - 1].path[j] = | ||
| 160 | ptable->hash_path_moves[j - ply]; | ||
| 161 | if (draft != MAX_DRAFT && | ||
| 162 | ptable->hash_pathl + ply < MAXPLY - 1) | ||
| 163 | tree->pv[ply - 1].pathh = 0; | ||
| 164 | tree->pv[ply - 1].pathl = | ||
| 165 | Min(MAXPLY - 1, ply + ptable->hash_pathl); | ||
| 166 | ptable->hash_path_age = transposition_age; | ||
| 167 | break; | ||
| 168 |               } | ||
| 169 |           } | ||
| 170 | return HASH_HIT; | ||
| 171 | case UPPER: | ||
| 172 | if (val <= alpha) | ||
| 173 | return HASH_HIT; | ||
| 174 | break; | ||
| 175 | case LOWER: | ||
| 176 | if (val >= beta) | ||
| 177 | return HASH_HIT; | ||
| 178 | break; | ||
| 179 |       } | ||
| 180 |     } | ||
| 181 | return avoid_null; | ||
| 182 |   } | ||
| 183 | return HASH_MISS; | ||
| 184 | } | ||
| 185 | |||
| 186 | /* last modified 02/22/14 */ | ||
| 187 | /* | ||
| 188 |  ******************************************************************************* | ||
| 189 |  *                                                                             * | ||
| 190 |  *   HashStore() is used to store entries into the transposition table so that * | ||
| 191 |  *   this sub-tree won't have to be searched again if the same position is     * | ||
| 192 |  *   reached.  We basically store three types of entries:                      * | ||
| 193 |  *                                                                             * | ||
| 194 |  *     (1) EXACT.  This entry is stored when we complete a search at some ply  * | ||
| 195 |  *        and end up with a score that is greater than alpha and less than     * | ||
| 196 |  *        beta, which is an exact score, which also has a best move to try if  * | ||
| 197 |  *        we encounter this position again.                                    * | ||
| 198 |  *                                                                             * | ||
| 199 |  *     (2) LOWER.  This entry is stored when we complete a search at some ply  * | ||
| 200 |  *        and end up with a score that is greater than or equal to beta.  We   * | ||
| 201 |  *        know know that this score should be at least equal to beta and may   * | ||
| 202 |  *        well be even higher.  So this entry represents a lower bound on the  * | ||
| 203 |  *        score for this node, and we also have a good move to try since it    * | ||
| 204 |  *        caused the cutoff, although we do not know if it is the best move or * | ||
| 205 |  *        not since not all moves were search.                                 * | ||
| 206 |  *                                                                             * | ||
| 207 |  *     (3) UPPER.  This entry is stored when we complete a search at some ply  * | ||
| 208 |  *        and end up with a score that is less than or equal to alpha.  We     * | ||
| 209 |  *        know know that this score should be at least equal to alpha and may  * | ||
| 210 |  *        well be even lower.  So this entry represents an upper bound on the  * | ||
| 211 |  *        score for this node.  We have no idea about which move is best in    * | ||
| 212 |  *        this position since they all failed low, so we store a best move of  * | ||
| 213 |  *        zero.                                                                * | ||
| 214 |  *                                                                             * | ||
| 215 |  *   For storing, we may require three passes.  We make our first pass looking * | ||
| 216 |  *   for an entry that matches the current hash signature.  If we find a match * | ||
| 217 |  *   then we are constrained to overwrite that entry regardless of any other   * | ||
| 218 |  *   considerations.  The second pass looks for entries stored in previous     * | ||
| 219 |  *   searches (not iterations) and chooses the one with the shallowest draft,  * | ||
| 220 |  *   if one is found;  Otherwise we make a final pass over the bucket and      * | ||
| 221 |  *   choose the entry with the shallowest draft, period.                       * | ||
| 222 |  *                                                                             * | ||
| 223 |  ******************************************************************************* | ||
| 224 |  */ | ||
| 225 | void HashStore(TREE * RESTRICT tree, int ply, int depth, int side, int type, | ||
| 226 | int value, int bestmove) { | ||
| 227 | HASH_ENTRY *htable, *replace = 0; | ||
| 228 | HPATH_ENTRY *ptable; | ||
| 229 | uint64_t word1, temp_hashkey; | ||
| 230 | int entry, draft, age, replace_draft, i, j; | ||
| 231 | |||
| 232 | /* | ||
| 233 |  ************************************************************ | ||
| 234 |  *                                                          * | ||
| 235 |  *  "Fill in the blank" and build a table entry from        * | ||
| 236 |  *  current search information.                             * | ||
| 237 |  *                                                          * | ||
| 238 |  ************************************************************ | ||
| 239 |  */ | ||
| 240 | word1 = transposition_age; | ||
| 241 | word1 = (word1 << 2) | type; | ||
| 242 | if (value > 32000) | ||
| 243 | value += ply - 1; | ||
| 244 | else if (value < -32000) | ||
| 245 | value -= ply - 1; | ||
| 246 | word1 = (word1 << 21) | bestmove; | ||
| 247 | word1 = (word1 << 15) | depth; | ||
| 248 | word1 = (word1 << 17) | (value + 65536); | ||
| 249 | temp_hashkey = (side) ? HashKey : ~HashKey; | ||
| 250 | /* | ||
| 251 |  ************************************************************ | ||
| 252 |  *                                                          * | ||
| 253 |  *  Now we search for an entry to overwrite in three        * | ||
| 254 |  *  passes.                                                 * | ||
| 255 |  *                                                          * | ||
| 256 |  *  Pass 1:  If any signature in the table matches the      * | ||
| 257 |  *    current signature, we are going to overwrite this     * | ||
| 258 |  *    entry, period.  It might seem worthwhile to check the * | ||
| 259 |  *    draft and not overwrite if the table draft is greater * | ||
| 260 |  *    than the current remaining depth, but after you think * | ||
| 261 |  *    about it, this is a bad idea.  If the draft is        * | ||
| 262 |  *    greater than or equal the current remaining depth,    * | ||
| 263 |  *    then we should never get here unless the stored bound * | ||
| 264 |  *    or score is unusable because of the current alpha/    * | ||
| 265 |  *    beta window.  So we are overwriting to avoid losing   * | ||
| 266 |  *    the current result.                                   * | ||
| 267 |  *                                                          * | ||
| 268 |  *  Pass 2:  If any of the entries come from a previous     * | ||
| 269 |  *    search (not iteration) then we choose the entry from  * | ||
| 270 |  *    this set that has the smallest draft, since it is the * | ||
| 271 |  *    least potentially usable result.                      * | ||
| 272 |  *                                                          * | ||
| 273 |  *  Pass 3:  If neither of the above two found an entry to  * | ||
| 274 |  *    overwrite, we simply choose the entry from the bucket * | ||
| 275 |  *    with the smallest draft and overwrite that.           * | ||
| 276 |  *                                                          * | ||
| 277 |  ************************************************************ | ||
| 278 |  */ | ||
| 279 | htable = trans_ref + (temp_hashkey & hash_mask); | ||
| 280 | for (entry = 0; entry < 4; entry++, htable++) { | ||
| 281 | if (temp_hashkey == (htable->word1 ^ htable->word2)) { | ||
| 282 | replace = htable; | ||
| 283 | break; | ||
| 284 |     } | ||
| 285 |   } | ||
| 286 | if (!replace) { | ||
| 287 | replace_draft = 99999; | ||
| 288 | htable = trans_ref + (temp_hashkey & hash_mask); | ||
| 289 | for (entry = 0; entry < 4; entry++, htable++) { | ||
| 290 | age = htable->word1 >> 55; | ||
| 291 | draft = (htable->word1 >> 17) & 0x7fff; | ||
| 292 | if (age != transposition_age && replace_draft > draft) { | ||
| 293 | replace = htable; | ||
| 294 | replace_draft = draft; | ||
| 295 |       } | ||
| 296 |     } | ||
| 297 | if (!replace) { | ||
| 298 | htable = trans_ref + (temp_hashkey & hash_mask); | ||
| 299 | for (entry = 0; entry < 4; entry++, htable++) { | ||
| 300 | draft = (htable->word1 >> 17) & 0x7fff; | ||
| 301 | if (replace_draft > draft) { | ||
| 302 | replace = htable; | ||
| 303 | replace_draft = draft; | ||
| 304 |         } | ||
| 305 |       } | ||
| 306 |     } | ||
| 307 |   } | ||
| 308 | /* | ||
| 309 |  ************************************************************ | ||
| 310 |  *                                                          * | ||
| 311 |  *  Now that we know which entry to replace, we simply      * | ||
| 312 |  *  stuff the values and exit.  Note that the two 64 bit    * | ||
| 313 |  *  words are xor'ed together and stored as the signature   * | ||
| 314 |  *  for the "lockless-hash" approach.                       * | ||
| 315 |  *                                                          * | ||
| 316 |  ************************************************************ | ||
| 317 |  */ | ||
| 318 | replace->word1 = word1; | ||
| 319 | replace->word2 = temp_hashkey ^ word1; | ||
| 320 | /* | ||
| 321 |  ************************************************************ | ||
| 322 |  *                                                          * | ||
| 323 |  *  If this is an EXACT entry, we are going to store the PV * | ||
| 324 |  *  in a safe place so that if we get a hit on this entry,  * | ||
| 325 |  *  we can recover the PV and see the complete path rather  * | ||
| 326 |  *  rather than one that is incomplete.                     * | ||
| 327 |  *                                                          * | ||
| 328 |  ************************************************************ | ||
| 329 |  */ | ||
| 330 | if (type == EXACT) { | ||
| 331 | ptable = hash_path + (temp_hashkey & hash_path_mask); | ||
| 332 | for (i = 0; i < 16; i++, ptable++) { | ||
| 333 | if (ptable->path_sig == temp_hashkey || | ||
| 334 | ((transposition_age - ptable->hash_path_age) > 1)) { | ||
| 335 | for (j = ply; j < tree->pv[ply - 1].pathl; j++) | ||
| 336 | ptable->hash_path_moves[j - ply] = tree->pv[ply - 1].path[j]; | ||
| 337 | ptable->hash_pathl = tree->pv[ply - 1].pathl - ply; | ||
| 338 | ptable->path_sig = temp_hashkey; | ||
| 339 | ptable->hash_path_age = transposition_age; | ||
| 340 | break; | ||
| 341 |       } | ||
| 342 |     } | ||
| 343 |   } | ||
| 344 | } | ||
| 345 | |||
| 346 | /* last modified 02/22/14 */ | ||
| 347 | /* | ||
| 348 |  ******************************************************************************* | ||
| 349 |  *                                                                             * | ||
| 350 |  *   HashStorePV() is called by Iterate() to insert the PV moves so they will  * | ||
| 351 |  *   be searched before any other moves.  Normally the PV moves would be in    * | ||
| 352 |  *   the table, but on occasion they can be overwritten, particularly the ones * | ||
| 353 |  *   that are a significant distance from the root since those table entries   * | ||
| 354 |  *   will have a low draft.                                                    * | ||
| 355 |  *                                                                             * | ||
| 356 |  ******************************************************************************* | ||
| 357 |  */ | ||
| 358 | void HashStorePV(TREE * RESTRICT tree, int side, int ply) { | ||
| 359 | HASH_ENTRY *htable, *replace; | ||
| 360 | uint64_t temp_hashkey, word1; | ||
| 361 | int entry, draft, replace_draft, age; | ||
| 362 | |||
| 363 | /* | ||
| 364 |  ************************************************************ | ||
| 365 |  *                                                          * | ||
| 366 |  *  First, compute the initial hash address and the fake    * | ||
| 367 |  *  entry we will store if we don't find a valid match      * | ||
| 368 |  *  already in the table.                                   * | ||
| 369 |  *                                                          * | ||
| 370 |  ************************************************************ | ||
| 371 |  */ | ||
| 372 | temp_hashkey = (side) ? HashKey : ~HashKey; | ||
| 373 | word1 = transposition_age; | ||
| 374 | word1 = (word1 << 2) | WORTHLESS; | ||
| 375 | word1 = (word1 << 21) | tree->pv[0].path[ply]; | ||
| 376 | word1 = (word1 << 32) | 65536; | ||
| 377 | /* | ||
| 378 |  ************************************************************ | ||
| 379 |  *                                                          * | ||
| 380 |  *  Now we search for an entry to overwrite in three        * | ||
| 381 |  *  passes.                                                 * | ||
| 382 |  *                                                          * | ||
| 383 |  *  Pass 1:  If any signature in the table matches the      * | ||
| 384 |  *    current signature, we are going to overwrite this     * | ||
| 385 |  *    entry, period.  It might seem worthwhile to check the * | ||
| 386 |  *    draft and not overwrite if the table draft is greater * | ||
| 387 |  *    than the current remaining depth, but after you think * | ||
| 388 |  *    about it, this is a bad idea.  If the draft is        * | ||
| 389 |  *    greater than or equal the current remaining depth,    * | ||
| 390 |  *    then we should never get here unless the stored bound * | ||
| 391 |  *    or score is unusable because of the current alpha/    * | ||
| 392 |  *    beta window.  So we are overwriting to avoid losing   * | ||
| 393 |  *    the current result.                                   * | ||
| 394 |  *                                                          * | ||
| 395 |  *  Pass 2:  If any of the entries come from a previous     * | ||
| 396 |  *    search (not iteration) then we choose the entry from  * | ||
| 397 |  *    this set that has the smallest draft, since it is the * | ||
| 398 |  *    least potentially usable result.                      * | ||
| 399 |  *                                                          * | ||
| 400 |  *  Pass 3:  If neither of the above two found an entry to  * | ||
| 401 |  *    overwrite, we simply choose the entry from the bucket * | ||
| 402 |  *    with the smallest draft and overwrite that.           * | ||
| 403 |  *                                                          * | ||
| 404 |  ************************************************************ | ||
| 405 |  */ | ||
| 406 | htable = trans_ref + (temp_hashkey & hash_mask); | ||
| 407 | for (entry = 0; entry < 4; entry++, htable++) { | ||
| 408 | if ((htable->word2 ^ htable->word1) == temp_hashkey) { | ||
| 409 | htable->word1 &= ~((uint64_t) 0x1fffff << 32); | ||
| 410 | htable->word1 |= (uint64_t) tree->pv[0].path[ply] << 32; | ||
| 411 | htable->word2 = temp_hashkey ^ htable->word1; | ||
| 412 | break; | ||
| 413 |     } | ||
| 414 |   } | ||
| 415 | if (entry == 4) { | ||
| 416 | htable = trans_ref + (temp_hashkey & hash_mask); | ||
| 417 | replace = 0; | ||
| 418 | replace_draft = 99999; | ||
| 419 | for (entry = 0; entry < 4; entry++, htable++) { | ||
| 420 | age = htable->word1 >> 55; | ||
| 421 | draft = (htable->word1 >> 17) & 0x7fff; | ||
| 422 | if (age != transposition_age && replace_draft > draft) { | ||
| 423 | replace = htable; | ||
| 424 | replace_draft = draft; | ||
| 425 |       } | ||
| 426 |     } | ||
| 427 | if (!replace) { | ||
| 428 | htable = trans_ref + (temp_hashkey & hash_mask); | ||
| 429 | for (entry = 0; entry < 4; entry++, htable++) { | ||
| 430 | draft = (htable->word1 >> 17) & 0x7fff; | ||
| 431 | if (replace_draft > draft) { | ||
| 432 | replace = htable; | ||
| 433 | replace_draft = draft; | ||
| 434 |         } | ||
| 435 |       } | ||
| 436 |     } | ||
| 437 | replace->word1 = word1; | ||
| 438 | replace->word2 = temp_hashkey ^ word1; | ||
| 439 |   } | ||
| 440 | } |