예제 #1
0
        protected virtual int QuiescenceSolve(BitBoard board, int alpha, int beta, int depth, bool prevmove = true)
        {
            searchResult.Nodes++;
            var cacheIndex = depth + Constants.MaxOpeningDepth + 1;

            var currentScore = Evaluation.Eval(board);

            if (depth == 0 || currentScore >= beta)
            {
                return(currentScore);
            }

            if (currentScore > alpha)
            {
                alpha = currentScore;
            }

            var moves = Rule.FindMoves(board);

            if (moves.Length == 0)
            {
                if (!prevmove)
                {
                    //END
                    return(EndGameEvaluation.Eval(board));
                }
                else
                {
                    var oppBoard   = board.Switch();
                    var childScore = GetCachedScore(oppBoard, cacheIndex, () => - QuiescenceSolve(oppBoard, -beta, -alpha, depth, false));

                    return(BalanceScore(currentScore, childScore));
                }
            }

            var nextScore = minimumScore;
            var foundPv   = false;

            var orderedMoves = OrderMovesByMobility(moves, board);

            foreach (var pos in orderedMoves)
            {
                var eval = 0;

                var oppBoard = Rule.MoveSwitch(board, pos);

                if (foundPv)
                {
                    //zero window
                    eval = GetCachedScore(oppBoard, cacheIndex - 1, () => - QuiescenceSolve(oppBoard, -alpha - 1, -alpha, depth - 1));
                    if ((eval > alpha) && (eval < beta))
                    {
                        eval = -QuiescenceSolve(oppBoard, -beta, -eval, depth - 1);
                    }
                }
                else
                {
                    eval = GetCachedScore(oppBoard, cacheIndex - 1, () => - QuiescenceSolve(oppBoard, -beta, -alpha, depth - 1));
                }

                if (eval > nextScore)
                {
                    nextScore = eval;

                    if (eval > alpha)
                    {
                        if (eval >= beta)
                        {
                            //pruning
                            return(nextScore);
                        }

                        alpha   = eval;
                        foundPv = true;
                    }
                }
            }

            return(BalanceScore(currentScore, nextScore));
        }
예제 #2
0
        protected override int FastestFirstSolve(BitBoard board, int alpha, int beta, int depth, bool prevmove = true)
        {
            searchResult.Nodes++;

            //leaf node
            if (depth == 0)
            {
                return(QuiescenceSolve(board, alpha, beta, 2, prevmove));
            }

            var moves = Rule.FindMoves(board);

            if (moves.Length == 0)
            {
                if (!prevmove)
                {
                    //END
                    return(EndGameEvaluation.Eval(board));
                }
                else
                {
                    var oppBoard = board.Switch();
                    return(GetCachedScore(oppBoard, depth, () => - FastestFirstSolve(oppBoard, -beta, -alpha, depth, false)));
                }
            }

            var score   = minimumScore;
            var foundPv = false;

            var orderedMoves = OrderMovesByMobility(moves, board);

            foreach (var pos in orderedMoves)
            {
                var eval = 0;

                var oppBoard = Rule.MoveSwitch(board, pos);

                if (foundPv)
                {
                    //zero window
                    eval = GetCachedScore(oppBoard, depth - 1, () => - FastestFirstSolve(oppBoard, -alpha - 1, -alpha, depth - 1));
                    if ((eval > alpha) && (eval < beta))
                    {
                        eval = -FastestFirstSolve(oppBoard, -beta, -eval, depth - 1);
                    }
                }
                else
                {
                    eval = GetCachedScore(oppBoard, depth - 1, () => - FastestFirstSolve(oppBoard, -beta, -alpha, depth - 1));
                }

                if (eval > score)
                {
                    score = eval;

                    if (eval > alpha)
                    {
                        if (eval >= beta)
                        {
                            //pruning
                            return(score);
                        }

                        alpha   = eval;
                        foundPv = true;
                    }
                }
            }

            return(score);
        }
