コード例 #1
0
        // should only be called by MinMaxWorker, since it initializes a bunch of stuff
        private SolvedMove MinMaxMove(AITask aiTask, Move move, SolvedMove lastSolvedMove)
        {
            if (lastSolvedMove != null)
            {
                lastSolvedMove.startSolvingMove = move;
                aiTask.onMoveComplete(lastSolvedMove);
            }
            Stopwatch stopWatch = new Stopwatch();

            stopWatch.Start();
            boardHash = HashBoard.ApplyMove(aiTask.board, move, boardHash);
            ulong currentBoardHash = boardHash;

            lock (stateLock) {
                if (alreadySolved.Contains(move))
                {
                    // if the hash has board has already been analyzed then skip
                    boardHash = HashBoard.ApplyMove(aiTask.board, move, boardHash);
                    return(null);
                }
                if (min > bestScore)
                {
                    bestScore = min;
                }
            }
            aiTask.board.Move(move);
            var startedFromMin    = min;
            var detectWinnerMoves = aiTask.board.GetMoves();
            // check for winner
            var winner = aiTask.board.detectWinner(detectWinnerMoves);

            if (winner != Winner.NONE)
            {
                float score = 0;
                if ((winner == Winner.WINNER_WHITE || winner == Winner.WINNER_BLACK))
                {
                    // if a checkmate is found then no deeper moves matter since we are going to play that move
                    score = float.MaxValue - aiTask.board.VirtualLevel;
                }
                else if (winner == Winner.DRAW)
                {
                    score = 0;
                }
                lock (stateLock) {
                    alreadySolved.Add(move);

                    min = Math.Max(score, min);
                }
                stopWatch.Stop();
                return(new SolvedMove()
                {
                    startFromMin = min,
                    min = min,
                    max = max,
                    durationMS = stopWatch.ElapsedMilliseconds,
                    move = new EvaluatedMove()
                    {
                        move = move,
                        score = score
                    },
                    taskId = currentTask.taskId,
                });
            }
            if (aiTask.tiedPositions.Contains(currentBoardHash))
            {
                float score = 0;
                lock (stateLock) {
                    alreadySolved.Add(move);

                    min = Math.Max(score, min);
                }
                return(new SolvedMove()
                {
                    startFromMin = min,
                    min = min,
                    max = max,
                    durationMS = stopWatch.ElapsedMilliseconds,
                    taskId = currentTask.taskId,
                    move = new EvaluatedMove()
                    {
                        move = move,
                        score = score,
                    },
                });
            }


            aiTask.board.VirtualLevel++;
            var moveScore = minmax.MinMax(aiTask.board, aiTask.depth, aiTask.tiedPositions, false, min, max);

            aiTask.board.VirtualLevel--;
            aiTask.board.UndoMove(move);
            boardHash = HashBoard.ApplyMove(aiTask.board, move, boardHash);
            lock (stateLock) {
                if (alreadySolved.Contains(move))
                {
                    //Console.WriteLine($"collision! refound found move! {MoveHelper.ReadableMove(move)}");
                    // if the hash has board has already been analyzed before this thread managed to do it, then skip
                    return(null);
                }

                // optimize for player
                if (moveScore > bestScore)
                {
                    bestScore = moveScore;
                }

                min = Math.Max(moveScore, min);


                alreadySolved.Add(move);
            }
            // outside of stateLock because otherwise it will trigger will trigger the lock in moveSolved
            Thread t = Thread.CurrentThread;

            stopWatch.Stop();
            return(new SolvedMove()
            {
                startFromMin = startedFromMin,
                min = min,
                max = max,
                durationMS = stopWatch.ElapsedMilliseconds,
                move = new EvaluatedMove()
                {
                    move = move,
                    score = moveScore
                },
                taskId = currentTask.taskId
            });
        }
コード例 #2
0
        // start by solving your own threads problems
        // afterwards start solving moves that belong to other that have not been started yet
        // if there are only started moves left then start working a move that is already beeing worked on (they might have a worse starting minimum score)
        internal void MinMaxWorker(AITask aiTask)
        {
            currentTask = aiTask;
            Board               board          = aiTask.board;
            List <Move>         moves          = aiTask.moves[aiTask.taskId];
            int                 depth          = aiTask.depth;
            Action <SolvedMove> onMoveComplete = aiTask.onMoveComplete;

            lock (stateLock) {
                max = float.MaxValue;
                min = float.MinValue;
                alreadySolved.Clear();
                begunMoves.Clear();
            }

            bestScore = float.MinValue;

            boardHash = HashBoard.hash(board);

            SolvedMove lastSolvedMove = null;

            // ------------ start working on this threads moves ------------------
            foreach (var move in moves)
            {
                // check that the other threads have not begun the next move yet
                if (!alreadySolved.Contains(move) && !begunMoves.Contains(move))
                {
                    lastSolvedMove = MinMaxMove(aiTask, move, lastSolvedMove);
                }
            }

            // ------------ start searching for other threads unfinished work --------------
            IEnumerable <Move> availableMoves = new List <Move>();
            Random             random         = new Random();

            do
            {
                availableMoves = aiTask.moves.SelectMany((threadsMoves) => {
                    return(threadsMoves.Where(move => !alreadySolved.Contains(move) && !begunMoves.Contains(move)));
                }).ToList();

                // use random to avoid conflicts
                var nextMove = availableMoves.RandomElementUsing(random);
                if (MoveHelper.isValidMove(nextMove))
                {
                    lastSolvedMove = MinMaxMove(aiTask, nextMove, lastSolvedMove);
                }
            } while (availableMoves.Count() > 0);

            // ------------ start searching for other threads begun but unfinished work --------------
            do
            {
                availableMoves = aiTask.moves.SelectMany((threadsMoves) => {
                    return(threadsMoves.Where(move => !alreadySolved.Contains(move)));
                }).ToList();

                // use random to avoid conflicts
                var nextMove = availableMoves.RandomElementUsing(random);
                if (MoveHelper.isValidMove(nextMove))
                {
                    lastSolvedMove = MinMaxMove(aiTask, nextMove, lastSolvedMove);
                }
            } while (availableMoves.Count() > 0);

            if (lastSolvedMove != null)
            {
                aiTask.onMoveComplete(lastSolvedMove);
            }
        }
