Esempio n. 1
0
 public bool Equals(TreeSearchNode <S, A> other)
 {
     if (other is null)
     {
         return(false);
     }
     if (ReferenceEquals(this, other))
     {
         return(true);
     }
     return(GetHashCode() == other.GetHashCode());
 }
Esempio n. 2
0
        /// <summary>
        /// Determines if this TreeSearchNode is an ancestor of the provided TreeSearchNode (i.e. when traversing the tree upwards, if this TreeSearchNode is encountered).
        /// </summary>
        /// <param name="descendant">TreeSearchNode that is a potential descendant of this TreeSearchNode.</param>
        /// <returns>Whether or not the argument TreeSearchNode is a descendant of this TreeSearchNode.</returns>
        public bool IsAncestorOf(TreeSearchNode <S, A> descendant)
        {
            while (!descendant.IsRoot())
            {
                if (descendant.Equals(this))
                {
                    return(true);
                }
                descendant = descendant.Parent;
            }

            return(false);
        }
Esempio n. 3
0
        /// <summary>
        /// Determines if this TreeSearchNode is a descendant of the provided TreeSearchNode (i.e. when traversing the tree upwards, if the argument TreeSearchNode is encountered).
        /// </summary>
        /// <param name="ancestor">TreeSearchNode that is a potential ancestor of this TreeSearchNode.</param>
        /// <returns>Whether or not the argument TreeSearchNode is an ancestor of this TreeSearchNode.</returns>
        public bool IsDescendantOf(TreeSearchNode <S, A> ancestor)
        {
            // A TreeSearchNode cannot be it's own ancestor
            if (Equals(ancestor))
            {
                return(false);
            }

            var node = this;

            while (!node.IsRoot())
            {
                node = node.Parent;

                if (node.Equals(ancestor))
                {
                    return(true);
                }
            }

            return(false);
        }
        /// <summary>
        /// Returns the child node of the argument node that has the best score to visits ratio.
        /// </summary>
        /// <param name="context">The context of the search.</param>
        /// <param name="node">The node from which to select the best child.</param>
        /// <returns>The child node of the argument node that has the best score to visits ratio.</returns>
        public TreeSearchNode <P, A> SelectFinalNode(SearchContext <D, P, A, S, Sol> context, TreeSearchNode <P, A> node)
        {
            var max = double.MinValue;
            var numberOfChildren = node.Children.Count;
            // This makes sure a random node is returned if all ratios are equal.
            var maxIndex = new Random().Next(numberOfChildren);

            for (var i = 0; i < numberOfChildren; i++)
            {
                var child = node.Children.ElementAt(i);

                // Don't consider nodes without visits (also to avoid divide-by-zero).
                if (child.Visits == 0)
                {
                    continue;
                }

                var nodeScore  = child.Score;
                var childRatio = nodeScore / child.Visits;

                if (!(childRatio > max))
                {
                    continue;
                }

                max      = childRatio;
                maxIndex = i;
            }

            // Return the child with the maximum ratio.
            return(node.Children.ElementAt(maxIndex));
        }
 public int Compare(TreeSearchNode <P, A> x, TreeSearchNode <P, A> y)
 {
     return(y.CalculateScore(_nodeEvaluation).CompareTo(x.CalculateScore(_nodeEvaluation)));
 }
        /// <summary>
        /// Selects the next node, given the argument node.
        /// </summary>
        /// <param name="context">The context of the search.</param>
        /// <param name="node">The node from which to select the next node.</param>
        /// <returns>The next node.</returns>
        public TreeSearchNode <P, A> SelectNextNode(SearchContext <D, P, A, S, Sol> context, TreeSearchNode <P, A> node)
        {
            // Determine the minimum number of visits on the parent node required before using evaluation.
            var numberOfChildren  = node.Children.Count;
            var minVisitsOnParent = MinVisits * numberOfChildren;

            // In default behaviour, we will have iterated over all children once before arriving at the first call to the Selection Strategy.
            // If the parent node hasn't been visited a minimum number of times, select the next appropriate child.
            if (minVisitsOnParent > node.Visits)
            {
                return(node.Children.ElementAt(node.Visits % numberOfChildren));
            }

            if (minVisitsOnParent == node.Visits)
            {
                node.Children = node.Children.OrderByDescending(i => i.CalculateScore(NodeEvaluation)).ToList();
            }
            else
            {
                // The first child is always the one picked; so it is the only node we need to sort to a new location.
                // Pick it, and ensure it's at its required location.
                var firstChild = node.Children.First();

                // Update the score and remove dirty.
                firstChild.CalculateScore(NodeEvaluation);

                var i = 1;
                for (; i < node.Children.Count; i++)
                {
                    if (firstChild.CalculateScore(NodeEvaluation) >= node.Children.ElementAt(i).CalculateScore(NodeEvaluation))
                    {
                        break;
                    }
                }
                i--;

                if (i <= 0)
                {
                    return(node.Children.First());
                }
                // Move everyone by one, and set the child at its newest index.
                if (i == 1)
                {
                    // Special case where we optimise for when we are just better than the second item (often).
                    var items = node.Children.ToArray();
                    items[0]      = items[1];
                    items[1]      = firstChild;
                    node.Children = items.ToList();
                }
                else
                {
                    var items = node.Children.ToArray();
                    Array.Copy(items, 1, items, 0, i);
                    items[i]      = firstChild;
                    node.Children = items.ToList();
                }
            }

            return(node.Children.First());
        }
        /// <summary>
        /// Propagate an evaluation value of the argument state starting from the argument node back up to the root node.
        /// </summary>
        /// <param name="context">The context of the search.</param>
        /// <param name="evaluation">The strategy used to evaluate the state.</param>
        /// <param name="node">The node from which the backpropagation starts.</param>
        /// <param name="state">The state that should be evaluated.</param>
        public void BackPropagate(SearchContext <D, P, A, S, Sol> context, IStateEvaluation <D, P, A, S, Sol, TreeSearchNode <P, A> > evaluation, TreeSearchNode <P, A> node, P state)
        {
            // Evaluate the state with respect to the argument node.
            var value = evaluation.Evaluate(context, node, state);

            do
            {
                // Visit the node with the evaluation value.
                node.Visit(value);

                // Keep moving up the tree while there is a valid parent.
            } while ((node = node.Parent) != null);
        }
        /// <summary>
        /// Propagate an evaluation value of the argument state starting from the argument node back up to the root node.
        /// </summary>
        /// <param name="context">The context of the search.</param>
        /// <param name="evaluation">The strategy used to evaluate the state.</param>
        /// <param name="node">The node from which the backpropagation starts.</param>
        /// <param name="state">The state that should be evaluated.</param>
        public void BackPropagate(SearchContext <D, P, A, S, Sol> context, IStateEvaluation <D, P, A, S, Sol, TreeSearchNode <P, A> > evaluation, TreeSearchNode <P, A> node, P state)
        {
            // Evaluate the state with respect to the argument node.
            var value = evaluation.Evaluate(context, node, state);

            // The root player is the current player in the search's source state.
            var rootPlayer = context.Source.CurrentPlayer();

            do
            {
                // Check whether or not this node is a root player's node.
                var targetPlayer = node.IsRoot() || rootPlayer == node.Payload.Player();

                // Visits the node with a coloured evaluation value.
                node.Visit(targetPlayer ? value : -value);

                // Keep moving up the tree while there is a valid parent.
            } while ((node = node.Parent) != null);
        }
Esempio n. 9
0
 /// <summary>
 /// Adds a child to this TreeSearchNode's Children.
 /// </summary>
 /// <param name="child">The TreeSearchNode to add as a child.</param>
 public void AddChild(TreeSearchNode <S, A> child)
 {
     Children.Add(child);
 }
Esempio n. 10
0
 /// <summary>
 /// Constructor that creates a TreeSearchNode with a parent node, a world-state and a payload.
 /// </summary>
 /// <param name="parent">The parent node of the node.</param>
 /// <param name="state">The state that this TreeSearchNode represents.</param>
 /// <param name="payload"><see cref="Node{A}.Payload"/></param>
 public TreeSearchNode(TreeSearchNode <S, A> parent, S state, A payload) : base(state, payload)
 {
     Parent   = parent;
     Children = new List <TreeSearchNode <S, A> >();
 }