正常に動作するチェスゲーム用のシングルスレッドのmin-maxアルゴリズムを作成しました。現在、使用可能なすべてのCPUコアを使用するように書き直そうとしていますが、正しく機能させることができません。
私の考えは、システム上のコア(私の場合は4)と同じ数のスレッドを生成し、スレッドが作業項目をキューに追加したり、キューから削除したりできるようにすることです。これらの各作業項目は「CalculateState」であり、ボード上でx回移動した後に可能なチェス盤に関する情報を保持します。
ワークアイテムがmaxDepthでスポーンされると、チェス盤を評価し、その値を「返し」ます。戻りは、(再帰をシミュレートするために)調べられた動きのツリーでその値を上向きに伝播することによって行われます。
アルゴリズムの開始:
private readonly ConcurrentPriorityQueue<int, CalculateState> _calculateStates = new ConcurrentPriorityQueue<int, CalculateState>();
private Thread[] _threads = new Thread[Environment.ProcessorCount];
private const int MaxDepth = 3;
private PlayerColor _maxPlayer;
public Move CalculateMoveMultithreaded(ChessBoard board)
{
_maxPlayer = board.TurnToMove;
var parentState = new CalculateState(null, null, 0, null, int.MaxValue, int.MinValue, board.TurnToMove);
foreach (var move in board.GetPossibleMoves())
{
move.MakeMove(board);
var newState = ChessStateTransforms.TransformChessBoardToState(board);
move.UnMakeMove(board);
_calculateStates.Enqueue(MaxDepth, new CalculateState(move, newState, 1, parentState, int.MaxValue, int.MinValue, Player.OppositeColor(board.TurnToMove)));
}
for (var i = 0; i < _threads.Length; i++)
{
var calculationThread = new Thread(DoWork);
_threads[i] = calculationThread;
calculationThread.Start();
}
foreach (var thread in _threads)
{
thread.Join();
}
return parentState.MoveToMake;
}
スレッドの実行:
private void DoWork()
{
while (true)
{
KeyValuePair<int, CalculateState> queueItem;
if (!_calculateStates.TryDequeue(out queueItem))
break;
var calculateState = queueItem.Value;
var board = ChessStateTransforms.TransformChessStateIntoChessBoard(calculateState.ChessState);
if (calculateState.Depth == MaxDepth)
{
var boardValue = board.ValueOfBoard(_maxPlayer);
calculateState.PropergateValue(boardValue);
continue;
}
foreach (var move in board.GetPossibleMoves())
{
move.MakeMove(board);
var newState = ChessStateTransforms.TransformChessBoardToState(board);
move.UnMakeMove(board);
_calculateStates.Enqueue(MaxDepth - calculateState.Depth, new CalculateState(calculateState.MoveToMake, newState, calculateState.Depth + 1, calculateState, calculateState.MinValue, calculateState.MaxValue, Player.OppositeColor(board.TurnToMove)));
}
}
}
作業項目のコンテキスト。
private class CalculateState
{
public readonly PlayerColor Turn;
public int MaxValue;
public int MinValue;
public readonly int Depth;
public readonly ChessState ChessState;
public Move MoveToMake;
private readonly CalculateState _parentState;
public CalculateState(Move moveToMake, ChessState chessState, int depth, CalculateState parentState, int minValue, int maxValue, PlayerColor turn)
{
Depth = depth;
_parentState = parentState;
MoveToMake = moveToMake;
ChessState = chessState;
MaxValue = maxValue;
Turn = turn;
MinValue = minValue;
}
public void PropergateValue(int value, Move firstMove = null)
{
lock (this)
{
if (Turn == _maxPlayer)
{
if (value > MaxValue)
{
MaxValue = value;
if (Depth == 0)
{
MoveToMake = firstMove;
return;
}
_parentState.PropergateValue(MaxValue, MoveToMake);
}
}
else
{
if (value < MinValue)
{
MinValue = value;
if (Depth == 0)
{
MoveToMake = firstMove;
return;
}
_parentState.PropergateValue(MinValue, MoveToMake);
}
}
}
}
}
アルゴリズムは敵の駒を奪う動きを返しますが、それ自体をまったく保護しません。チェス盤、移動、valueofboardなどのコードは正しいと確信しています。問題は、マルチスレッド/propegate値コードのようになっている必要があります。私はこれで一週間以上髪を引き裂いてきました、そして本当に助けていただければ幸いです。
ありがとう