public Node(Move move, Node parent, State state, Deck deck) { this.state = state; this.generatingMove = move; this.parent = parent; this.results = 0; this.visits = 0; this.children = new List<Node>(); this.untriedMoves = state.GetMoves(deck); }
// Runs an entire game using a parallelized version of iterative deepening minimax private Move ParallelIterativeDeepening(State state, int timeLimit, Deck deck) { Move bestMove = new PlayerMove(); List<Move> moves = state.GetMoves(deck); ConcurrentBag<Tuple<double, Move>> scores = new ConcurrentBag<Tuple<double, Move>>(); if (moves.Count == 0) { // game over return bestMove; } // create the resulting states before starting the threads List<State> resultingStates = new List<State>(); foreach (Move move in moves) { State resultingState = state.ApplyMove(move); resultingStates.Add(resultingState); } Parallel.ForEach(resultingStates, resultingState => { double score = IterativeDeepening(resultingState, timeLimit, deck.Clone()).Score; scores.Add(new Tuple<double, Move>(score, resultingState.GeneratingMove)); }); // find the best score double highestScore = Double.MinValue; foreach (Tuple<double, Move> score in scores) { PlayerMove move = (PlayerMove)score.Item2; if (score.Item1 > highestScore) { highestScore = score.Item1; bestMove = score.Item2; } } return bestMove; }
// Parallel time limited MCTS private DIRECTION ParallelTimeLimitedMCTS(State currentState, int timeLimit, Deck deck) { ConcurrentBag<Node> allChildren = new ConcurrentBag<Node>(); int numOfChildren = currentState.GetMoves(deck).Count; Stopwatch timer = new Stopwatch(); timer.Start(); Parallel.For(0, NUM_THREADS, i => { Node resultRoot = TimeLimited(currentState, timeLimit, timer, deck); foreach (Node child in resultRoot.Children) { allChildren.Add(child); } }); timer.Stop(); List<int> totalVisits = new List<int>(4) { 0, 0, 0, 0 }; List<double> totalResults = new List<double>(4) { 0, 0, 0, 0 }; foreach (Node child in allChildren) { int direction = (int)((PlayerMove)child.GeneratingMove).Direction; totalVisits[direction] += child.Visits; totalResults[direction] += child.Results; } double best = Double.MinValue; int bestDirection = -1; for (int k = 0; k < 4; k++) { double avg = totalResults[k] / totalVisits[k]; if (avg > best) { best = avg; bestDirection = k; } } if (bestDirection == -1) return (DIRECTION)(-1); return (DIRECTION)bestDirection; }