using System.Collections; using System.Collections.Generic; using System; namespace Rokojori { public abstract class TreeWalker where N:class { public abstract N Parent( N node ); public abstract N ChildAt( N node, int index ); public abstract int NumChildren( N node ); public bool HasChildren( N node ) { return NumChildren( node ) > 0; } public bool HasParent( N node ) { return Parent( node ) != null; } public int ChildIndexOf( N node ) { var p = Parent( node ); if ( p == null ) { return -1; } var numKids = NumChildren( p ); for ( var i = 0; i= NumChildren( p ) ) { return null; } return ChildAt( p, index ); } public N NextSibling( N node ) { var index = ChildIndexOf( node ); return SiblingAt( node, index+1 ); } public N PreviousSibling( N node ) { var index = ChildIndexOf( node ); return SiblingAt( node, index-1 ); } public bool HasSiblingAt( N node, int index ) { var p = Parent( node ); if ( p == null || index < 0 || index >= NumChildren( p ) ) { return false; } return true; } public int NumSiblings( N node ) { if ( node == null ) { return 0; } var p = Parent( node ); if ( p == null ) { return 0; } return NumChildren( p ) - 1; } public void IterateSiblings( N node, Action action ) { if ( node == null ) { return; } var p = Parent( node ); if ( p == null ) { return; } var numChildren = NumChildren( p ); for ( int i = 0; i < numChildren; i++ ) { var child = ChildAt( p, i ); if ( child == node ) { continue; } action( child ); } } public N FindSibling( N node, Func evaluater ) { if ( node == null ) { return null; } var p = Parent( node ); if ( p == null ) { return null ; } var numChildren = NumChildren( p ); for ( int i = 0; i < numChildren; i++ ) { var child = ChildAt( p, i ); if ( child == node ) { continue; } var result = evaluater( child ); if ( result ) { return child; } } return null; } public N FirstChild( N node ) { return NumChildren( node )<=0?null:ChildAt( node, 0 ); } public N LastChild( N node ) { var num = NumChildren( node ); return num <= 0 ? null : ChildAt( node, num - 1 ); } public void ForEachChild( N node, bool directChildrenOnly, Action action ) { if ( directChildrenOnly ) { var numChildren = NumChildren( node ); for ( int i = 0; i < numChildren; i++ ) { var child = ChildAt( node, i ); action( child ); } } else { Iterate( node, action, true ); } } public N FindDirectChild( N node, Predicate selector ) { return FindChild( node, true, selector ); } public N FindAnyChild( N node, Predicate selector ) { return FindChild( node, false, selector ); } public N FindChild( N node, bool directChildrenOnly, Predicate selector ) { if ( directChildrenOnly ) { var numChildren = NumChildren( node ); for ( int i = 0; i < numChildren; i++ ) { var child = ChildAt( node, i ); if ( selector( child ) ) { return child; } } } else { return Find( node, selector, true ); } return null; } public N GetDirectChildWithLowestValue( N node, Func getValue ) { return GetChildWithLowestValue( node, true, getValue ); } public N GetAnyChildWithLowestValue( N node, Func getValue ) { return GetChildWithLowestValue( node, false, getValue ); } public N GetChildWithLowestValue( N node, bool directChildrenOnly, Func getValue ) { var lowestValue = float.MaxValue; N childWithLowestValue = null; ForEachChild( node, directChildrenOnly, ( child )=> { var value = getValue( child ); if ( value < lowestValue ) { lowestValue = value; childWithLowestValue = child; } } ); return childWithLowestValue; } public N GetDirectChildWithHighestValue( N node, Func getValue ) { return GetChildWithHighestValue( node, true, getValue ); } public N GetAnyChildWithHighestValue( N node, Func getValue ) { return GetChildWithHighestValue( node, false, getValue ); } public N GetChildWithHighestValue( N node, bool directChildrenOnly, Func getValue ) { var highestValue = -float.MaxValue; N childWithHighestValue = null; ForEachChild( node, directChildrenOnly, ( child )=> { var value = getValue( child ); if ( value > highestValue ) { highestValue = value; childWithHighestValue = child; } } ); return childWithHighestValue; } public N NextNode( N node ) { if ( HasChildren( node ) ) { return FirstChild( node ); } var next = NextSibling( node ); if ( next != null ) { return next; } var parent = Parent( node ); while ( parent != null ) { var n = NextSibling( parent ); if ( n != null ) { return n; } parent = Parent( parent ); } return null; } public N PreviousNode( N node ) { var prev = PreviousSibling( node ); if ( prev != null ) { while ( HasChildren( prev ) ) { prev = LastChild( prev ); } return prev; } return Parent( node ); } public N RootParent( N node ) { node = Parent( node ); if ( node == null ) { return null; } while ( HasParent( node ) ) { node = Parent( node ); } return node; } public N LastGrandChild( N node ) { if ( HasChildren( node ) ) { node = LastChild( node ); while ( HasChildren( node ) ) { node = LastChild( node ); } return node; } return null; } public N NextAfterChildren( N node ) { var lastGrandChild = LastGrandChild( node ); if ( lastGrandChild != null ) { return NextNode( lastGrandChild ); } return NextNode( node ); } public bool IsChildOf( N child, N parent ) { var p = Parent( child ); while ( p != null ) { if ( p == parent ) { return true; } p = Parent( p ); } return false; } public int NumParents( N node ) { var num = 0; var p = Parent( node ); while ( p != null ) { num++; p = Parent( p ); } return num; } public N LastOuterNode( N node ) { var its = 0; var max = 10000; while ( HasChildren( node ) ) { its++; if ( its > max ) { throw new Exception(); } node = LastChild( node ); } return node; } public N NextNonChild( N node ) { return NextNode( LastOuterNode( node ) ); } public N IterationEndOf( N node ) { return NextNonChild( node ); } public N GetInParents( N node, Func predicate ) { var p = Parent( node ); while ( p != null ) { if ( predicate( p ) ) { return p; } p = Parent( p ); } return null; } public int GetAncestorDistance( N child, N ancestor ) { if ( ancestor == null ) { return -1; } if ( child == ancestor ) { return 0; } var p = Parent( child ); var distance = 1; while ( p != null ) { if ( p == ancestor ) { return distance; } p = Parent( p ); distance ++; } return -1; } public int GetDepth( N node, Dictionary depthMap = null ) { if ( depthMap == null ) { var depth = 0; var it = Parent( node ); var maxDepth = 1000; while ( it != null ) { depth ++; if ( depth == maxDepth ) { RJLog.Log( "reached max depth", it ); return depth; } it = Parent( it ); } return depth; } if ( depthMap.ContainsKey( node ) ) { return depthMap[ node ]; } var parent = Parent( node ); if ( parent == null ) { depthMap[ node ] = 0; return 0; } if ( depthMap.ContainsKey( parent ) ) { var parentDepth = depthMap[ parent ]; var nodeDepth = parentDepth + 1; depthMap[ node ] = nodeDepth; return nodeDepth; } depthMap[ node ] = GetDepth( node ); return depthMap[ node ]; } public void DepthIterate( N node, Action callback, bool childrenOnly = false, Dictionary depthMap = null ) { if ( depthMap == null ) { depthMap = new Dictionary(); } var iterationCallback = ( N node )=> { var depth = GetDepth( node, depthMap ); callback( node, depth ); }; Iterate( node, iterationCallback, childrenOnly ); } public void Iterate( N node, Action callback, bool childrenOnly = false ) { var end = IterationEndOf( node ); var it = node; if ( childrenOnly ) { it = NextNode( it ); } while ( it != end ) { callback( it ); it = NextNode( it ); } } public N Find( N node, Predicate predicate, bool childrenOnly ) { var end = IterationEndOf( node ); var it = node; if ( childrenOnly ) { it = NextNode( it ); } while ( it != end ) { if ( predicate( it ) ) { return it; } it = NextNode( it ); } return null; } public void Filter( List list, N node, Predicate predicate, bool childrenOnly ) { Action addToList = ( N n ) => { if ( predicate( n ) ) { list.Add( n ); } }; Iterate( node, addToList, childrenOnly ); } public void FilterAndMap( List list, N node, Predicate predicate, Func mapper, bool childrenOnly ) { Action addToList = ( N n ) => { if ( predicate( n ) ) { list.Add( mapper( n ) ); } }; Iterate( node, addToList, childrenOnly ); } public void Map( List list, N node, Predicate predicate, Func mapper, bool childrenOnly ) { Action addToList = ( N n ) => { list.Add( mapper( n ) ); }; Iterate( node, addToList, childrenOnly ); } public void PruneChildTraversal( N root, Func callback ) { var it = NextNode( root ); while ( it != null && IsChildOf( it, root ) ) { var continueWithChildren = callback( it ); if ( continueWithChildren ) { it = NextNode( it ); } else { it = NextAfterChildren( it ); } } } } }