예제 #3
0
        public override SearchResult Search(BitBoard board, int depth)
        {
            PrepareSearch(board);

            searchResult = new SearchResult();

            if (depth > Constants.MaxEndGameDepth)
            {
                searchResult.Message = "too depth...";
                return(searchResult);
            }

            var clock = new Clock();

            clock.Start();

            var moves = Rule.FindMoves(board);

            if (moves.Length == 0)
            {
                moves = Rule.FindMoves(board);

                if (moves.Length == 0)
                {
                    //END
                    var endScore = EndGameEvaluation.Eval(board);

                    return(new SearchResult()
                    {
                        Move = -1, Score = endScore
                    });
                }
                else
                {
                    var result = Search(board.Switch(), depth);
                    result.Score = -result.Score;

                    return(result);
                }
            }

            var alpha = Window.Alpha;
            var beta  = Window.Beta;

            if (depth >= Constants.MaxEndGameDepth - 2)
            {//make search window small
                alpha = -1;
                beta  = 1;
            }

            var score   = minimumScore;
            var foundPv = false;
            var index   = 0;

            var orderedMoves = OrderMovesByMobility(moves, board);

            foreach (var pos in orderedMoves)
            {
                //move
                var oppBoard = Rule.MoveSwitch(board, pos);

                var eval = 0;
                //check
                if (foundPv)
                {
                    //zero window
                    eval = -FastestFirstSolve(oppBoard, -alpha - 1, -alpha, depth - 1);
                    if ((eval > alpha) && (eval < beta))
                    {
                        eval = -FastestFirstSolve(oppBoard, -beta, -eval, depth - 1);
                    }
                }
                else
                {
                    eval = -FastestFirstSolve(oppBoard, -beta, -alpha, depth - 1);
                }

                //reback?

                searchResult.EvalList.Add(new EvalItem {
                    Move = pos, Score = eval
                });

                searchResult.Message += string.Format("({0}:{1})", pos, eval);
                if (eval > score)
                {
                    score = eval;
                    //update move
                    searchResult.Move  = pos;
                    searchResult.Score = score;

                    if (eval > alpha)
                    {
                        if (eval >= beta)
                        {
                            //pruning
                            break;
                        }
                        alpha   = eval;
                        foundPv = true;
                    }
                }

                searchResult.TimeSpan = clock.Elapsed;
                searchResult.Process  = (++index) / (double)(moves.Length + 1);
                UpdateProgress?.Invoke(searchResult);
            }

            clock.Stop();

            searchResult.TimeSpan = clock.Elapsed;

            var s = from q in scoreCaches.Select((e, i) => new { e.Count, Index = i })
                    where q.Count > 0
                    select new { q.Count, q.Index };

            var cacheInfo = string.Join(",", s.Select(c => $"({c.Index}:{c.Count})"));

            searchResult.Message += $" (hits: {hits}, cache info:{cacheInfo})";
            searchResult.Process  = 1;

            return(searchResult);
        }
예제 #4
0
        protected virtual int FastestFirstSolve(BitBoard board, int alpha, int beta, int depth, bool prevmove = true)
        {
            searchResult.Nodes++;

            //game over
            if (board.IsFull)
            {
                return(EndGameEvaluation.Eval(board));
            }

            //leaf node
            if (depth == 0)
            {
                return(Evaluation.Eval(board));
            }

            var moves = Rule.FindMoves(board);

            if (moves.Length == 0)
            {
                if (!prevmove)
                {
                    //END
                    return(EndGameEvaluation.Eval(board));
                }
                else
                {
                    var oppBoard = board.Switch();
                    //TODO: should it be +, not -?
                    return(GetCachedScore(oppBoard, depth, () => - FastestFirstSolve(oppBoard, -beta, -alpha, depth, false)));
                }
            }

            var score   = minimumScore;
            var foundPv = false;

            //moves = moves.OrderBy(i => squareDict[i]).ToArray();

            var orderedMoves = OrderMovesByMobility(moves, board);

            foreach (var pos in orderedMoves)
            {
                var eval = 0;

                var oppBoard = Rule.MoveSwitch(board, pos);

                if (foundPv)
                {
                    //zero window
                    eval = GetCachedScore(oppBoard, depth, () => - FastestFirstSolve(oppBoard, -alpha - 1, -alpha, depth - 1));
                    if ((eval > alpha) && (eval < beta))
                    {
                        eval = -FastestFirstSolve(oppBoard, -beta, -eval, depth - 1);
                    }
                }
                else
                {
                    eval = GetCachedScore(oppBoard, depth, () => - FastestFirstSolve(oppBoard, -beta, -alpha, depth - 1));
                }

                //reback?

                if (eval > score)
                {
                    score = eval;

                    if (eval > alpha)
                    {
                        if (eval >= beta)
                        {
                            //pruning
                            return(score);
                        }

                        alpha   = eval;
                        foundPv = true;
                    }
                }
            }

            return(score);
        }
