/// <summary>
        /// Generates all immediate children of the specified node
        /// WARNING: this method is not thread-safe, run it in parallel only
        /// for nodes in non-overlapping subtrees
        /// </summary>
        public void GenerateAllChildren(AnalysisNode parent, uint depth,
            bool is_restore_missing_positions = true)
        {
            Debug.Assert(parent != null && parent.Position != null);
            Debug.Assert(depth > 0);

            // Check if all moves were generated for the parent node
            // If not, clear the list of children and re-generate them all
            if (parent.IsSomeChildrenErased)
            {
                parent.SetChildrenList(null);
            }

            if (parent.Children == null)
            {
                parent.InitChildrenList();
                // TODO - conside memory pooling for the list of moves
                var moves = new List<Move>(64);
                MovesGenerator.GenerateMoves(parent.Position, moves);
                var player_to_move = parent.Position.PlayerToMove;
                bool is_parent_in_check = parent.Position.IsInCheck;
                foreach (var m in moves)
                {
                    var child_position = parent.Position.PlayMove(m);
                    // Last check if the move is a legal move
                    // Didn't do it earlier, as we need resulting position
                    // for this
                    if (!PositionValidator.IsMyMovePutsMyKingInCheck(
                        player_to_move, m, child_position, is_parent_in_check))
                    {
                        parent.Children.Add(new AnalysisNode(parent, child_position,
                            m));
                        Interlocked.Increment(ref m_node_count);
                    }
                }
                // Let the position to know whether there are legal moves
                parent.Position.HasLegalMoves = !parent.IsLeaf;
            }
            else if (is_restore_missing_positions)
            {
                foreach (var node in parent.Children)
                {
                    if (node.Position == null)
                    {
                        // Position object was destroyed to free the memory
                        // Re-create it now
                        node.RecreatePosition();
                    }
                }
            }

            // Indicate that all children are generated and present in the collection
            // Unless we have generated the moves having some restrictions imposed
            parent.IsSomeChildrenErased = false;

            // Generate next levels of child nodes recursively
            if (depth > 1)
            {
                foreach (var node in parent.Children)
                {
                    GenerateAllChildren(node, depth - 1, is_restore_missing_positions);
                }
            }

            if (ReferenceEquals(parent, Root))
            {
                m_listener.RootChildrenGenerated(Root.Children);
            }
        }
        /// <summary>
        /// Erases all children nodes which satisfy the specified condition
        /// WARNING: this method is not thread-safe, run it in parallel only
        /// for nodes in non-overlapping subtrees
        /// </summary>
        public void ReleaseChildren(Predicate<AnalysisNode> condition,
            AnalysisNode subtree_root)
        {
            if (subtree_root.Children == null)
            {
                return;
            }

            List<AnalysisNode> new_children = null;
            foreach (var child in subtree_root.Children)
            {
                if (condition(child))
                {
                    ReleaseNode(child);
                }
                else
                {
                    if (new_children == null)
                    {
                        new_children = new List<AnalysisNode>(
                            subtree_root.Children.Count);
                    }
                    new_children.Add(child);
                }
            }

            if (new_children == null
                || (new_children.Count != subtree_root.Children.Count))
            {
                subtree_root.IsSomeChildrenErased = true;
                subtree_root.SetChildrenList(new_children);
            }
        }
 // Assumes the tree is locked
 private void ReleaseNode(AnalysisNode subtree_root)
 {
     if (subtree_root.Children != null)
     {
         foreach (var child in subtree_root.Children)
         {
             ReleaseNode(child);
         }
         subtree_root.SetChildrenList(null);
     }
     Interlocked.Decrement(ref m_node_count);
 }
 /// <summary>
 /// Erases all children nodes
 /// WARNING: this method is not thread-safe, run it in parallel only
 /// for nodes in non-overlapping subtrees
 /// </summary>
 public void ReleaseChildren(AnalysisNode subtree_root)
 {
     if (subtree_root.Children != null)
     {
         foreach (var child in subtree_root.Children)
         {
             ReleaseNode(child);
         }
     }
     subtree_root.IsSomeChildrenErased = true;
     subtree_root.SetChildrenList(null);
 }