コード例 #3
0
        private async Task <List <EvaluatedMove> > delegateToWorkers(Board board, List <EvaluatedMove> moves, int depth, HashSet <ulong> tiedBoards, Action <AIProgress> onProgress = null)
        {
            EvalBoard.initThreadStaticVariables();
            int workerWorkId = random.Next();

            lock (stateLock) {
                workId = workerWorkId;
            }
            solvedMoves.Clear();
            //var minmax = new MinMaxAI();
            // get shallow minMax to figure out a initial ordering, which will be used to share out
            //var moves = minmax.MinMaxList(board, 2);
            //var moves = Board.GetMoves(board)
            //    .Where(move => Board.IsLegalMove(board, move))
            //    .Select(move => new BestMove() { move = move, score = 10 })
            //    .ToList();
            // create a list of moves foreach worker
            List <List <Move> > workerMoves = workers.Select((worker) => new List <Move>()).ToList();

            // the idea here is that every worker gets the complete list of moves to try but they start at different points
            // the goal is to find the best move as soon as possible as possible and then share it to all other threads
            // therefor the moves are sorted first and then given out so the first worker
            // worker 1: 1,4,7,10,
            // worker 2: 2,5,8,11,
            // worker 3: 3,6,9,12,
            for (int i = 0; i < moves.Count; i++)
            {
                var move = moves[i];
                workerMoves[i % workerMoves.Count].Add(move.move);
            }

            CancellationTokenSource cancelationSource = new CancellationTokenSource();
            var cancelationtoken = cancelationSource.Token;

            int moveCount = moves.Count;


            object alreadyCompletedLock = new object();

            try {
                var task = new Task(() => {
                    for (int i = 0; i < workers.Count; i++)
                    {
                        var worker = workers[i];
                        var aiTask = new AITask()
                        {
                            taskId         = i,
                            board          = board.CreateCopy(),
                            moves          = workerMoves,
                            depth          = depth,
                            tiedPositions  = tiedBoards,
                            onMoveComplete = (solvedMove) => {
                                int count  = 0;
                                bool isNew = false;
                                lock (stateLock) {
                                    if (workId != workerWorkId)
                                    {
                                        // if the worker returned to late then refuse the task
                                        return;
                                    }
                                    var exists = solvedMoves.Count(move => move.move.move.Equals(solvedMove.move.move));
                                    if (exists == 0)
                                    {
                                        isNew = true;
                                        solvedMoves.Add(solvedMove);
                                        foreach (var otherWorker in workers)
                                        {
                                            if (worker != otherWorker)
                                            {
                                                otherWorker.moveSolved(solvedMove);
                                            }
                                        }
                                        count = solvedMoves.Count;
                                        if (solvedMoves.Count >= moveCount)
                                        {
                                            cancelationSource.Cancel();
                                        }
                                    }
                                }
                                if (onProgress != null && isNew)
                                {
                                    totalFound++;
                                    onProgress(new AIProgress()
                                    {
                                        foundScore = solvedMove.move.score,
                                        total      = totalMoves,
                                        progress   = totalFound,
                                        move       = solvedMove,
                                        depth      = depth
                                    });
                                }
                            }
                        };
                        worker.tasks.Enqueue(aiTask);
                    }
                    // max wait for 3 minutes
                    Task.Delay(1000 * 60 * 3).Wait();
                    cancelationSource.Cancel();
                });

                task.Start();
                //while (!alreadyComplete) {
                //    Task.Delay(10).GetAwaiter().GetResult();
                //}
                //lock(alreadyCompleteLock) {
                //    wasComplated = alreadyComplete;
                //}
                //if(!wasComplated) {

                task.Wait(cancelationtoken);
                //}
            } catch (OperationCanceledException) {
                // intentional cancel
            }


            return(solvedMoves.Select(move => move.move).OrderBy(move => move.score).Reverse().ToList());
        }