// Load custom position from fen string public void LoadPosition(string fen) { Initialize(); var loadedPosition = FenUtility.PositionFromFen(fen); // Load pieces into board array and piece lists for (int squareIndex = 0; squareIndex < 64; squareIndex++) { int piece = loadedPosition.squares[squareIndex]; Square[squareIndex] = piece; if (piece != Piece.None) { int pieceType = Piece.PieceType(piece); int pieceColourIndex = (Piece.IsColour(piece, Piece.White)) ? WhiteIndex : BlackIndex; if (Piece.IsSlidingPiece(piece)) { if (pieceType == Piece.Queen) { queens[pieceColourIndex].AddPieceAtSquare(squareIndex); } else if (pieceType == Piece.Rook) { rooks[pieceColourIndex].AddPieceAtSquare(squareIndex); } else if (pieceType == Piece.Bishop) { bishops[pieceColourIndex].AddPieceAtSquare(squareIndex); } } else if (pieceType == Piece.Knight) { knights[pieceColourIndex].AddPieceAtSquare(squareIndex); } else if (pieceType == Piece.Pawn) { pawns[pieceColourIndex].AddPieceAtSquare(squareIndex); } else if (pieceType == Piece.King) { KingSquare[pieceColourIndex] = squareIndex; } } } // Side to move WhiteToMove = loadedPosition.whiteToMove; ColourToMove = (WhiteToMove) ? Piece.White : Piece.Black; OpponentColour = (WhiteToMove) ? Piece.Black : Piece.White; ColourToMoveIndex = (WhiteToMove) ? 0 : 1; // Create gamestate int whiteCastle = ((loadedPosition.whiteCastleKingside) ? 1 << 0 : 0) | ((loadedPosition.whiteCastleQueenside) ? 1 << 1 : 0); int blackCastle = ((loadedPosition.blackCastleKingside) ? 1 << 2 : 0) | ((loadedPosition.blackCastleQueenside) ? 1 << 3 : 0); int epState = loadedPosition.epFile << 4; ushort initialGameState = (ushort)(whiteCastle | blackCastle | epState); gameStateHistory.Push(initialGameState); currentGameState = initialGameState; plyCount = loadedPosition.plyCount; // Initialize zobrist key ZobristKey = Zobrist.CalculateZobristKey(this); }
public void StartSearch() { InitDebugInfo(); // Initialize search settings bestEvalThisIteration = bestEval = 0; bestMoveThisIteration = bestMove = Move.InvalidMove; tt.enabled = settings.useTranspositionTable; // Clearing the transposition table before each search seems to help // This makes no sense to me, I presume there is a bug somewhere but haven't been able to track it down yet if (settings.clearTTEachMove) { tt.Clear(); } moveGenerator.promotionsToGenerate = settings.promotionsToSearch; currentIterativeSearchDepth = 0; abortSearch = false; searchDiagnostics = new SearchDiagnostics(); // Iterative deepening. This means doing a full search with a depth of 1, then with a depth of 2, and so on. // This allows the search to be aborted at any time, while still yielding a useful result from the last search. if (settings.useIterativeDeepening) { var targetDepth = settings.useFixedDepthSearch ? settings.depth : int.MaxValue; for (var searchDepth = 1; searchDepth <= targetDepth; searchDepth++) { SearchMoves(searchDepth, 0, negativeInfinity, positiveInfinity); if (abortSearch) { break; } currentIterativeSearchDepth = searchDepth; bestMove = bestMoveThisIteration; bestEval = bestEvalThisIteration; // Update diagnostics searchDiagnostics.lastCompletedDepth = searchDepth; searchDiagnostics.move = bestMove.Name; searchDiagnostics.eval = bestEval; searchDiagnostics.moveVal = PGNCreator.NotationFromMove(FenUtility.CurrentFen(board), bestMove); // Exit search if found a mate if (IsMateScore(bestEval) && !settings.endlessSearchMode) { break; } } } else { SearchMoves(settings.depth, 0, negativeInfinity, positiveInfinity); bestMove = bestMoveThisIteration; bestEval = bestEvalThisIteration; } onSearchComplete?.Invoke(bestMove); if (!settings.useThreading) { LogDebugInfo(); } }