private void AnalyzeNextMoves(Board board, CancellationToken aiCancelToken, out IDictionary <Move, BoardAnalysisData> movesData, out IDictionary <Move, BoardAnalysisDataDiff> dataDiffs) { var localMovesData = new ConcurrentDictionary <Move, BoardAnalysisData>(); var localDataDiffs = new ConcurrentDictionary <Move, BoardAnalysisDataDiff>(); var moves = new ConcurrentQueue <Move>(); foreach (Move move in board.GetMoves()) { moves.Enqueue(move); } Parallel.ForEach(moves, (nextMove) => { aiCancelToken.ThrowIfCancellationRequested(); Board futureBoard = board.Clone(); if (!futureBoard.TryMakeMove(nextMove)) { throw new Exception("Oh noe! Bad move."); } localMovesData[nextMove] = BoardAnalysisData.GetBoardAnalysisData(futureBoard, _weights); localDataDiffs[nextMove] = BoardAnalysisData.Diff(board, futureBoard, _weights); }); movesData = localMovesData; dataDiffs = localDataDiffs; }
private void GetSortedMoves(Board board, CancellationToken aiCancelToken, out IOrderedEnumerable <KeyValuePair <Move, Tuple <BoardAnalysisData, Board> > > orderedAnalysis) { var localMovesData = new ConcurrentDictionary <Move, Tuple <BoardAnalysisData, Board> >(); // I think this parallelism allows for randomness when picking multiple moves that all analyze to the same advantage number Parallel.ForEach(board.GetMoves(), (nextMove, parallelLoopState) => { if (parallelLoopState.ShouldExitCurrentIteration) { parallelLoopState.Stop(); } if (aiCancelToken.IsCancellationRequested) { parallelLoopState.Stop(); } Board futureBoard = board.Clone(); if (!futureBoard.TryMakeMove(nextMove)) { throw new Exception("Oh noe! Bad move."); } localMovesData[nextMove] = new Tuple <BoardAnalysisData, Board>(BoardAnalysisData.GetBoardAnalysisData(futureBoard, _weights), futureBoard); }); aiCancelToken.ThrowIfCancellationRequested(); if (board.whiteToPlay) { orderedAnalysis = localMovesData.OrderByDescending(m => m.Value.Item1.whiteAdvantage); } else { orderedAnalysis = localMovesData.OrderBy(m => m.Value.Item1.whiteAdvantage); } }
private double AnalyzeNextMoves(Board board, double alpha, double beta, int depth, int color, CancellationToken aiCancelToken, out Move bestMove) { aiCancelToken.ThrowIfCancellationRequested(); if (depth == 0 || board.GetMoves().Count == 0) { bestMove = null; return(BoardAnalysisData.GetBoardAnalysisData(board, _weights).whiteAdvantage *color); } var localMovesData = new ConcurrentDictionary <Move, Tuple <BoardAnalysisData, Board> >(); IOrderedEnumerable <KeyValuePair <Move, Tuple <BoardAnalysisData, Board> > > orderedAnalysis; GetSortedMoves(board, aiCancelToken, out orderedAnalysis); double bestScore = double.MinValue; Move localBestMove = orderedAnalysis.First().Key; object _lock = new object(); foreach (var kvp in orderedAnalysis) { Move subBestMove; double score = -AnalyzeNextMoves(kvp.Value.Item2, -beta, -alpha, depth - 1, -color, aiCancelToken, out subBestMove); double oldBestScore = bestScore; bestScore = Math.Max(score, bestScore); if (oldBestScore != bestScore) { localBestMove = kvp.Key; } alpha = Math.Max(alpha, bestScore); if (alpha >= beta) { break; } } ; bestMove = localBestMove; return(bestScore); }
private void DrawGameInfo(Board board) { StringBuilder sb = new StringBuilder(); sb.AppendFormat("White: '{0}' vs. Black: '{1}'\n", _game.whitePlayerName, _game.blackPlayerName); sb.AppendFormat("{0}\n", board.whiteToPlay ? "White Turn" : "Black Turn"); if (board.hivailableHexes.Count == 0) { board.RefreshDependantBoardData(); } var analysisData = BoardAnalysisData.GetBoardAnalysisData(board, BoardAnalysisWeights.winningWeights); sb.AppendFormat("Advantage: {0}\n", analysisData.whiteAdvantage); sb.Append(analysisData.ToString()); TextBlock textBlock = new TextBlock(); textBlock.Text = sb.ToString(); textBlock.Foreground = Brushes.Black; Canvas.SetLeft(textBlock, 5); Canvas.SetTop(textBlock, 5); MainCanvas.Children.Add(textBlock); }