void State::makeMove(Move const & move) { FromTo const & fromTo = move.fromTo; movePiece(fromTo, &board); if (move.castle.from.file) { movePiece(move.castle, &board); } if (move.enPassCap.file) { getPieceRef(move.enPassCap, &board) = ' '; } if (move.promPiece) { getPieceRef(fromTo.to, &board) = makePiece(move.promPiece, turn); } turn = (State::WHITE == turn) ? State::BLACK : State::WHITE; }
//quiescence search int SimplePVSearch::qSearch(Board& board, SearchInfo& si) { if (stop(si)) { return 0; } if (board.isDraw() || si.ply >= maxSearchPly-1) { return drawScore; } TranspositionTable::HashData hashData; MoveIterator::Move hashMove; const Key key = board.getKey(); bool okToPrune=false; const int oldAlpha=si.alpha; // tt retrieve & prunning const bool hashOk = si.nodeType == PV_NODE ? agent->hashGet(okToPrune, key, hashData, si.ply, si.depth) : agent->hashGet(okToPrune, key, hashData, si.ply, si.depth, si.allowNullMove, si.alpha, si.beta); if (hashOk) { hashMove = hashData.move(); if (okToPrune) { return hashData.value(); } } const bool isKingAttacked = board.isInCheck(); bool isLazyEval = false; int bestScore = -maxScore; int currentScore = -maxScore; if (!isKingAttacked) { if (hashOk && (hashData.flag() & TranspositionTable::NODE_EVAL)) { currentScore = hashData.evalValue(); } else { currentScore=evaluator.evaluate(board,si.alpha,si.beta); isLazyEval = evaluator.isLazyEval(); } bestScore=currentScore; if(bestScore>=si.beta) { if (!hashOk && !isLazyEval) { const TranspositionTable::NodeFlag flag = TranspositionTable::NODE_EVAL; agent->hashPut(key,bestScore,currentScore,-maxSearchPly,si.ply,flag,emptyMove); } return bestScore; } const int delta = board.isPawnPromoting()?getDeltaMargin(si.depth)*2:getDeltaMargin(si.depth); if (bestScore < si.alpha - delta && !(si.nodeType==PV_NODE) && hashMove.none() && !isMateScore(si.beta)) { if (!hashOk && !isLazyEval) { const TranspositionTable::NodeFlag flag = TranspositionTable::NODE_EVAL; agent->hashPut(key,si.alpha,currentScore,-maxSearchPly,si.ply,flag,emptyMove); } return si.alpha; } if((si.nodeType==PV_NODE) && si.alpha<bestScore) { si.alpha = bestScore; } } int moveCounter=0; MoveIterator moves = MoveIterator(); MoveIterator::Move bestMove=emptyMove; MoveIterator::Move move; const PieceColor sideToMove = board.getSideToMove(); while (true) { move = selectMove<true>(board, moves, hashMove, si.ply, si.depth); if (move.none()) { break; } const bool isHashMove = move.type==MoveIterator::TT_MOVE; const bool passedPawn = isPawnPush(board,move.to); const bool pawnOn7thRank = move.promotionPiece!=EMPTY; const bool allowFutility = !isKingAttacked && !(si.nodeType==PV_NODE) && !isHashMove && !pawnOn7thRank; moveCounter++; if (move.promotionPiece==makePiece(sideToMove,ROOK) || move.promotionPiece==makePiece(sideToMove,BISHOP) ) { continue; } if (allowFutility) { if (si.depth < qsOnlyRecaptureDepth && move.to != si.move.to) { continue; } if (move.type==MoveIterator::BAD_CAPTURE) { continue; } } MoveBackup backup; board.doMove(move,backup); const bool givingCheck = board.setInCheck(board.getSideToMove()); if (move.promotionPiece==makePiece(sideToMove,KNIGHT) && !givingCheck) { board.undoMove(backup); continue; } if (allowFutility && !board.isPawnFinal() && !passedPawn && !givingCheck ) { const int gain = materialValues[backup.capturedPiece]; const int futilityScore = currentScore+gain+getFutilityMargin(); if (futilityScore<si.alpha) { if (futilityScore>bestScore) { bestScore=futilityScore; } board.undoMove(backup); continue; } } SearchInfo newSi(false,move,-si.beta,-si.alpha,si.depth-1, si.ply+1,si.nodeType,si.splitPoint); int score = -qSearch(board, newSi); board.undoMove(backup); if (stop(si)) { return 0; } nodes++; if( score >= si.beta ) { const TranspositionTable::NodeFlag flag = currentScore!=-maxScore && !isLazyEval? TranspositionTable::LOWER_EVAL:TranspositionTable::LOWER; agent->hashPut(key,score,currentScore,si.depth!=0?-1:0,si.ply,flag,move); return score; } if (score>bestScore) { bestScore=score; if( score>si.alpha ) { si.alpha = score; bestMove=move; } } } if (!moveCounter && isKingAttacked) { return -maxScore+si.ply; } TranspositionTable::NodeFlag flag; if (bestScore>oldAlpha) { flag = currentScore!=-maxScore && !isLazyEval? TranspositionTable::EXACT_EVAL:TranspositionTable::EXACT; } else { flag = currentScore!=-maxScore && !isLazyEval? TranspositionTable::UPPER_EVAL:TranspositionTable::UPPER; bestMove=emptyMove; } agent->hashPut(key,bestScore,currentScore,si.depth!=0?-1:0,si.ply,flag,bestMove); return bestScore; }