コード例 #1
0
        public int Evaluate(SquareBoard board, Side side)
        {
            var enemySide = SideUtil.Opposite(side);

            var score = SideScore(board.GetAll(side)) - SideScore(board.GetAll(enemySide));

            return(score);
        }
コード例 #2
0
ファイル: NegaMaxBot.cs プロジェクト: IvanYuriev/Checkers
        //HOWTO: make it possible to visualize search progress - let WPF to see each State and decisions?

        public BotMove FindBestMove(SquareBoard board, Side botSide, CancellationToken cancellation, BotOptions options = default)
        {
            this.options      = options ?? new BotOptions();
            this.botSide      = botSide;
            this.playerSide   = SideUtil.Opposite(botSide);
            this.cancellation = cancellation;

            return(Negamax(board, this.options.MaxDepth, Int32.MinValue + 1, Int32.MaxValue, botSide, CancellationToken.None));
        }
コード例 #3
0
 private Point GetJumpPoint(Figure figure, Func <Point, int, Point> direction, out Figure neighbour)
 {
     neighbour = board.Get(direction(figure.Point, 1));
     if (neighbour.Side == SideUtil.Opposite(figure.Side))
     {
         var doubleStep = direction(figure.Point, 2);
         if (board.IsEmpty(doubleStep))
         {
             return(doubleStep);
         }
     }
     return(Point.Nop);
 }
コード例 #4
0
        private void CheckForWin()
        {
            // TODO: extract it into Rules class - because there are a lot of draw cases (pretty complex)
            var validEnemyMoves = _rulesProvider.GetMoves(Board, SideUtil.Opposite(SideUtil.Convert(CurrentPlayer.Side)));

            if (validEnemyMoves.Count == 0)
            {
                _winnerIndex = CurrentPlayerIndex;
                Status       = _winnerIndex == 0 ? GameStatus.Player1Wins : GameStatus.Player2Wins;
                //_isRunning = false;
                //TODO: potentially it's ok to undo move after game is over?
                // - don't stop the game with _isRunning = false
                // - then Undo should unmark it?
                // - then to be able to make Redo should store it in History
                // etc.
            }
        }
コード例 #5
0
ファイル: NegaMaxBot.cs プロジェクト: IvanYuriev/Checkers
        // 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();
                }
            }
        }