/// <summary> /// Performs the tree search. /// </summary> /// <param name="rootState"></param> /// <param name="maxIterations"></param> /// <param name="randomizeState"></param> /// <returns></returns> internal static TreeNode Search(PlayingState rootState, int maxIterations = int.MaxValue, bool randomizeState = true) { var rootNode = new TreeNode(); HandRandomizer randomizer = null; if ((randomizeState) && (rootState.NeedRandomize())) randomizer = new HandRandomizer(rootState); for (var i = 0; i < maxIterations; i++) { var node = rootNode; // 1. Determinize. var state = rootState.CloneAndRandomize(randomizer); // 2. Select. var validMoves = state.GetValidMoves(); while ((validMoves != 0) && (node.GetUntriedMoves(validMoves) == 0)) // The node is fully expanded and non-terminal. { node = node.UcbSelectChild(validMoves); state.DoMove(node.Move); validMoves = state.GetValidMoves(); } // 3. Expand. var untriedMoves = node.GetUntriedMoves(validMoves); if (untriedMoves != 0) { var randomMove = GetRandomMove(untriedMoves, state); var activeIndex = state.ActiveIndex; state.DoMove(randomMove); node = node.AddChild(randomMove, activeIndex); } // 4. Simulate. validMoves = state.GetValidMoves(); while (validMoves != 0) { var randomMove = GetRandomMove(validMoves, state); state.DoMove(randomMove); validMoves = state.GetValidMoves(); } // 5. Backpropagate. while (node != null) { node.UpdateStatistics(state); node = node.Parent; } } return rootNode.GetBestChild(); }
/// <summary> /// Adds a child node to this node. /// </summary> /// <param name="move"></param> /// <param name="activeIndex"></param> /// <returns>A new child node.</returns> internal TreeNode AddChild(Move move, int activeIndex) { var child = new TreeNode { Move = move, ActiveIndex = activeIndex, Parent = this }; if (FirstChild == null) { FirstChild = child; LastChild = child; } else { LastChild.NextSibling = child; LastChild = child; } return child; }