/// <summary> /// If the argument node has been visited at least T times, the node is expanded by advancing the PositionGenerator (or creating one if it is undefined) and adding the new child to the node. /// </summary> /// <param name="context">The context of the search.</param> /// <param name="node">The node that is to be expanded.</param> /// <param name="state">The state to expand from.</param> /// <returns>The argument node if it has been visited less than T time, or if no more expansion is possible, otherwise the newly created child node.</returns> public TreeSearchNode <P, A> Expand(SearchContext <D, P, A, S, Sol> context, TreeSearchNode <P, A> node, P state) { // No expansion before T visits, except for the root. if (node.Visits < T && !node.IsRoot()) { return(node); } // Create a position generator if there is not one set in the node yet. var positionGenerator = node.PositionGenerator; if (positionGenerator == null) { var expansion = context.Expansion; positionGenerator = expansion.Expand(context, state); node.PositionGenerator = positionGenerator; } // Move the PositionGenerator to the next item, if available (note: PositionGenerator initialises to before the first item). if (!positionGenerator.MoveNext()) { return(node); } var child = new TreeSearchNode <P, A>(positionGenerator.Current); node.AddChild(child); child.Parent = node; return(child); }
/// <summary> /// Selects an Action by using the NaïveSampling method and expands the tree with this action if it is not already present. /// </summary> /// <param name="context">The current search context.</param> /// <param name="node">The node from which to expand the tree.</param> /// <param name="gMAB">The global Multi-Armed-Bandit collection.</param> /// <param name="endTime">When running on a time budget, this indicates when the search should stop.</param> /// <param name="it">The iteration count of the main search.</param> /// <returns>A <see cref="TreeSearchNode{S,A}"/> from which represents the selected node for the Simulation phase.</returns> private TreeSearchNode <P, A> NaïveSelectAndExpand(SearchContext <D, P, A, S, Sol> context, TreeSearchNode <P, A> node, IDictionary <long, Dictionary <int, LocalArm> > gMAB, DateTime endTime, ref int it) { // a = NaïveSampling(node.state, node.state.currentPlayer) // if `a' leads to a child of `node' // then // return SelectAndExpand(node.GetChild(a)) // else // newNode = Apply(node.state, a) // node.AddChild(newNode, a) // return newNode // Find an action through the NaïveSampling process var action = NaïveSampling(context, node.State, gMAB); var actionHash = action.GetHashCode(); // Check if any of the children of the current node have the sampled action as their payload var existingChild = node.Children.FirstOrDefault(i => i.PayloadHash == actionHash); if (existingChild != null) { // Move down the tree unless we have reached a terminal node, or are out of time if (existingChild.State.IsTerminal() || (Time != Constants.NO_LIMIT_ON_THINKING_TIME && DateTime.Now >= endTime)) { return(existingChild); } // Increase the iteration count, since we'll be doing more sampling and simulating it++; return(NaïveSelectAndExpand(context, existingChild, gMAB, endTime, ref it)); } // If none of the current children on the node have the action as payload, create a new child var newState = context.Application.Apply(context, context.Cloner.Clone(node.State), action); var newNode = new TreeSearchNode <P, A>(node, newState, action); // Add it to the node's children and return the child node.AddChild(newNode); return(newNode); }