/// <summary> /// Multithreaded version of the FindGoodMove /// </summary> ScoreCorral FindGoodMoveMulti(GameState game, int depth, out IMove bestMove, out int bestEval, bool allMoves) { if (depth != 0) { throw new ApplicationException(); } var depthMoves = _singleThreadData.DepthMoves; while (depth >= _singleThreadData.DepthMoves.Count) { depthMoves.Add(new List <IMove>()); } var moves = depthMoves[depth]; moves.Clear(); EnumerateMoves(moves, game, _randomPositions); ScoreCorral _corral = new ScoreCorral(allMoves); object sync = new object(); Parallel.ForEach <IMove, IterThreadData>(moves, () => { // Initialize a thread's local data var data = new IterThreadData(game); data.BestMove = null; data.BestEval = int.MinValue; return(data); }, (move, loopState, data) => { // make the move move.MakeMove(data.Game); data.Game.Ply++; int eval; bool gameOver; data.Evaluator.Evaluate(data.Game, out eval, out gameOver); if (0 == (data.Game.Ply & 1)) { eval *= -1; } if (!(depth == _maxDepth || gameOver)) { IMove opmove; int opeval; FindGoodMove(data, depth + 1, data.BestMove == null ? (int?)null : -data.BestEval, out opmove, out opeval); eval = opeval * -1; } _corral.AddScore(move, eval); data.Game.Ply--; move.TakeBackMove(data.Game); if (gameOver && eval > 0) { loopState.Stop(); } return(data); }, data => { // do nothing }); bestMove = _corral.bestMove(); bestEval = _corral.bestScore(); return(_corral); }
/// <summary> /// Multithreaded version of the FindGoodMove /// </summary> void FindGoodMoveMulti(GameState game, int depth, out IMove bestMove, out int bestEval) { if (depth != 0) { throw new ApplicationException(); } var depthMoves = _singleThreadData.DepthMoves; while (depth >= _singleThreadData.DepthMoves.Count) { depthMoves.Add(new List <IMove>()); } var moves = depthMoves[depth]; moves.Clear(); EnumerateMoves(moves, game, _randomPositions); IMove sharedBestMove = null; int sharedBestEval = int.MinValue; object sync = new object(); Parallel.ForEach <IMove, IterThreadData>(moves, () => { // Initialize a thread's local data var data = new IterThreadData(game); lock (sync) { data.BestMove = sharedBestMove; data.BestEval = sharedBestEval; } return(data); }, (move, loopState, data) => { // synchronize thread's best move lock (sync) { if (sharedBestEval > data.BestEval) { data.BestEval = sharedBestEval; data.BestMove = sharedBestMove; } } // make the move move.MakeMove(data.Game); data.Game.Ply++; int eval; bool gameOver; data.Evaluator.Evaluate(data.Game, out eval, out gameOver); data.Evals++; if (0 == (data.Game.Ply & 1)) { eval *= -1; } if (!(depth == _maxDepth || gameOver)) { IMove opmove; int opeval; FindGoodMove(data, depth + 1, data.BestMove == null ? (int?)null : -data.BestEval, out opmove, out opeval); eval = opeval * -1; } if (eval > data.BestEval) { data.BestEval = eval; data.BestMove = move; } data.Game.Ply--; move.TakeBackMove(data.Game); // synchronize shared best move lock (sync) { if (data.BestEval > sharedBestEval) { sharedBestEval = data.BestEval; sharedBestMove = data.BestMove; } } if (gameOver && eval > 0) { loopState.Stop(); } return(data); }, data => { _evals += data.Evals; // do nothing }); bestMove = sharedBestMove; bestEval = sharedBestEval; }