void hashCollectPV(Position* position, Move pv[]){ HashData* hd; guint64 hData; guint index = 0; while(hashFind(&hd,position->key,&hData)){ if(index < Max_Pv-1 && hashMove(hData) != Empty){ pv[index] = hashMove(hData); moveDo(position,pv[index]); index++; } else break; } pv[index] = Empty; while(index>0){ moveUndo(position); index--; } }
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; }
gboolean moveDo(Position* position, const Move move){ History* history = &position->history[position->ply]; history->move = move; history->key = position->key; history->capture = position->capture; history->staticMoves = position->staticMoves; history->enPassant = position->enPassant; history->castle = position->castle; history->inCheck = position->inCheck; history->material[White] = position->material[White]; history->material[Black] = position->material[Black]; history->pvt[Opening] = position->pvt[Opening]; history->pvt[Endgame] = position->pvt[Endgame]; history->extend = position->extend; history->phase = position->phase; #ifndef G_DISABLE_ASSERT if(move != Null_Move && position->type[moveGetFrom(move)]%2 != position->turn){ positionPrint(position); g_printf("Wrong move ("); movePrint(move); g_printf(")\n"); g_error("!!\n"); } #endif if(position->enPassant != 0){ position->key ^= enPassantKey[file(position->enPassant)]; position->enPassant = 0; } position->capture = Empty; position->extend = FALSE; position->staticMoves ++; switch(moveGetType(move)){ case Normal: { normalMoveDo(position, move); break;} case Capture: { captureMoveDo(position, move); break;} case En_Passant:{ enPassantMoveDo(position, move); break;} case Castle: { if(!castleMoveDo(position,move)){ position->enPassant = history->enPassant; position->capture = history->capture; position->extend = history->extend; position->staticMoves--; #ifndef G_DISABLE_ASSERT positionIsOk(position); #endif return FALSE; }else{ position->turn ^= 1; position->key ^= turnKey; position->ply++; position->inCheck = positionIsInCheck(position); /* Speed up (rook only)*/ if(position->inCheck) position->extend = TRUE; #ifndef G_DISABLE_ASSERT positionIsOk(position); #endif return TRUE; } } case Promote_Queen: { promoteMoveDo(position,move,Queen); break;} case Promote_Rook: { promoteMoveDo(position,move,Rook); break;} case Promote_Bishop: { promoteMoveDo(position,move,Bishop); break;} case Promote_Knight: { promoteMoveDo(position,move,Knight); break;} case Null_Move: { position->turn ^= 1; position->key ^= turnKey; position->ply++; position->staticMoves = 0; #ifndef G_DISABLE_ASSERT positionIsOk(position); #endif return TRUE; } default: { g_error("Wrong move type!\n"); } }; position->turn ^= 1; position->key ^= turnKey; position->ply++; if(!positionGood(position)){ moveUndo(position); return FALSE; } position->inCheck = positionIsInCheck(position); /* Speed up */ if(position->inCheck) position->extend = TRUE; #ifndef G_DISABLE_ASSERT positionIsOk(position); #endif return TRUE; }