// 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; }
// Time limited MCTS private Node TimeLimited(State rootState, int timeLimit, Stopwatch timer, Deck deck) { Node rootNode = new Node(null, null, rootState, deck); while (true) { if (timer.ElapsedMilliseconds > timeLimit) { if (FindBestChild(rootNode.Children) == null && !rootNode.state.IsGameOver()) { timeLimit += 10; timer.Restart(); } else { return rootNode; } } Node node = rootNode; State state = rootState.Clone(); Deck clonedDeck = deck.Clone(); // 1: Select while (node.UntriedMoves.Count == 0 && node.Children.Count != 0) { node = node.SelectChild(); state = state.ApplyMove(node.GeneratingMove); if (node.GeneratingMove is ComputerMove) { clonedDeck.Remove(((ComputerMove)node.GeneratingMove).Card); if (clonedDeck.IsEmpty()) clonedDeck = new Deck(); } } // 2: Expand if (node.UntriedMoves.Count != 0) { Move randomMove = node.UntriedMoves[random.Next(0, node.UntriedMoves.Count)]; if (randomMove is ComputerMove) { if (clonedDeck.IsEmpty()) clonedDeck = new Deck(); clonedDeck.Remove(((ComputerMove)randomMove).Card); state = state.ApplyMove(randomMove); node = node.AddChild(randomMove, state, clonedDeck); } else { state = state.ApplyMove(randomMove); node = node.AddChild(randomMove, state, clonedDeck); } } // 3: Simulation while (state.GetMoves(clonedDeck).Count != 0) { Move move = state.GetRandomMove(clonedDeck); if (move is ComputerMove) { if (clonedDeck.IsEmpty()) clonedDeck = new Deck(); clonedDeck.Remove(((ComputerMove)move).Card); state = state.ApplyMove(move); } else { state = state.ApplyMove(move); } } // 4: Backpropagation while (node != null) { node.Update(state.GetResult()); node = node.Parent; } } }