void hashWriteBestMove(const guint64 key, const gint depth, const gint eval, const Move move){ HashData * hd = &data[key % hSize]; guint64 hData; if(stopFlag == FALSE && parallelStopFlag == FALSE){ guint hdDepth = hashDepth(hd->data); if(hdDepth == 0) hFree --; hData = depth | (EXACT << 8) | (move << 16) | (((guint64)hOld) << 32) | (((guint64)eval) << 48); hd->key = key ^ hData; hd->data = hData; } }
void hashWrite(HashData* hd, const guint64 key, const gint depth, const gint eval, const guint flag, const Move move){ guint64 hData; gint hdDepth; if(stopFlag == FALSE && parallelStopFlag == FALSE){ hdDepth = hashDepth(hd->data); if(hdDepth <= depth || (gint)hashOld(hd->data) < hOld){ if(hdDepth == 0 || (gint)hashOld(hd->data) < hOld) hFree --; hData = depth | (flag << 8) | (move << 16) | (((guint64)hOld) << 32) | (((guint64)eval) << 48); hd->key = key ^ hData; hd->data = hData; } } }
gint threadSearch(Position* position, gint alpha, gint beta, gint depth, gint hight, const gboolean nullMove, const gboolean nodePV){ Moves moves; Move move, bestMove = Empty, hMove = Empty, pMove=Empty; gboolean extend=FALSE, endGamePhase; gint eval, tmpDepth, movesSearched = 0, pAlpha, pType; guint idleThreads; guint64 key = position->key, hData; HashData* hd; if(stopFlag == TRUE && !ponderSearch) return EVAL_DRAW; searchNodes++; /* Draw */ if(positionRepeat(position) >= 1 || position->staticMoves >= 100) return EVAL_DRAW; /* End game */ gint numberOfPieces = numberOfBits64(position->allPieces); if(numberOfPieces <= 5 && egbbIsLoaded()){ tmpDepth = (2 * iterativeDepth) / 3; if((numberOfPieces <= 4 || hight <= tmpDepth) && (hight >= tmpDepth || positionEvalEG(position))){ if(egbbProbe(position, &eval)){ if(eval < 0) return eval + hight * 40 + positionMaterial(position); if(eval > 0) return eval - hight * 40 + positionMaterial(position); return eval; } } } /* Mate distance pruning */ eval = -EVAL_MATE + hight; if(eval > alpha){ if(eval >= beta) return eval; alpha = eval; } eval = EVAL_MATE - hight; if(eval < beta){ if(eval <= alpha) return eval; beta = eval; } /* Hash */ if(hashFind(&hd,key,&hData)){ hMove = hashMove(hData); if(!nodePV && (gint)hashDepth(hData) >= depth){ if(hashFlag(hData) == EXACT) return hashEval(hData); else if(hashFlag(hData) == ALPHA && hashEval(hData) > alpha){ bestMove = hashMove(hData); alpha = hashEval(hData); if(alpha >= beta) return alpha; } else if(hashFlag(hData) == BETA && hashEval(hData) < beta){ beta = hashEval(hData); if(alpha >= beta) return beta; } } } /* Extension */ if(position->extend || (nodePV && passedPawnMove(position))){ depth ++; extend = TRUE; } /* Horizon */ if(depth < 1){ eval = quiescent(position,alpha,beta,hight+1,TRUE); return eval; } if(position->phase <= 7 && numberOfPieces <= 10) endGamePhase = TRUE; else endGamePhase = FALSE; /* Null move pruning */ if (!nodePV && nullMove && depth>2 && !extend && !endGamePhase){ if(depth > 6) tmpDepth = depth - 4; else tmpDepth = depth - 3; moveDo(position,Null_Move); eval = -threadSearch(position,-beta,-beta+1,tmpDepth,hight+1,FALSE,FALSE); moveUndo(position); if(eval >= beta){ hashWrite(hd,key,depth,eval,ALPHA,Empty); return eval; } } /* Internal Iterative Deepening */ tmpDepth = depth/2; if(nodePV && hMove == Empty && depth > 3 && tmpDepth >= (gint)hashDepth(hData)){ threadSearch(position,alpha, beta, tmpDepth, hight, FALSE,nodePV); if(hashFind2(hd,key,&hData)) hMove = hashMove(hData); } /* First move */ moves.state = START; if(hMove != Empty){ move = hMove; moveDo(position,move); } else move = nextMoveDo(position,&moves); if(move != Empty){ eval = -threadSearch(position, -beta, -alpha, depth-1, hight+1, TRUE,nodePV); if(eval > alpha){ if(eval >= beta){ moveUndo(position); if(moves.state == STATIC) history[moveGetFrom(move)][moveGetTo(move)] += 1<<depth; hashWrite(hd,key,depth,eval,ALPHA,move); return eval; } alpha = eval; bestMove = move; } moveUndo(position); movesSearched ++; } /* Parallel search*/ idleThreads = searchThreads; while(TRUE){ if(idleThreads > 0){ move = nextMoveDo(position,&moves); /* Last moves searched sequential */ if(move == Empty){ parallelStopFlag = TRUE; moves.size = moves.next = 0; while(idleThreads != searchThreads){ parallelSearchResult(&pMove,&pAlpha,&pType); idleThreads++; moves.move[moves.size] = pMove; moves.size ++; } parallelStopFlag = FALSE; moves.toSort = moves.size; break; } /* History pruning */ if(!nodePV && movesSearched >= HistoryFullDepthMoves && depth > HistoryReductionLimit && !extend && !position->extend){ idleThreads--; parallelSearch(position, move, -(alpha+1), -alpha, depth-2, hight+1,TRUE,HP,FALSE); moveUndo(position); movesSearched ++; } else{ /* PVS */ idleThreads--; parallelSearch(position, move, -(alpha+1), -alpha, depth-1, hight+1,TRUE,PVS,FALSE); moveUndo(position); movesSearched ++; } } else{ eval = -parallelSearchResult(&pMove,&pAlpha,&pType); idleThreads++; pAlpha = -pAlpha - 1; if(pType == HP && eval > pAlpha){ /* HP */ idleThreads--; moveDo(position,pMove); parallelSearch(position, pMove, -(pAlpha+1), -pAlpha, depth-1, hight+1,TRUE,PVS,FALSE); moveUndo(position); continue; } if(pType == PVS && eval > pAlpha && eval < beta){ /* PVS research */ idleThreads--; moveDo(position,pMove); parallelSearch(position, pMove, -beta, -pAlpha, depth-1, hight+1,TRUE,RPVS,nodePV); moveUndo(position); continue; } if(eval > alpha){ if(eval >= beta){ parallelSearchStop(idleThreads); if(moveGetType(pMove) == Normal) history[moveGetFrom(pMove)][moveGetTo(pMove)] += 1<<depth; hashWrite(hd,key,depth,eval,ALPHA,pMove); return eval; } alpha = eval; bestMove = pMove; } } } /* Last moves searched sequential */ move = nextMoveDo(position,&moves); while(move != Empty){ /* History pruning */ if(!nodePV && movesSearched >= HistoryFullDepthMoves && depth > HistoryReductionLimit && !extend && !position->extend){ eval = -threadSearch(position, -(alpha+1), -alpha, depth-2, hight+1, TRUE, FALSE); } else eval = alpha + 1; /* PVS */ if(eval > alpha){ eval = -threadSearch(position, -(alpha+1), -alpha, depth-1, hight+1, TRUE, FALSE); if(eval > alpha && eval < beta) eval = -threadSearch(position, -beta, -alpha, depth-1, hight+1, TRUE, nodePV); } moveUndo(position); if(eval > alpha){ if(eval >= beta){ if(moveGetType(pMove) == Normal) history[moveGetFrom(move)][moveGetTo(move)] += 1<<depth; hashWrite(hd,key,depth,eval,ALPHA,move); return eval; } alpha = eval; bestMove = move; } movesSearched ++; move = nextMoveDo(position,&moves); } /* Mate or pat */ if(movesSearched == 0){ if(position->inCheck == TRUE){ eval = -EVAL_MATE+hight; hashWrite(hd,key,depth,eval,EXACT,Empty); return eval; } else{ hashWrite(hd,key,depth,EVAL_DRAW,EXACT,Empty); return EVAL_DRAW; } } /* hash is update */ if(bestMove != Empty) hashWrite(hd,key,depth,alpha,EXACT,bestMove); else hashWrite(hd,key,depth,alpha,BETA,hMove); return alpha; }