예제 #1
0
        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);
        }
예제 #2
0
 public SearchService(PossibleMovesService possibleMovesService, IEvaluationService evaluationService, IInterruptor interruptor)
 {
     PossibleMovesService = possibleMovesService;
     EvaluationService    = evaluationService;
     Interruptor          = interruptor;
     TTable = new TranspositionTable <SearchTTEntry>(26);
 }
예제 #3
0
        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;
        }
예제 #4
0
        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));
        }
예제 #5
0
        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);
                    }
                }
            }
        }
예제 #6
0
        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);
            }
        }
예제 #7
0
        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]);
        }
예제 #8
0
        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);
        }
예제 #9
0
        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);
        }
예제 #10
0
 public PerftService(PossibleMovesService possibleMovesService)
 {
     PossibleMovesService = possibleMovesService;
     MultiThreaded        = true;
 }
예제 #11
0
        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);
        }
예제 #12
0
        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);
        }