示例#1
0
        public static long Qdivide(ChessBoard chessBoard, int depth)
        {
            ThreadData.StartPly();
            MoveGenerator.GenerateMoves(ThreadData, chessBoard);
            long counter = 0;

            while (ThreadData.HasNext())
            {
                var move = ThreadData.Next();
                if (depth == 1)
                {
                    Console.WriteLine(new MoveWrapper(move) + ": " + 1);
                    counter++;
                    continue;
                }

                chessBoard.DoMove(move);
                var divideCounter = Qperft(chessBoard, depth - 1);
                counter += divideCounter;
                chessBoard.UndoMove(move);
                Console.WriteLine(new MoveWrapper(move) + ": " + divideCounter);
            }

            return(counter);
        }
示例#2
0
        public static void PerftDivide(Board b, int depth)
        {
            var startTime = DateTime.Now;
            var moves     = MoveGenerator.GenerateMoves(b, true);
            int total     = 0;
            int i         = 0;
            int moveCount = 0;

            foreach (var m in moves)
            {
                if (!b.MakeMove(m))
                {
                    continue;
                }
                i++;
                var nodes = Perft(b, depth - 1);

                moveCount++;
                total += nodes;
                b.UnMakeMove();
                Console.WriteLine(String.Format("{0}: {1}", m.ToAlegbraicNotation(b), nodes));
            }
            Console.WriteLine("Moves: {0}", moveCount);
            Console.WriteLine("Total: {0}", total);
            var endTime = DateTime.Now;

            Console.WriteLine("Completed in {0}ms", (endTime - startTime).TotalMilliseconds);
        }
示例#3
0
        private static int perft(ChessBoard cb, ThreadData threadData, int depth)
        {
            threadData.StartPly();
            MoveGenerator.GenerateMoves(threadData, cb);
            MoveGenerator.GenerateAttacks(threadData, cb);

            if (depth == 0)
            {
                threadData.EndPly();
                return(1);
            }

            var counter = 0;

            while (threadData.HasNext())
            {
                var move = threadData.Next();
                if (!cb.IsLegal(move))
                {
                    continue;
                }

                cb.DoMove(move);
                counter += perft(cb, threadData, depth - 1);
                cb.UndoMove(move);
            }

            threadData.EndPly();
            return(counter);
        }
        public void FoolsCheckMateTest()
        {
            // generate moves
            var moves = new List <Move>(4)
            {
                new Move(EPieces.WhitePawn, ESquare.f2, ESquare.f3),
                new Move(EPieces.BlackPawn, ESquare.e7, ESquare.e5, EMoveType.Doublepush, EPieces.NoPiece),
                new Move(EPieces.WhitePawn, ESquare.g2, ESquare.g4, EMoveType.Doublepush, EPieces.NoPiece),
                new Move(EPieces.BlackQueen, ESquare.d8, ESquare.h4)
            };

            // construct game and start a new game
            var game = new Game();

            game.NewGame();

            // make the moves necessary to create a mate
            foreach (var move in moves)
            {
                Assert.True(game.MakeMove(move));
            }

            // verify in check is actually true
            Assert.True(game.Position.InCheck);

            var mg = new MoveGenerator(game.Position);

            // generate all legal moves
            mg.GenerateMoves(true);

            // verify that no legal moves actually exists.
            Assert.Empty(mg.Moves);
        }
示例#5
0
        private static char GetCheckChar(this IPosition pos)
        {
            var mg = new MoveGenerator(pos);

            mg.GenerateMoves();
            return(mg.Moves.Count > 0 ? '+' : '#');
        }
示例#6
0
        public override void DoTurn()
        {
            var cells = GameBoard.Instance.GetCells();

            cells.RemoveAll(c => c.piece == null);
            cells.RemoveAll(c => c.piece.color != color);

            while (cells.Count > 0)
            {
                var cell = cells.RandomItem();
                cells.Remove(cell);

                List <Move> moves = MoveGenerator.GenerateMoves(cell);
                while (moves.Count > 0)
                {
                    var move = moves.RandomItem();
                    moves.Remove(move);

                    turn = new Turn(cell, GameBoard.Instance.GetCell(move.targetPosition))
                    {
                        extraCaptures = move.extraCaptures
                    };

                    OnTurnCompleted?.Invoke(turn);
                    return;
                }
            }

            // There are no possible moves for any of the pieces
        }
示例#7
0
        public void MoveGeneratorDoesNotChangeHashKey()
        {
            var b        = new Board();
            var expected = TranspositionTable.GetHashKeyForPosition(b);

            MoveGenerator.GenerateMoves(b);
            Assert.Equal(expected, b.HashKey);
        }
        public void PerfTLevel1()
        {
            var testBoard = new Board();

            var result = MoveGenerator.GenerateMoves(testBoard);

            Assert.Equal(20, result.Count);
        }