예제 #5
0
        private int NoParitySearch(BitBoard board, int alpha, int beta, int empties, bool prevmove = true)
        {
            searchResult.Nodes++;
            var moves = Rule.FindMoves(board);

            if (moves.Length == 0)
            {
                if (!prevmove)
                {
                    //END
                    return(EndGameEvaluation.Eval(board));
                }
                else
                {
                    return(-NoParitySearch(board.Switch(), -beta, -alpha, empties, false));
                }
            }

            var score     = minimumScore;
            var diffCount = board.DiffCount();

            foreach (var pos in moves)
            {
                var eval = 0;

                var flips    = Rule.FindFlips(board, pos);
                var oppBoard = Rule.FlipSwitch(board, pos, flips);

                if (empties == 2)
                {
                    var ownFlipsCount = flips.CountBits();
                    //the last move of opponent player
                    var lastEmptySquare = oppBoard.EmptyPieces.Index();
                    if (lastEmptySquare < 0)
                    {
                        throw new Exception($"invalid square index:{lastEmptySquare}");
                    }

                    var oppFlipsCount = Rule.CountFlips(oppBoard, lastEmptySquare);

                    if (oppFlipsCount > 0)
                    {
                        //both done.
                        eval = diffCount + 2 * (ownFlipsCount - oppFlipsCount);
                    }
                    else
                    {
                        //opp pass
                        var ownLastFlipsCount = Rule.CountFlips(oppBoard, lastEmptySquare);

                        if (ownLastFlipsCount > 0)
                        {
                            eval = diffCount + 2 * (ownFlipsCount + ownLastFlipsCount) + 2;
                        }
                        else
                        {
                            //all pass
                            eval = diffCount + 2 * ownFlipsCount;
                            //TODO: eval==0?
                            if (eval >= 0)
                            {
                                eval += 2;
                            }
                        }
                    }
                }
                else
                {
                    //empties!=2
                    eval = -NoParitySearch(oppBoard, -beta, -alpha, empties - 1);
                }

                if (eval > score)
                {
                    score = eval;
                    if (eval > alpha)
                    {
                        if (eval >= beta)
                        {
                            return(score);
                        }
                        alpha = eval;
                    }
                }
            }

            return(score);
        }
예제 #6
0
        private int ParitySearch(BitBoard board, int alpha, int beta, int depth, bool prevmove = true)
        {
            searchResult.Nodes++;

            //game over
            if (board.IsFull)
            {
                return(EndGameEvaluation.Eval(board));
            }

            //leaf node
            if (depth == 0)
            {
                return(Evaluation.Eval(board));
            }

            var moves = Rule.FindMoves(board);

            if (moves.Length == 0)
            {
                if (!prevmove)
                {
                    //END
                    return(EndGameEvaluation.Eval(board));
                }
                else
                {
                    return(-ParitySearch(board.Switch(), -beta, -alpha, depth, false));
                }
            }

            var score   = minimumScore;
            var foundPv = false;

            //moves = moves.OrderBy(i => squareDict[i]).ToArray();

            var orderedMoves = OrderMovesBySquares(moves);

            foreach (var pos in orderedMoves)
            {
                var eval = 0;

                var oppBoard = Rule.MoveSwitch(board, pos);

                if (depth <= Constants.NoParityDepth)
                {
                    //Parity Search
                    if (foundPv)
                    {
                        //zero window
                        eval = -NoParitySearch(oppBoard, -alpha - 1, -alpha, depth - 1);
                        if ((eval > alpha) && (eval < beta))
                        {
                            eval = -NoParitySearch(oppBoard, -beta, -eval, depth - 1);
                        }
                    }
                    else
                    {
                        eval = -NoParitySearch(oppBoard, -beta, -alpha, depth - 1);
                    }
                }
                else
                {
                    if (foundPv)
                    {
                        //zero window
                        eval = -ParitySearch(oppBoard, -alpha - 1, -alpha, depth - 1);
                        if ((eval > alpha) && (eval < beta))
                        {
                            eval = -ParitySearch(oppBoard, -beta, -eval, depth - 1);
                        }
                    }
                    else
                    {
                        eval = -ParitySearch(oppBoard, -beta, -alpha, depth - 1);
                    }
                }

                //reback?

                if (eval > score)
                {
                    score = eval;

                    if (eval > alpha)
                    {
                        if (eval >= beta)
                        {
                            //pruning
                            return(score);
                        }

                        alpha   = eval;
                        foundPv = true;
                    }
                }
            }

            return(score);
        }