private static void DoSearch() { var fen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"; // Starting pos //fen = "2rr3k/pp3pp1/1nnqbN1p/3pN3/2pP4/2P3Q1/PPB4P/R4RK1 w - -"; // Mate in 3 fen = "r1b1k2r/ppppnppp/2n2q2/2b5/3NP3/2P1B3/PP3PPP/RN1QKB1R w KQkq - 0 1"; // Developed fen = "r1b1kb1r/2pp1ppp/1np1q3/p3P3/2P5/1P6/PB1NQPPP/R3KB1R b KQkq - 0 1 "; // Midgame var fact = new BoardFactory(); var board = fact.ParseFEN(fen); var hyperbola = new HyperbolaQuintessence(); var evaluationService = new EvaluationService(); var attacksService = new AttacksService(hyperbola); var movesService = new PossibleMovesService(attacksService, hyperbola); var interruptor = new ConsoleInterruptor(); var searchService = new SearchService(movesService, evaluationService, interruptor); searchService.OnSearchInfo += info => Console.WriteLine(info.ToString()); var sParams = new SearchParams(); //sParams.MaxDepth = 5; sParams.Infinite = true; var move = searchService.Search(board, sParams); }
public SearchService(PossibleMovesService possibleMovesService, IEvaluationService evaluationService, IInterruptor interruptor) { PossibleMovesService = possibleMovesService; EvaluationService = evaluationService; Interruptor = interruptor; TTable = new TranspositionTable <SearchTTEntry>(26); }
public Game(IInterruptor interruptor) { var hyperbola = new HyperbolaQuintessence(); var evaluationService = new EvaluationService(); var attacksService = new AttacksService(hyperbola); var movesService = new PossibleMovesService(attacksService, hyperbola); var searchService = new SearchService(movesService, evaluationService, interruptor); BoardFact = new BoardFactory(); Hyperbola = hyperbola; Evaluation = evaluationService; Attacks = attacksService; Moves = movesService; Search = searchService; }
private static void TestRepetitions() { var fen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"; // Starting pos //fen = "2rr3k/pp3pp1/1nnqbN1p/3pN3/2pP4/2P3Q1/PPB4P/R4RK1 w - -"; // Mate in 3 fen = "r1b1k2r/ppppnppp/2n2q2/2b5/3NP3/2P1B3/PP3PPP/RN1QKB1R w KQkq - 0 1"; // Developed var fact = new BoardFactory(); var board = fact.ParseFEN(fen); var hyperbola = new HyperbolaQuintessence(); var evaluationService = new EvaluationService(); var attacksService = new AttacksService(hyperbola); var movesService = new PossibleMovesService(attacksService, hyperbola); var interruptor = new ConsoleInterruptor(); var searchService = new SearchService(movesService, evaluationService, interruptor); Console.WriteLine(searchService.IsRepetition(board)); var move = new Move(1, 18, ChessPiece.WhiteKnight); board = board.DoMove(move); Console.WriteLine(move.ToPositionString() + " " + searchService.IsRepetition(board)); move = new Move(57, 42, ChessPiece.BlackKnight); board = board.DoMove(move); Console.WriteLine(move.ToPositionString() + " " + searchService.IsRepetition(board)); move = new Move(18, 1, ChessPiece.WhiteKnight); board = board.DoMove(move); Console.WriteLine(move.ToPositionString() + " " + searchService.IsRepetition(board)); move = new Move(42, 57, ChessPiece.BlackKnight); board = board.DoMove(move); Console.WriteLine(move.ToPositionString() + " " + searchService.IsRepetition(board)); move = new Move(1, 18, ChessPiece.WhiteKnight); board = board.DoMove(move); Console.WriteLine(move.ToPositionString() + " " + searchService.IsRepetition(board)); move = new Move(57, 40, ChessPiece.BlackKnight); board = board.DoMove(move); Console.WriteLine(move.ToPositionString() + " " + searchService.IsRepetition(board)); }
private IEnumerable <string> GetPossibleMovesInner(Board board, int depth, int currentDepth, string currentString) { var moves = PossibleMovesService.GetAllPossibleMoves(board); foreach (var move in moves) { var moveString = currentString + (currentString.Length == 0 ? string.Empty : " ") + move.ToPositionString(); if (currentDepth >= depth) { yield return(moveString); } else { var movedBoard = board.DoMove(move); foreach (var otherBoards in GetPossibleMovesInner(movedBoard, depth, currentDepth + 1, moveString)) { yield return(otherBoards); } } } }
private static void DoPerft() { var fen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"; //fen = "3k4/3p4/8/K1P4r/8/8/8/8 b - - 0 50"; //fen = "8/1kP5/8/K2p3r/8/8/8/8 w - - 1 53 "; //fen = "r1b1k2r/ppppnppp/2n2q2/2b5/3NP3/2P1B3/PP3PPP/RN1QKB1R w KQkq - 0 1"; //fen = "2k5/8/8/8/8/8/6p1/2K5 w - - 1 1 "; //fen = "rnbqkbnr/1ppppppp/8/p7/1P6/P7/2PPPPPP/RNBQKBNR b KQkq b3 0 2 "; var fact = new BoardFactory(); var hyperbola = new HyperbolaQuintessence(); var attacksService = new AttacksService(hyperbola); var movesService = new PossibleMovesService(attacksService, hyperbola); var perft = new PerftService(movesService); var results = perft.GetPossibleMoves(fact.ParseFEN(fen), 1); using (var sharperClient = new SharperPerftClient(@"C:\sharper\Sharper.exe", fen)) { var perftRunner = new PerftRunner(perft, sharperClient, fact); perftRunner.OnOut += Console.Write; perftRunner.Test(fen, 6); } }
private static void TestMove() { var fact = new BoardFactory(); var board = fact.ParseFEN("r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq -"); board.EnPassantFile = Board.Files[3]; var hyperbola = new HyperbolaQuintessence(); var evaluationService = new EvaluationService(); Console.WriteLine(evaluationService.Evaluate(board)); var attacksService = new AttacksService(hyperbola); var movesService = new PossibleMovesService(attacksService, hyperbola); var forWhite = true; var moves = movesService.GetPossibleKingMoves(board).ToList(); var dests = moves.Select(x => x.To); var toMoveBoard = fact.PiecesToBitBoard(dests); var attacked = attacksService.GetAllAttacked(board); var newMove = new Move(4, 2, ChessPiece.WhiteKing); var movedBoard = board.DoMove(newMove); Debugging.ShowBitBoard(movedBoard.BitBoard[ChessPiece.WhiteKing], movedBoard.BitBoard[ChessPiece.WhiteRook]); }
public int GetPossibleMoveCountInner(Board board, int depth, int currentDepth) { var currentNum = 0; var moves = PossibleMovesService.GetAllPossibleMoves(board); if (currentDepth >= depth) { currentNum = moves.Count; } else { if (currentDepth == 1) { var sync = new object(); Parallel.ForEach(moves, m => { var movedBoard = board.DoMove(m); var possibleMoveCountInner = GetPossibleMoveCountInner(movedBoard, depth, currentDepth + 1); lock (sync) { currentNum += possibleMoveCountInner; } }); } else { foreach (var move in moves) { var movedBoard = board.DoMove(move); var possibleMoveCountInner = GetPossibleMoveCountInner(movedBoard, depth, currentDepth + 1); currentNum += possibleMoveCountInner; } } } return(currentNum); }
public IList <MoveAndNodes> Divide(Board board, int depth) { var moves = PossibleMovesService.GetAllPossibleMoves(board); if (depth == 1) { return(moves.Select(x => new MoveAndNodes(x.ToPositionString(), 1)).OrderBy(x => x.Move).ToList()); } var results = new List <MoveAndNodes>(); Action <Move> act = m => { var moved = board.DoMove(m); var count = GetPossibleMoveCountInner(moved, depth, 2); var posStr = m.ToPositionString(); var man = new MoveAndNodes(posStr, count, m); lock (results) { results.Add(man); } }; if (MultiThreaded) { Parallel.ForEach(moves, act); } else { foreach (var move in moves) { act.Invoke(move); } } var ordered = results.OrderBy(x => x.Move).ToList(); return(ordered); }
public PerftService(PossibleMovesService possibleMovesService) { PossibleMovesService = possibleMovesService; MultiThreaded = true; }
public int Quiessence(int alpha, int beta, Board board, int currentDepth) { #if TEST Test.Assert(beta > alpha); board.CheckBoard(); #endif if ((NodesSearched & 2047) == 0) { if (Interruptor.IsInterrupted()) { Stopped = true; return(0); } } NodesSearched++; var isRepetition = IsRepetition(board); if (isRepetition) { return(0); } if (board.History.Length - board.LastTookPieceHistoryIndex >= 100) { return(0); } if (currentDepth >= MaxDepth) { return(EvaluationService.Evaluate(board)); } int score = EvaluationService.Evaluate(board); if (score >= beta) { return(beta); } if (score > alpha) { alpha = score; } var potentialMoves = PossibleMovesService.GetAllPotentialMoves(board).Where(x => x.TakesPiece > 0).ToList(); var oldAlpha = alpha; var validMoves = 0; Move?bestMove = null; var bestScore = -Inf; score = -Inf; for (var i = 0; i < potentialMoves.Count; i++) { SortNextMove(i, board, potentialMoves, currentDepth, null); var potentialMove = potentialMoves[i]; var bbAfter = PossibleMovesService.DoMoveIfKingSafe(board, potentialMove); if (bbAfter == null) { continue; } validMoves++; score = -Quiessence(-beta, -alpha, bbAfter, currentDepth + 1); if (Stopped) { return(0); } if (score > alpha) { if (score >= beta) { #if TEST if (validMoves == 1) { FailHighFirst++; } FailHigh++; #endif return(beta); } alpha = score; } } #if TEST Test.Assert(alpha >= oldAlpha); Test.Assert(alpha < Inf); Test.Assert(alpha > -Inf); #endif return(alpha); }
public int PrincipalVariationSearch(int alpha, int beta, Board board, int depth, int currentDepth, bool allowNullMoveSearch) { #if TEST Test.Assert(beta > alpha); Test.Assert(depth >= 0); board.CheckBoard(); #endif if ((NodesSearched & 2047) == 0) { if (Interruptor.IsInterrupted()) { Stopped = true; return(0); } } NodesSearched++; var isRepetition = IsRepetition(board); if (isRepetition && currentDepth > 0) { return(0); } if (board.History.Length - board.LastTookPieceHistoryIndex >= 100) { return(0); } if (currentDepth >= MaxDepth) { return(EvaluationService.Evaluate(board)); } if (depth <= 0) { // quiessence next return(Quiessence(alpha, beta, board, currentDepth)); } var enemyAttacks = PossibleMovesService.AttacksService.GetAllAttacked(board, !board.WhiteToMove); var myKing = board.WhiteToMove ? board.BitBoard[ChessPiece.WhiteKing] : board.BitBoard[ChessPiece.BlackKing]; var inCheck = (enemyAttacks & myKing) != 0; if (inCheck) { depth++; } int score = -Inf; Move?pvMove = null; SearchTTEntry foundEntry; var found = TTable.TryGet(board.Key, out foundEntry); if (found && foundEntry.Key == board.Key) { pvMove = foundEntry.Move; if (foundEntry.Depth >= depth) { switch (foundEntry.Flag) { case SearchTTFlags.Beta: return(beta); break; case SearchTTFlags.Exact: return(foundEntry.Score); break; case SearchTTFlags.Alpha: return(alpha); break; } } } const int nullMoveFactor = 2; if (allowNullMoveSearch && !inCheck && currentDepth > 0 && depth >= nullMoveFactor + 1) { var haveBigPiece = false; var pieceOffset = board.WhiteToMove ? 1 : 7; for (var i = 1; i < 5; i++) { if (board.PieceCounts[pieceOffset + i] > 0) { haveBigPiece = true; break; } } if (haveBigPiece) { var nullMove = new Move(0, 0, 0); var nullBoard = board.DoMove(nullMove); score = -PrincipalVariationSearch(-beta, -beta + 1, nullBoard, depth - nullMoveFactor - 1, currentDepth + 1, false); if (Stopped) { return(0); } if (score >= beta && score > -MateThereshold && score < MateThereshold) { NullMoveCutOffs++; return(beta); } } } var potentialMoves = PossibleMovesService.GetAllPotentialMoves(board); var oldAlpha = alpha; var validMoves = 0; Move?bestMove = null; var bestScore = -Inf; score = -Inf; var bbsAfter = new Board[potentialMoves.Count]; for (var i = 0; i < potentialMoves.Count; i++) { SortNextMove(i, board, potentialMoves, currentDepth, pvMove); var potentialMove = potentialMoves[i]; var bbAfter = PossibleMovesService.DoMoveIfKingSafe(board, potentialMove); if (bbAfter == null) { continue; } bbsAfter[i] = bbAfter; validMoves++; score = -PrincipalVariationSearch(-beta, -alpha, bbAfter, depth - 1, currentDepth + 1, true); if (Stopped) { return(0); } if (score > bestScore) { bestScore = score; bestMove = potentialMove; if (score > alpha) { if (score >= beta) { #if TEST if (validMoves == 1) { FailHighFirst++; } FailHigh++; #endif if (potentialMove.TakesPiece == 0) { SearchKillers[currentDepth, 1] = SearchKillers[currentDepth, 0]; SearchKillers[currentDepth, 0] = potentialMove.Key; } var entry = new SearchTTEntry(board.Key, bestMove.Value, beta, SearchTTFlags.Beta, depth); TTable.Add(board.Key, entry); return(beta); } alpha = score; if (potentialMove.TakesPiece == 0) { SearchHistory[potentialMove.Piece, potentialMove.To] += depth; } } } } if (validMoves == 0) { if (inCheck) { return(-MateScore + currentDepth); } else { return(0); } } #if TEST Test.Assert(alpha >= oldAlpha); #endif if (alpha != oldAlpha) { var entry = new SearchTTEntry(board.Key, bestMove.Value, bestScore, SearchTTFlags.Exact, depth); TTable.Add(board.Key, entry); //PVTable[currentDepth] = new PVSResult(alpha, bbsAfter[bestMove], potentialMoves[bestMove]); } else { var entry = new SearchTTEntry(board.Key, bestMove.Value, alpha, SearchTTFlags.Alpha, depth); TTable.Add(board.Key, entry); } return(alpha); }