예제 #1
0
 public bool Equals(BotMove other) => Figure == other.Figure && Sequence == other.Sequence;
예제 #2
0
        // NegaMax algorithm with alpha/beta, source: https://en.wikipedia.org/wiki/Negamax
        //TODO: append transposition tables
        private BotMove Negamax(SquareBoard board, int depth, int alpha, int beta, Side side, CancellationToken branchToken)
        {
            if (cancellation.IsCancellationRequested ||
                !CanSearchDeeper(board, depth))
            {
                return(BotMove.Empty(Estimate(board)));
            }

            var states = GetStates(board, side);

            if (depth == options.MaxDepth && states.Count == 1)
            {
                var singleState = states[0];
                return(new BotMove(singleState.Figure, singleState.MoveSequence, 0));
            }

            BotMove bestMove = new BotMove(Int32.MinValue);

            var noMoves = true;
            var cts     = new CancellationTokenSource();
            var workers = new List <Task>();

            foreach (var state in states)
            {
                noMoves = false;
                if (cts.IsCancellationRequested)
                {
                    break;
                }
                if (branchToken.IsCancellationRequested)
                {
                    cts.Cancel();
                    break;
                }

                if (states.Count > 1 && _runningWorkersCount < options.DegreeOfParallelism && depth <= options.MaxDepth - 1)
                {
                    Interlocked.Increment(ref _runningWorkersCount);
                    workers.Add(Task.Run(() =>
                    {
                        DoNegamax(state);
                        Interlocked.Decrement(ref _runningWorkersCount);
                    }));
                }
                else
                {
                    DoNegamax(state);
                }
            }

            Task.WaitAll(workers.ToArray());

            if (noMoves)
            {
                return(BotMove.Empty(Estimate(board)));
            }

            return(bestMove);

            void DoNegamax(State state)
            {
                if (options.IsDebug)
                {
                    Log("before", board, side, state, bestMove.Score, depth, alpha, beta);
                }
                var boardAfterMove = new MoveCommandChain(state.Figure, state.Board, state.MoveSequence).Execute();
                var score          = -Negamax(boardAfterMove, depth - 1, -beta, -alpha, SideUtil.Opposite(side), cts.Token).Score;
                var shouldPrun     = false;

                lock (locker)
                {
                    if (score > bestMove.Score)
                    {
                        bestMove = new BotMove(state.Figure, state.MoveSequence, score);
                    }
                    alpha = Math.Max(alpha, bestMove.Score);
                    //let's move cts.Cancel out of the lock scope
                    shouldPrun = options.AllowPrunning && alpha >= beta;
                }
                if (options.IsDebug)
                {
                    Log("after", board, side, state, score, depth, alpha, beta);
                }
                if (shouldPrun)
                {
                    cts.Cancel();
                }
            }
        }