示例#9
0
        public void FirstMove()
        {
            Board         board         = new Board(new Player[10, 10]);
            MoveGenerator moveGenerator = new MoveGenerator(board);

            Assert.Collection(moveGenerator.GenerateMoves(), p =>
            {
                Assert.Equal(board.FlattenedIndex((5, 5)), p);
            });
示例#10
0
        public static (bool, Move) Locate(this Move move, IPosition pos)
        {
            // force position to contain the latest moves for the position moves to be searched in
            var mg = new MoveGenerator(pos);

            mg.GenerateMoves();

            var element = mg.Moves.FirstOrDefault(x => x.GetFromSquare() == move.GetFromSquare() && x.GetToSquare() == move.GetToSquare());

            return(element == null ? (false, EmptyMove) : (true, element));
        }
示例#11
0
        //TJ: setting the right flags after parsing the move from a string without having a board instance as context isn't possible and so we add the flags here
        public Move WithFlags(Move move)
        {
            foreach (var candidate in _moveGen.GenerateMoves(_board, true))
            {
                if (candidate.StartSquare == move.StartSquare && candidate.TargetSquare == move.TargetSquare && candidate.PromotionPieceType == move.PromotionPieceType)
                {
                    return(candidate);
                }
            }

            //not found? well... that's... kinda bad
            throw new Exception(move.Name + " not valid in the given position!");
        }
示例#12
0
        public void HashKeyRestoredAfterUnMakeMove()
        {
            var testBoard = new Board();
            var moves     = MoveGenerator.GenerateMoves(testBoard);

            foreach (var m in moves)
            {
                var expected = testBoard.HashKey;
                if (!testBoard.MakeMove(m))
                {
                    continue;
                }
                testBoard.UnMakeMove();
                Assert.Equal(expected, testBoard.HashKey);
            }
        }
示例#13
0
        private void TryMakeMove(Coord startSquare, Coord targetSquare)
        {
            var startIndex  = BoardRepresentation.IndexFromCoord(startSquare);
            var targetIndex = BoardRepresentation.IndexFromCoord(targetSquare);
            var moveIsLegal = false;
            var chosenMove  = new Move();

            var moveGenerator        = new MoveGenerator();
            var wantsKnightPromotion = Input.GetKey(KeyCode.LeftAlt);

            var legalMoves = moveGenerator.GenerateMoves(board);

            for (var i = 0; i < legalMoves.Count; i++)
            {
                var legalMove = legalMoves[i];

                if (legalMove.StartSquare == startIndex && legalMove.TargetSquare == targetIndex)
                {
                    if (legalMove.IsPromotion)
                    {
                        if (legalMove.MoveFlag == Move.Flag.PromoteToQueen && wantsKnightPromotion)
                        {
                            continue;
                        }
                        if (legalMove.MoveFlag != Move.Flag.PromoteToQueen && !wantsKnightPromotion)
                        {
                            continue;
                        }
                    }

                    moveIsLegal = true;
                    chosenMove  = legalMove;
                    //	Debug.Log (legalMove.PromotionPieceType);
                    break;
                }
            }

            if (moveIsLegal)
            {
                ChoseMove(chosenMove);
                currentState = InputState.None;
            }
            else
            {
                CancelPieceSelection();
            }
        }
示例#14
0
        Result GetGameState()
        {
            MoveGenerator moveGenerator = new MoveGenerator();
            var           moves         = moveGenerator.GenerateMoves(board);

            // Look for mate/stalemate
            if (moves.Count == 0)
            {
                if (moveGenerator.InCheck())
                {
                    return((board.WhiteToMove) ? Result.WhiteIsMated : Result.BlackIsMated);
                }
                return(Result.Stalemate);
            }

            // Fifty move rule
            if (board.fiftyMoveCounter >= 100)
            {
                return(Result.FiftyMoveRule);
            }

            // Threefold repetition
            int repCount = board.RepetitionPositionHistory.Count((x => x == board.ZobristKey));

            if (repCount == 3)
            {
                return(Result.Repetition);
            }

            // Look for insufficient material (not all cases implemented yet)
            int numPawns   = board.pawns[Board.WhiteIndex].Count + board.pawns[Board.BlackIndex].Count;
            int numRooks   = board.rooks[Board.WhiteIndex].Count + board.rooks[Board.BlackIndex].Count;
            int numQueens  = board.queens[Board.WhiteIndex].Count + board.queens[Board.BlackIndex].Count;
            int numKnights = board.knights[Board.WhiteIndex].Count + board.knights[Board.BlackIndex].Count;
            int numBishops = board.bishops[Board.WhiteIndex].Count + board.bishops[Board.BlackIndex].Count;

            if (numPawns + numRooks + numQueens == 0)
            {
                if (numKnights == 1 || numBishops == 1)
                {
                    return(Result.InsufficientMaterial);
                }
            }

            return(Result.Playing);
        }
示例#15
0
        public void HighlightLegalMoves(Board board, Coord fromSquare)
        {
            if (showLegalMoves)
            {
                var moves = moveGenerator.GenerateMoves(board);

                for (var i = 0; i < moves.Count; i++)
                {
                    var move = moves[i];
                    if (move.StartSquare == BoardRepresentation.IndexFromCoord(fromSquare))
                    {
                        var coord = BoardRepresentation.CoordFromIndex(move.TargetSquare);
                        SetSquareColour(coord, boardTheme.lightSquares.legal, boardTheme.darkSquares.legal);
                    }
                }
            }
        }
示例#16
0
        // zasady WDZ
        Result GetGameState()
        {
            MoveGenerator moveGenerator = new MoveGenerator();
            var           moves         = moveGenerator.GenerateMoves(board);

            // Mat
            if (moves.Count == 0)
            {
                if (moveGenerator.InCheck())
                {
                    return((board.WhiteToMove) ? Result.WhiteIsMated : Result.BlackIsMated);
                }
                return(Result.Stalemate);
            }

            // Zasada 50
            if (board.fiftyMoveCounter >= 100)
            {
                return(Result.FiftyMoveRule);
            }

            // Zasada Powtórzeń
            int repCount = board.RepetitionPositionHistory.Count((x => x == board.ZobristKey));

            if (repCount == 3)
            {
                return(Result.Repetition);
            }

            int numPawns   = board.pawns[Board.WhiteIndex].Count + board.pawns[Board.BlackIndex].Count;
            int numRooks   = board.rooks[Board.WhiteIndex].Count + board.rooks[Board.BlackIndex].Count;
            int numQueens  = board.queens[Board.WhiteIndex].Count + board.queens[Board.BlackIndex].Count;
            int numKnights = board.knights[Board.WhiteIndex].Count + board.knights[Board.BlackIndex].Count;
            int numBishops = board.bishops[Board.WhiteIndex].Count + board.bishops[Board.BlackIndex].Count;

            if (numPawns + numRooks + numQueens == 0)
            {
                if (numKnights == 1 || numBishops == 1)
                {
                    return(Result.InsufficientMaterial);
                }
            }

            return(Result.Playing);
        }
示例#17
0
        public void GetHashKeyAgreesWithMakeMove1()
        {
            var testBoard = new Board();

            var moves = MoveGenerator.GenerateMoves(testBoard);

            foreach (var m in moves)
            {
                var expected = testBoard.HashKey;
                if (!testBoard.MakeMove(m))
                {
                    continue;
                }
                testBoard.UnMakeMove();
                Assert.Equal(expected, testBoard.HashKey);
            }
            var result = testBoard.HashKey;
        }
示例#18
0
        private void AttemptMove(Cell cell)
        {
            // Generate a set of all valid moves for the starting piece
            var moves     = MoveGenerator.GenerateMoves(turn.start);
            var validMove = moves.Where(m => m.targetPosition == cell.position).FirstOrDefault();

            // If the move we want to take is one of the valid moves, we can continue
            if (validMove != null)
            {
                // Moving to an empty space is fine. Capturing is only allowed if the piece is of opposite color to you.
                if (cell.piece == null || (cell.piece != null && cell.piece.color != color))
                {
                    turn.end = cell;
                    OnTurnCompleted?.Invoke(turn);
                    turnManager.selectedCell = null;
                }
            }
        }
示例#19
0
        public static int Divide(ChessBoard cb, ThreadData threadData, int depth)
        {
            threadData.StartPly();
            MoveGenerator.GenerateMoves(threadData, cb);
            MoveGenerator.GenerateAttacks(threadData, cb);
            var counter = 0;

            while (threadData.HasNext())
            {
                var move = threadData.Next();
                cb.DoMove(move);
                var divideCounter = perft(cb, threadData, depth - 1);
                counter += divideCounter;
                cb.UndoMove(move);
                Console.WriteLine(new MoveWrapper(move) + ": " + divideCounter);
            }

            return(counter);
        }
示例#20
0
            public override void Render(Batcher batcher, Camera camera)
            {
                if (GameBoard.Instance.Layout == null)
                {
                    return;
                }

                if (previousSelectedCell != TurnManager.Instance.selectedCell)
                {
                    previousSelectedCell = TurnManager.Instance.selectedCell;

                    if (previousSelectedCell != null && previousSelectedCell.piece != null && previousSelectedCell.piece.color == TurnManager.Instance.CurrentPlayer.color)
                    {
                        possibleMoves = MoveGenerator.GenerateMoves(previousSelectedCell);
                    }
                }

                DrawMouseOverlay(batcher, camera);
                DrawPossibleMoves(batcher);
            }
示例#21
0
        public static void PerftDivideParallel(Board b, int depth)
        {
            var startTime  = DateTime.Now;
            var moves      = MoveGenerator.GenerateMoves(b);
            var legalMoves = new List <PerfTMove>();

            //before we parallelize, let's remove any illegal moves
            foreach (var m in moves)
            {
                if (!b.MakeMove(m))
                {
                    continue;
                }
                legalMoves.Add(new PerfTMove {
                    Move = m, Nodes = 0
                });
                b.UnMakeMove();
            }


            Parallel.ForEach(legalMoves, (m) =>
            {
                Board newBoard = new Board(b);
                if (!newBoard.MakeMove(m.Move))
                {
                    return;
                }

                var nodes = Perft(newBoard, depth - 1);

                m.Nodes += nodes;
                newBoard.UnMakeMove();
                Console.WriteLine(String.Format("{0}: {1}", m.Move.ToAlegbraicNotation(newBoard), nodes));
            });
            Console.WriteLine("Moves: {0}", legalMoves.Count);
            Console.WriteLine("Total: {0}", legalMoves.Sum(x => x.Nodes));
            var endTime = DateTime.Now;

            Console.WriteLine("Completed in {0}ms", (endTime - startTime).TotalMilliseconds);
        }
示例#22
0
        static int Perft(Board b, int depth)
        {
            int nodes = 0;

            if (depth == 0)
            {
                return(1);
            }

            var moves  = MoveGenerator.GenerateMoves(b);
            var nMoves = moves.Count;

            foreach (var m in moves)
            {
                if (b.MakeMove(m))
                {
                    nodes += Perft(b, depth - 1);
                    b.UnMakeMove();
                }
            }
            return(nodes);
        }
示例#23
0
        private static long Qperft(ChessBoard chessBoard, int depth)
        {
            ThreadData.StartPly();
            MoveGenerator.GenerateMoves(ThreadData, chessBoard);
            MoveGenerator.GenerateAttacks(ThreadData, chessBoard);

            long counter = 0;

            if (depth == 1)
            {
                while (ThreadData.HasNext())
                {
                    if (chessBoard.IsLegal(ThreadData.Next()))
                    {
                        counter++;
                    }
                }

                ThreadData.EndPly();
                return(counter);
            }

            while (ThreadData.HasNext())
            {
                var move = ThreadData.Next();
                if (!chessBoard.IsLegal(move))
                {
                    continue;
                }

                chessBoard.DoMove(move);
                counter += Qperft(chessBoard, depth - 1);
                chessBoard.UndoMove(move);
            }

            ThreadData.EndPly();
            return(counter);
        }
示例#24
0
        public static Dictionary <string, double> LoadFens(string fileName, bool containsResult, bool includingCheck)
        {
            Console.WriteLine("Loading " + fileName);

            var fens       = new Dictionary <string, double>();
            var checkCount = 0;
            var checkmate  = 0;
            var stalemate  = 0;

            try
            {
                foreach (var line in File.ReadLines(fileName))
                {
                    double score = 0;
                    string fenString;
                    if (containsResult)
                    {
                        var scoreString = GetScoreStringFromLine(line);
                        fenString = GetFenStringFromLine(line);
                        if (scoreString.Equals("\"1/2-1/2\";"))
                        {
                            score = 0.5;
                        }
                        else if (scoreString.Equals("\"1-0\";"))
                        {
                            score = 1;
                        }
                        else if (scoreString.Equals("\"0-1\";"))
                        {
                            score = 0;
                        }
                        else
                        {
                            throw new Exception("Unknown result: " + scoreString);
                        }
                    }
                    else
                    {
                        fenString = line;
                    }

                    ChessBoardUtil.SetFen(fenString, Cb);

                    if (Cb.CheckingPieces == 0)
                    {
                        ThreadData.StartPly();
                        MoveGenerator.GenerateAttacks(ThreadData, Cb);
                        MoveGenerator.GenerateMoves(ThreadData, Cb);
                        if (ThreadData.HasNext())
                        {
                            fens.Add(fenString, score);
                        }
                        else
                        {
                            stalemate++;
                        }

                        ThreadData.EndPly();
                    }
                    else
                    {
                        checkCount++;
                        if (!includingCheck)
                        {
                            continue;
                        }
                        ThreadData.StartPly();
                        MoveGenerator.GenerateAttacks(ThreadData, Cb);
                        MoveGenerator.GenerateMoves(ThreadData, Cb);
                        if (ThreadData.HasNext())
                        {
                            fens.Add(fenString, score);
                        }
                        else
                        {
                            checkmate++;
                        }

                        ThreadData.EndPly();
                    }

                    //line = br.readLine();
                }
            }
            catch (IOException e)
            {
                throw new Exception("", e);
            }

            Console.WriteLine("In check : " + checkCount);
            Console.WriteLine("Checkmate : " + checkmate);
            Console.WriteLine("Stalemate : " + stalemate);
            return(fens);
        }
示例#25
0
        public int SearchRoot(int alpha, int beta, int depth)
        {
            PvLength[0] = 0;

            if (MyGameState.GameBoard.History.IsGameDrawn(MyBoard.HashKey))
            {
                return(CurrentDrawScore);
            }

            if (RootMoves == null)
            {
                RootMoves = MoveGenerator
                            .GenerateMoves(MyBoard)
                            .OrderByDescending(m => OrderRootMove(m))
                            .ToList();
            }

            int  score;
            Move bestMove = null, lastMove = null;
            bool inCheck = MyBoard.InCheck(MyBoard.SideToMove);

            foreach (var m in RootMoves)
            {
                if (!Make(m))
                {
                    continue;
                }

                if (depth > 0)
                {
                    if (bestMove == null)
                    {
                        score = -Search(-beta, -alpha, depth - 1);
                    }
                    else
                    {
                        score = -Search(-alpha - 1, -alpha, depth - 1);
                        if (score > alpha)
                        {
                            score = -Search(-beta, -alpha, depth - 1);
                        }
                    }
                }
                else
                {
                    score = -Quiesce(-beta, -alpha);
                }

                TakeBack();

                if (MyGameState.TimeUp)
                {
                    return(alpha);
                }

                if (score >= beta)
                {
                    //we want to try this move first next time
                    NewRootMove(m);
                    PvLength[0] = 1;
                    PrincipalVariation[0, 0] = m;
                    return(score);
                }

                if (score > alpha)
                {
                    alpha    = score;
                    bestMove = m;
                    // PV Node
                    //update the PV
                    UpdatePv(bestMove);
                    TranspositionTable.Instance.Store(MyBoard.HashKey, m, depth, alpha, EntryType.PV);
                }

                lastMove = m;
            }

            //check for mate
            if (lastMove == null)
            {
                //we can't make a move. check for mate or stalemate.
                if (inCheck)
                {
                    return(-10000 + Ply);
                }
                else
                {
                    return(CurrentDrawScore);
                }
            }


            if (bestMove != null)
            {
                if (bestMove != RootMoves[0])
                {
                    NewRootMove(bestMove);
                }
            }
            return(alpha);
        }
示例#26
0
        public int Search(int alpha, int beta, int depth)
        {
            Metrics.Nodes++;
            PvLength[Ply] = Ply;
            var inCheck = MyBoard.InCheck(MyBoard.SideToMove);
            int ext     = inCheck ? 1 : 0;

            if (MyGameState.GameBoard.History.IsPositionDrawn(MyBoard.HashKey))
            {
                return(CurrentDrawScore);
            }

            if (Ply >= MAX_DEPTH)
            {
                TakeBack();
                return(Evaluator.Evaluate(MyBoard, -10000, 10000));
            }

            if ((Metrics.Nodes & 65535) == 65535)
            {
                Interrupt();
                if (MyGameState.TimeUp)
                {
                    return(alpha);
                }
            }

            Move bestMove = null;

            if (depth + ext <= 0)
            {
                return(Quiesce(alpha, beta));
            }

            //first let's look for a transposition
            var entry = TranspositionTable.Instance.Read(MyBoard.HashKey);

            if (entry != null)
            {
                //we have a hit from the TTable
                if (entry.Depth >= depth)
                {
                    if (entry.Type == (byte)EntryType.CUT && entry.Score >= beta)
                    {
                        return(beta);
                    }
                    else if (entry.Type == (byte)EntryType.ALL && entry.Score <= alpha)
                    {
                        return(alpha);
                    }
                    else if (entry.Type == (byte)EntryType.PV)
                    {
                        return(entry.Score);
                    }
                }
            }

            int mateThreat   = 0;
            var myPieceCount = MyBoard.PieceCount(MyBoard.SideToMove);

            //next try a Null Move
            if (Ply > 0 &&
                depth > 1 &&
                alpha == beta - 1 &&
                !inCheck &&
                !MyBoard.History[Ply - 1].IsNullMove &&
                myPieceCount > 0 &&
                (myPieceCount > 2 || depth < 7))
            {
                Metrics.NullMoveTries++;
                MakeNullMove();
                var nullReductionDepth = depth > 6 ? 4 : 3;
                int nmScore;
                if (depth - nullReductionDepth - 1 > 0)
                {
                    nmScore = -Search(-beta, 1 - beta, depth - nullReductionDepth - 1);
                }
                else
                {
                    nmScore = -Quiesce(-beta, 1 - beta);
                }
                UnmakeNullMove();

                if (MyGameState.TimeUp)
                {
                    return(alpha);
                }

                if (nmScore >= beta)
                {
                    Metrics.NullMoveFailHigh++;
                    TranspositionTable.Instance.Store(MyBoard.HashKey, null, depth, nmScore, EntryType.CUT);
                    return(nmScore);
                }
            }

            var moves = MoveGenerator
                        .GenerateMoves(MyBoard)
                        .OrderByDescending((m) => OrderMove(m, entry));
            Move lastMove = null;
            int  lmr = 0, nonCaptureMoves = 0, movesSearched = 0;

            foreach (var m in moves)
            {
                bool fprune = false;
                int  score;
                if (!Make(m))
                {
                    continue;
                }

                var justGaveCheck = MyBoard.InCheck(MyBoard.SideToMove);
                var capture       = ((m.Bits & (byte)MoveBits.Capture) != 0);
                if (!capture && (entry == null || entry.MoveValue != m.Value)) // don't count the hash move as a non-capture
                {
                    ++nonCaptureMoves;                                         // while it might not be a capture, the point
                }
                // here is to start counting after generated captures
                var passedpawnpush = (m.Bits & (byte)MoveBits.Pawn) > 0 && (Evaluator.PassedPawnMask[MyBoard.SideToMove ^ 1, m.To] & MyBoard.Pawns[MyBoard.SideToMove]) == 0;
                //LATE MOVE REDUCTIONS
                if (ext == 0 &&          //no extension
                    !inCheck &&          //i am not in check at this node
                    !justGaveCheck &&    //the move we just made does not check the opponent
                    mateThreat == 0 &&   //no mate threat detected
                    !passedpawnpush &&   //do not reduce/prune passed pawn pushes
                    nonCaptureMoves > 0) //start reducing after the winning captures
                {
                    if (depth > 2)
                    {
                        lmr = movesSearched > 2 ? 2 : 1; // start reducing depth if we aren't finding anything useful
                    }
                    //FUTILITY PRUNING
                    else if (depth < 3 && alpha > -9900 && beta < 9900)
                    {
                        if (depth == 2 && -Evaluator.EvaluateMaterial(MyBoard) + Evaluator.PieceValues[(int)Piece.Rook] <= alpha)
                        {
                            Metrics.EFPrune++;
                            fprune = true;
                        }

                        else if (depth == 1 && -Evaluator.EvaluateMaterial(MyBoard) + Evaluator.PieceValues[(int)Piece.Knight] <= alpha)
                        {
                            Metrics.FPrune++;
                            fprune = true;
                        }
                    }
                }
                if (!fprune)
                {
                    //if we don't yet have a move, then search full window (PV Node)
                    if (bestMove == null)
                    {
                        score = -Search(-beta, -alpha, depth - 1 - lmr + ext);
                    }
                    else //otherwise, use a zero window
                    {
                        //zero window search
                        score = -Search(-alpha - 1, -alpha, depth - 1 - lmr + ext);

                        if (score > alpha)
                        {
                            //this move might be better than our current best move
                            //we have to research with full window

                            score = -Search(-beta, -alpha, depth - 1 - lmr + ext);

                            if (score > alpha && lmr > 0)
                            {
                                //let's research again without the lmr
                                Metrics.LMRResearch++;
                                score = -Search(-beta, -alpha, depth - 1);
                            }
                        }
                    }
                }
                else
                {
                    score = -Quiesce(-beta, -alpha);
                }

                TakeBack();
                ++movesSearched;
                if (MyGameState.TimeUp)
                {
                    return(alpha);
                }

                if (score >= beta)
                {
                    SearchFailHigh(m, score, depth, entry);
                    if (lastMove == null)
                    {
                        Metrics.FirstMoveFailHigh++;
                    }
                    return(score);
                }

                if (score > alpha)
                {
                    alpha    = score;
                    bestMove = m;
                    // PV Node
                    //update the PV
                    UpdatePv(bestMove);
                    //Add to hashtable
                    TranspositionTable.Instance.Store(
                        MyBoard.HashKey, bestMove, depth, alpha, TranspositionTableEntry.EntryType.PV);
                }

                lastMove = m;
            }

            //check for mate
            if (lastMove == null)
            {
                //we can't make a move. check for mate or stalemate.
                if (inCheck)
                {
                    return(-10000 + Ply);
                }
                else
                {
                    return(CurrentDrawScore);
                }
            }


            if (bestMove == null)
            {
                //ALL NODE
                TranspositionTable.Instance.Store(
                    MyBoard.HashKey, null, depth, alpha,
                    TranspositionTableEntry.EntryType.ALL);
            }

            return(alpha);
        }
示例#27
0
 private static char GetCheckChar(this MoveGenerator moveGenerator)
 {
     moveGenerator.GenerateMoves();
     return(moveGenerator.Moves.Count > 0 ? '+' : '#');
 }
示例#28
0
        static string NotationFromMove(Board board, Move move)
        {
            MoveGenerator moveGen = new MoveGenerator();

            int movePieceType     = Piece.PieceType(board.Square[move.StartSquare]);
            int capturedPieceType = Piece.PieceType(board.Square[move.TargetSquare]);

            if (move.MoveFlag == Move.Flag.Castling)
            {
                int delta = move.TargetSquare - move.StartSquare;
                if (delta == 2)
                {
                    return("O-O");
                }
                else if (delta == -2)
                {
                    return("O-O-O");
                }
            }

            string moveNotation = GetSymbolFromPieceType(movePieceType);

            // check if any ambiguity exists in notation (e.g if e2 can be reached via Nfe2 and Nbe2)
            if (movePieceType != Piece.Pawn && movePieceType != Piece.King)
            {
                var allMoves = moveGen.GenerateMoves(board);

                foreach (Move altMove in allMoves)
                {
                    if (altMove.StartSquare != move.StartSquare && altMove.TargetSquare == move.TargetSquare)               // if moving to same square from different square
                    {
                        if (Piece.PieceType(board.Square[altMove.StartSquare]) == movePieceType)                            // same piece type
                        {
                            int fromFileIndex          = BoardRepresentation.FileIndex(move.StartSquare);
                            int alternateFromFileIndex = BoardRepresentation.FileIndex(altMove.StartSquare);
                            int fromRankIndex          = BoardRepresentation.RankIndex(move.StartSquare);
                            int alternateFromRankIndex = BoardRepresentation.RankIndex(altMove.StartSquare);

                            if (fromFileIndex != alternateFromFileIndex)                               // pieces on different files, thus ambiguity can be resolved by specifying file
                            {
                                moveNotation += BoardRepresentation.fileNames[fromFileIndex];
                                break;                                 // ambiguity resolved
                            }
                            else if (fromRankIndex != alternateFromRankIndex)
                            {
                                moveNotation += BoardRepresentation.rankNames[fromRankIndex];
                                break;                                 // ambiguity resolved
                            }
                        }
                    }
                }
            }

            if (capturedPieceType != 0)               // add 'x' to indicate capture
            {
                if (movePieceType == Piece.Pawn)
                {
                    moveNotation += BoardRepresentation.fileNames[BoardRepresentation.FileIndex(move.StartSquare)];
                }
                moveNotation += "x";
            }
            else                 // check if capturing ep
            {
                if (move.MoveFlag == Move.Flag.EnPassantCapture)
                {
                    moveNotation += BoardRepresentation.fileNames[BoardRepresentation.FileIndex(move.StartSquare)] + "x";
                }
            }

            moveNotation += BoardRepresentation.fileNames[BoardRepresentation.FileIndex(move.TargetSquare)];
            moveNotation += BoardRepresentation.rankNames[BoardRepresentation.RankIndex(move.TargetSquare)];

            // add promotion piece
            if (move.IsPromotion)
            {
                int promotionPieceType = move.PromotionPieceType;
                moveNotation += "=" + GetSymbolFromPieceType(promotionPieceType);
            }

            board.MakeMove(move, inSearch: true);
            var legalResponses = moveGen.GenerateMoves(board);

            // add check/mate symbol if applicable
            if (moveGen.InCheck())
            {
                if (legalResponses.Count == 0)
                {
                    moveNotation += "#";
                }
                else
                {
                    moveNotation += "+";
                }
            }
            board.UnmakeMove(move, inSearch: true);

            return(moveNotation);
        }
示例#29
0
        public static int CalculateBestMove(ChessBoard cb, ThreadData threadData, int ply, int depth,
                                            int alpha, int beta,
                                            int nullMoveCounter)
        {
            if (!IsRunning)
            {
                return(ChessConstants.ScoreNotRunning);
            }

            if (EngineConstants.Assert)
            {
                Assert.IsTrue(depth >= 0);
                Assert.IsTrue(alpha >= Util.ShortMin && alpha <= Util.ShortMax);
                Assert.IsTrue(beta >= Util.ShortMin && beta <= Util.ShortMax);
            }

            var alphaOrig = alpha;

            // get extensions
            depth += Extensions(cb);

            /* mate-distance pruning */
            if (EngineConstants.EnableMateDistancePruning)
            {
                alpha = Math.Max(alpha, Util.ShortMin + ply);
                beta  = Math.Min(beta, Util.ShortMax - ply - 1);
                if (alpha >= beta)
                {
                    return(alpha);
                }
            }

            // TODO JITWatch unpredictable branch
            if (depth == 0)
            {
                return(QuiescenceUtil.CalculateBestMove(cb, threadData, alpha, beta));
            }

            /* transposition-table */
            var ttEntry = TtUtil.GetEntry(cb.ZobristKey);
            var score   = ttEntry.GetScore(ply);

            if (ttEntry.Key != 0)
            {
                if (!EngineConstants.TestTtValues)
                {
                    if (ttEntry.Depth >= depth)
                    {
                        switch (ttEntry.Flag)
                        {
                        case TtUtil.FlagExact:
                            return(score);

                        case TtUtil.FlagLower:
                            if (score >= beta)
                            {
                                return(score);
                            }

                            break;

                        case TtUtil.FlagUpper:
                            if (score <= alpha)
                            {
                                return(score);
                            }

                            break;
                        }
                    }
                }
            }

            if (Statistics.Enabled)
            {
                Statistics.AbNodes++;
            }

            var eval = Util.ShortMin;
            var isPv = beta - alpha != 1;

            if (!isPv && cb.CheckingPieces == 0)
            {
                eval = EvalUtil.GetScore(cb, threadData);

                /* use tt value as eval */
                if (EngineConstants.UseTtScoreAsEval)
                {
                    if (TtUtil.CanRefineEval(ttEntry, eval, score))
                    {
                        eval = score;
                    }
                }

                /* static null move pruning */
                if (EngineConstants.EnableStaticNullMove && depth < StaticNullmoveMargin.Length)
                {
                    if (eval - StaticNullmoveMargin[depth] >= beta)
                    {
                        if (Statistics.Enabled)
                        {
                            Statistics.StaticNullMoved[depth]++;
                        }

                        return(eval);
                    }
                }

                /* razoring */
                if (EngineConstants.EnableRazoring && depth < RazoringMargin.Length &&
                    Math.Abs(alpha) < EvalConstants.ScoreMateBound)
                {
                    if (eval + RazoringMargin[depth] < alpha)
                    {
                        score = QuiescenceUtil.CalculateBestMove(cb, threadData, alpha - RazoringMargin[depth],
                                                                 alpha - RazoringMargin[depth] + 1);
                        if (score + RazoringMargin[depth] <= alpha)
                        {
                            if (Statistics.Enabled)
                            {
                                Statistics.Razored[depth]++;
                            }

                            return(score);
                        }
                    }
                }

                /* null-move */
                if (EngineConstants.EnableNullMove)
                {
                    if (nullMoveCounter < 2 && eval >= beta &&
                        MaterialUtil.HasNonPawnPieces(cb.MaterialKey, cb.ColorToMove))
                    {
                        cb.DoNullMove();
                        // TODO less reduction if stm (other side) has only 1 major piece
                        var reduction = depth / 4 + 3 + Math.Min((eval - beta) / 80, 3);
                        score = depth - reduction <= 0
                            ? -QuiescenceUtil.CalculateBestMove(cb, threadData, -beta, -beta + 1)
                            : -CalculateBestMove(cb, threadData, ply + 1, depth - reduction, -beta, -beta + 1,
                                                 nullMoveCounter + 1);
                        cb.UndoNullMove();
                        if (score >= beta)
                        {
                            if (Statistics.Enabled)
                            {
                                Statistics.NullMoveHit++;
                            }

                            return(score);
                        }

                        if (Statistics.Enabled)
                        {
                            Statistics.NullMoveMiss++;
                        }
                    }
                }
            }

            var parentMove     = ply == 0 ? 0 : threadData.Previous();
            var bestMove       = 0;
            var bestScore      = Util.ShortMin - 1;
            var ttMove         = 0;
            var counterMove    = 0;
            var killer1Move    = 0;
            var killer2Move    = 0;
            var movesPerformed = 0;

            threadData.StartPly();
            var phase = PhaseTt;

            while (phase <= PhaseQuiet)
            {
                switch (phase)
                {
                case PhaseTt:
                    if (ttEntry.Key != 0)
                    {
                        ttMove = ttEntry.Move;
                        if (cb.IsValidMove(ttMove))
                        {
                            threadData.AddMove(ttMove);
                        }

                        // else {
                        // throw new RuntimeException("invalid tt-move found: " + new MoveWrapper(ttMove));
                        // }
                    }

                    break;

                case PhaseAttacking:
                    MoveGenerator.GenerateAttacks(threadData, cb);
                    threadData.SetMvvlvaScores();
                    threadData.Sort();
                    break;

                case PhaseKiller1:
                    killer1Move = threadData.GetKiller1(ply);
                    if (killer1Move != 0 && killer1Move != ttMove && cb.IsValidMove(killer1Move))
                    {
                        threadData.AddMove(killer1Move);
                        break;
                    }

                    phase++;
                    goto case PhaseKiller2;

                case PhaseKiller2:
                    killer2Move = threadData.GetKiller2(ply);
                    if (killer2Move != 0 && killer2Move != ttMove && cb.IsValidMove(killer2Move))
                    {
                        threadData.AddMove(killer2Move);
                        break;
                    }

                    phase++;
                    goto case PhaseCounter;

                case PhaseCounter:
                    counterMove = threadData.GetCounter(cb.ColorToMove, parentMove);
                    if (counterMove != 0 && counterMove != ttMove && counterMove != killer1Move &&
                        counterMove != killer2Move && cb.IsValidMove(counterMove))
                    {
                        threadData.AddMove(counterMove);
                        break;
                    }

                    phase++;
                    goto case PhaseQuiet;

                case PhaseQuiet:
                    MoveGenerator.GenerateMoves(threadData, cb);
                    threadData.SetHhScores(cb.ColorToMove);
                    threadData.Sort();
                    break;
                }

                while (threadData.HasNext())
                {
                    var move = threadData.Next();

                    switch (phase)
                    {
                    case PhaseQuiet when move == ttMove || move == killer1Move || move == killer2Move ||
                        move == counterMove ||
                        !cb.IsLegal(move):
                    case PhaseAttacking when move == ttMove || !cb.IsLegal(move):
                        continue;
                    }

                    // pruning allowed?
                    if (!isPv && cb.CheckingPieces == 0 && movesPerformed > 0 && threadData.GetMoveScore() < 100 &&
                        !cb.IsDiscoveredMove(MoveUtil.GetFromIndex(move)))
                    {
                        if (phase == PhaseQuiet)
                        {
                            /* late move pruning */
                            if (EngineConstants.EnableLmp && depth <= 4 && movesPerformed >= depth * 3 + 3)
                            {
                                if (Statistics.Enabled)
                                {
                                    Statistics.Lmped[depth]++;
                                }

                                continue;
                            }

                            /* futility pruning */
                            if (EngineConstants.EnableFutilityPruning && depth < FutilityMargin.Length)
                            {
                                if (!MoveUtil.IsPawnPush78(move))
                                {
                                    if (eval == Util.ShortMin)
                                    {
                                        eval = EvalUtil.GetScore(cb, threadData);
                                    }

                                    if (eval + FutilityMargin[depth] <= alpha)
                                    {
                                        if (Statistics.Enabled)
                                        {
                                            Statistics.Futile[depth]++;
                                        }

                                        continue;
                                    }
                                }
                            }
                        }
                        /* SEE Pruning */
                        else if (EngineConstants.EnableSeePruning && depth <= 6 && phase == PhaseAttacking &&
                                 SeeUtil.GetSeeCaptureScore(cb, move) < -20 * depth * depth)
                        {
                            continue;
                        }
                    }

                    cb.DoMove(move);
                    movesPerformed++;

                    /* draw check */
                    if (cb.IsRepetition(move) || MaterialUtil.IsDrawByMaterial(cb))
                    {
                        score = EvalConstants.ScoreDraw;
                    }
                    else
                    {
                        score = alpha + 1; // initial is above alpha

                        var reduction = 1;
                        if (depth > 2 && movesPerformed > 1 && MoveUtil.IsQuiet(move) && !MoveUtil.IsPawnPush78(move))
                        {
                            reduction = LmrTable[Math.Min(depth, 63)][Math.Min(movesPerformed, 63)];
                            if (threadData.GetMoveScore() > 40)
                            {
                                reduction -= 1;
                            }

                            if (move == killer1Move || move == killer2Move || move == counterMove)
                            {
                                reduction -= 1;
                            }

                            if (!isPv)
                            {
                                reduction += 1;
                            }

                            reduction = Math.Min(depth - 1, Math.Max(reduction, 1));
                        }

                        /* LMR */
                        if (EngineConstants.EnableLmr && reduction != 1)
                        {
                            score = -CalculateBestMove(cb, threadData, ply + 1, depth - reduction, -alpha - 1, -alpha,
                                                       0);
                        }

                        /* PVS */
                        if (EngineConstants.EnablePvs && score > alpha && movesPerformed > 1)
                        {
                            score = -CalculateBestMove(cb, threadData, ply + 1, depth - 1, -alpha - 1, -alpha, 0);
                        }

                        /* normal bounds */
                        if (score > alpha)
                        {
                            score = -CalculateBestMove(cb, threadData, ply + 1, depth - 1, -beta, -alpha, 0);
                        }
                    }

                    cb.UndoMove(move);

                    if (score > bestScore)
                    {
                        bestScore = score;
                        bestMove  = move;

                        if (ply == 0 && IsRunning)
                        {
                            threadData.SetBestMove(cb, bestMove, alphaOrig, beta, bestScore, depth);
                        }

                        alpha = Math.Max(alpha, score);
                        if (alpha >= beta)
                        {
                            if (Statistics.Enabled)
                            {
                                Statistics.FailHigh[Math.Min(movesPerformed - 1, Statistics.FailHigh.Length - 1)]++;
                            }

                            /* killer and history */
                            if (MoveUtil.IsQuiet(move) && cb.CheckingPieces == 0)
                            {
                                threadData.AddCounterMove(cb.ColorToMove, parentMove, move);
                                threadData.AddKillerMove(move, ply);
                                threadData.AddHhValue(cb.ColorToMove, move, depth);
                            }

                            phase += 10;
                            break;
                        }
                    }

                    if (MoveUtil.IsQuiet(move))
                    {
                        threadData.AddBfValue(cb.ColorToMove, move, depth);
                    }
                }

                phase++;
            }

            threadData.EndPly();

            /* checkmate or stalemate */
            if (movesPerformed == 0)
            {
                if (cb.CheckingPieces == 0)
                {
                    if (Statistics.Enabled)
                    {
                        Statistics.StaleMateCount++;
                    }

                    return(EvalConstants.ScoreDraw);
                }

                if (Statistics.Enabled)
                {
                    Statistics.MateCount++;
                }

                return(Util.ShortMin + ply);
            }

            if (EngineConstants.Assert)
            {
                Assert.IsTrue(bestMove != 0);
            }

            // set tt-flag
            var flag = TtUtil.FlagExact;

            if (bestScore >= beta)
            {
                flag = TtUtil.FlagLower;
            }
            else if (bestScore <= alphaOrig)
            {
                flag = TtUtil.FlagUpper;
            }

            if (IsRunning)
            {
                TtUtil.AddValue(cb.ZobristKey, bestScore, ply, depth, flag, bestMove);
            }

            Statistics.SetBestMove(cb, bestMove, ttMove, ttEntry, flag, counterMove, killer1Move, killer2Move);

            if (EngineConstants.TestTtValues)
            {
                SearchTestUtil.TestTtValues(score, bestScore, depth, bestMove, flag, ttEntry, ply);
            }

            return(bestScore);
        }