/*++ Copyright (c) Scott Gasch Module Name: evalhash.c Abstract: Evaluation score hashing code. Author: Scott Gasch (scott.gasch@gmail.com) 11 Jul 2006 Revision History: --*/ #include "chess.h" #ifdef EVAL_HASH extern ULONG g_uIterateDepth; SCORE GetRoughEvalScore(IN OUT SEARCHER_THREAD_CONTEXT *ctx, IN SCORE iAlpha, IN SCORE iBeta, IN FLAG fUseHash) /*++ Routine description: This is meant to be the "one place" that code looks when it needs to get an idea of the estimated evaluation of a position (in mid tree, not at the leaves... at the leaves just call Eval directly). The thought is that: 1. The top of the tree (near the root) represents very few nodes which have big subtrees. Use the real Eval here. 2. Otherwise possibly probe the eval hash -- if there's a score in it then we can return quickly. 3. Otherwise do a (very) rough material estimate. Parameters: IN OUT SEARCHER_THREAD_CONTEXT *ctx, IN SCORE iAlpha, IN SCORE iBeta, IN FLAG fUseHash Return value: SCORE --*/ { POSITION *pos = &(ctx->sPosition); UINT64 u64Key; ULONG u; if (ctx->uPly <= 4) { return Eval(ctx, iAlpha, iBeta); } else if ((fUseHash) || (ctx->uPly <= (g_uIterateDepth / 2))) { u64Key = (pos->u64PawnSig ^ pos->u64NonPawnSig); u = (ULONG)u64Key & (EVAL_HASH_TABLE_SIZE - 1); if (ctx->rgEvalHash[u].u64Key == u64Key) { switch(ctx->rgEvalHash[u].bvFlags) { case EVAL_HASH_EXACT: ctx->uPositional = ctx->rgEvalHash[u].uPositional; return(ctx->rgEvalHash[u].iEval); case EVAL_HASH_UPPER: if (ctx->rgEvalHash[u].iBound <= iAlpha) { return(ctx->rgEvalHash[u].iEval); } break; case EVAL_HASH_LOWER: if (ctx->rgEvalHash[u].iBound >= iBeta) { return(ctx->rgEvalHash[u].iEval); } break; } } } return(pos->iMaterialBalance[pos->uToMove] + ctx->uPositional); } SCORE ProbeEvalHash(IN OUT SEARCHER_THREAD_CONTEXT *ctx, IN SCORE iAlpha, IN SCORE iBeta) /*++ Routine description: Probe the eval hash; return a real score if there's a hit otherwise return INVALID_SCORE. An EXACT entry is always usable. An UPPER/LOWER entry (recorded from a lazy-eval early exit) is only usable if the bound it proved still resolves the caller's current alpha/beta window; otherwise it's treated as a miss and the caller must actually compute something. Parameters: IN OUT SEARCHER_THREAD_CONTEXT *ctx : note that in the case of a hit, *ctx is modified also. IN SCORE iAlpha, IN SCORE iBeta : caller's current window Return value: SCORE --*/ { POSITION *pos = &(ctx->sPosition); UINT64 u64Key = (pos->u64PawnSig ^ pos->u64NonPawnSig); ULONG u = (ULONG)u64Key & (EVAL_HASH_TABLE_SIZE - 1); if (ctx->rgEvalHash[u].u64Key == u64Key) { switch(ctx->rgEvalHash[u].bvFlags) { case EVAL_HASH_EXACT: ctx->uPositional = ctx->rgEvalHash[u].uPositional; pos->cTrapped[WHITE] = ctx->rgEvalHash[u].cTrapped[WHITE]; pos->cTrapped[BLACK] = ctx->rgEvalHash[u].cTrapped[BLACK]; return(ctx->rgEvalHash[u].iEval); case EVAL_HASH_UPPER: if (ctx->rgEvalHash[u].iBound <= iAlpha) { return(ctx->rgEvalHash[u].iEval); } break; case EVAL_HASH_LOWER: if (ctx->rgEvalHash[u].iBound >= iBeta) { return(ctx->rgEvalHash[u].iEval); } break; } } return(INVALID_SCORE); } void StoreEvalHash(IN OUT SEARCHER_THREAD_CONTEXT *ctx, IN SCORE iScore, IN SCORE iBound, IN UCHAR bvFlags) /*++ Routine description: Store a score in the eval hash table (which is pointed to indirectly via ctx). bvFlags is EVAL_HASH_EXACT for a fully computed eval (iBound ignored) or EVAL_HASH_UPPER/EVAL_HASH_LOWER for a bound proven by a lazy-eval early exit (iScore is the uncorrected partial score that would be returned, iBound is the proven bound on the true eval). Parameters: SEARCHER_THREAD_CONTEXT *ctx, SCORE iScore, SCORE iBound, UCHAR bvFlags Return value: void --*/ { POSITION *pos = &(ctx->sPosition); UINT64 u64Key = (pos->u64PawnSig ^ pos->u64NonPawnSig); ULONG u = (ULONG)u64Key & (EVAL_HASH_TABLE_SIZE - 1); ctx->rgEvalHash[u].u64Key = u64Key; ctx->rgEvalHash[u].iEval = iScore; ctx->rgEvalHash[u].iBound = iBound; ctx->rgEvalHash[u].bvFlags = bvFlags; if (bvFlags == EVAL_HASH_EXACT) { ctx->rgEvalHash[u].uPositional = ctx->uPositional; ctx->rgEvalHash[u].cTrapped[WHITE] = pos->cTrapped[WHITE]; ctx->rgEvalHash[u].cTrapped[BLACK] = pos->cTrapped[BLACK]; } } #endif // EVAL_HASH