class Node:
def __init__(self, name=None, parent=None, available=True):
self.name = name
self.parent = parent
self.available = available
self.children = []
@property
def next_sibling(self):
"""Return next node on the same level."""
try:
return self.parent.children[self.parent.children.index(self)+1]
except (AttributeError, IndexError):
return None
@property
def next_node(self):
"""Return next available node using depth-first search."""
def f(node):
return node if node.available else node.next_node
if self.available and self.children:
return f(self.children[0])
elif self.next_sibling:
return f(self.next_sibling)
node = self
while node.parent is not None:
node = node.parent
if node.next_sibling:
return f(node.next_sibling)
return None
def print_tree(node, only_available=False):
todo = [node]
while todo:
node = todo.pop()
if only_available and not node.available:
continue
todo.extend(reversed(node.children))
print(node.name + (' (unavailable)' if not node.available else ''))
def traverse(node):
while True:
print(node.name)
node = node.next_node
if not node:
break
grandparent = Node(name='grandparent')
parent0 = Node(name=' parent0', parent=grandparent)
parent1 = Node(name=' parent1', parent=grandparent)
parent2 = Node(name=' parent2', parent=grandparent, available=False)
parent3 = Node(name=' parent3', parent=grandparent)
child0 = Node(name=' child0', parent=parent0, available=False)
child1 = Node(name=' child1', parent=parent0, available=False)
child2 = Node(name=' child2', parent=parent1, available=False)
child3 = Node(name=' child3', parent=parent1)
child4 = Node(name=' child4', parent=parent2)
child5 = Node(name=' child5', parent=parent3)
child6 = Node(name=' child6', parent=parent3, available=False)
grandchild0 = Node(name=' grandchild0', parent=child0)
grandchild1 = Node(name=' grandchild1', parent=child0)
grandchild2 = Node(name=' grandchild2', parent=child3)
grandparent.children = [parent0, parent1, parent2, parent3]
parent0.children = [child0, child1]
parent1.children = [child2, child3]
parent2.children = [child4]
parent3.children = [child5, child6]
child0.children = [grandchild0, grandchild1]
child3.children = [grandchild2]
print('Full node tree:\n')
print_tree(grandparent, only_available=False)
print('\n\nGoal sequence:\n')
print_tree(grandparent, only_available=True)
print('\n\nTraverse using Node.next_node() method (must be equal to "Goal sequence"):\n')
traverse(grandparent)
Y2xhc3MgTm9kZToKICAgIGRlZiBfX2luaXRfXyhzZWxmLCBuYW1lPU5vbmUsIHBhcmVudD1Ob25lLCBhdmFpbGFibGU9VHJ1ZSk6CiAgICAgICAgc2VsZi5uYW1lID0gbmFtZQogICAgICAgIHNlbGYucGFyZW50ID0gcGFyZW50CiAgICAgICAgc2VsZi5hdmFpbGFibGUgPSBhdmFpbGFibGUKICAgICAgICBzZWxmLmNoaWxkcmVuID0gW10KCiAgICBAcHJvcGVydHkKICAgIGRlZiBuZXh0X3NpYmxpbmcoc2VsZik6CiAgICAgICAgIiIiUmV0dXJuIG5leHQgbm9kZSBvbiB0aGUgc2FtZSBsZXZlbC4iIiIKICAgICAgICB0cnk6CiAgICAgICAgICAgIHJldHVybiBzZWxmLnBhcmVudC5jaGlsZHJlbltzZWxmLnBhcmVudC5jaGlsZHJlbi5pbmRleChzZWxmKSsxXQogICAgICAgIGV4Y2VwdCAoQXR0cmlidXRlRXJyb3IsIEluZGV4RXJyb3IpOgogICAgICAgICAgICByZXR1cm4gTm9uZQoKICAgIEBwcm9wZXJ0eQogICAgZGVmIG5leHRfbm9kZShzZWxmKToKICAgICAgICAiIiJSZXR1cm4gbmV4dCBhdmFpbGFibGUgbm9kZSB1c2luZyBkZXB0aC1maXJzdCBzZWFyY2guIiIiCiAgICAgICAgZGVmIGYobm9kZSk6CiAgICAgICAgICAgIHJldHVybiBub2RlIGlmIG5vZGUuYXZhaWxhYmxlIGVsc2Ugbm9kZS5uZXh0X25vZGUKCiAgICAgICAgaWYgc2VsZi5hdmFpbGFibGUgYW5kIHNlbGYuY2hpbGRyZW46CiAgICAgICAgICAgIHJldHVybiBmKHNlbGYuY2hpbGRyZW5bMF0pCiAgICAgICAgCiAgICAgICAgZWxpZiBzZWxmLm5leHRfc2libGluZzoKICAgICAgICAgICAgcmV0dXJuIGYoc2VsZi5uZXh0X3NpYmxpbmcpCgogICAgICAgIG5vZGUgPSBzZWxmCiAgICAgICAgd2hpbGUgbm9kZS5wYXJlbnQgaXMgbm90IE5vbmU6CiAgICAgICAgICAgIG5vZGUgPSBub2RlLnBhcmVudAogICAgICAgICAgICBpZiBub2RlLm5leHRfc2libGluZzoKICAgICAgICAgICAgICAgIHJldHVybiBmKG5vZGUubmV4dF9zaWJsaW5nKQoKICAgICAgICByZXR1cm4gTm9uZQoKCmRlZiBwcmludF90cmVlKG5vZGUsIG9ubHlfYXZhaWxhYmxlPUZhbHNlKToKICAgIHRvZG8gPSBbbm9kZV0KICAgIHdoaWxlIHRvZG86CiAgICAgICAgbm9kZSA9IHRvZG8ucG9wKCkgICAgICAKICAgICAgICBpZiBvbmx5X2F2YWlsYWJsZSBhbmQgbm90IG5vZGUuYXZhaWxhYmxlOgogICAgICAgICAgICBjb250aW51ZQogICAgICAgIHRvZG8uZXh0ZW5kKHJldmVyc2VkKG5vZGUuY2hpbGRyZW4pKQogICAgICAgIHByaW50KG5vZGUubmFtZSArICgnICh1bmF2YWlsYWJsZSknIGlmIG5vdCBub2RlLmF2YWlsYWJsZSBlbHNlICcnKSkKCgpkZWYgdHJhdmVyc2Uobm9kZSk6CiAgICB3aGlsZSBUcnVlOgogICAgICAgIHByaW50KG5vZGUubmFtZSkKICAgICAgICBub2RlID0gbm9kZS5uZXh0X25vZGUKICAgICAgICBpZiBub3Qgbm9kZToKICAgICAgICAgICAgYnJlYWsKCgpncmFuZHBhcmVudCA9IE5vZGUobmFtZT0nZ3JhbmRwYXJlbnQnKQpwYXJlbnQwID0gTm9kZShuYW1lPScgICAgcGFyZW50MCcsIHBhcmVudD1ncmFuZHBhcmVudCkKcGFyZW50MSA9IE5vZGUobmFtZT0nICAgIHBhcmVudDEnLCBwYXJlbnQ9Z3JhbmRwYXJlbnQpCnBhcmVudDIgPSBOb2RlKG5hbWU9JyAgICBwYXJlbnQyJywgcGFyZW50PWdyYW5kcGFyZW50LCBhdmFpbGFibGU9RmFsc2UpCnBhcmVudDMgPSBOb2RlKG5hbWU9JyAgICBwYXJlbnQzJywgcGFyZW50PWdyYW5kcGFyZW50KQpjaGlsZDAgPSBOb2RlKG5hbWU9JyAgICAgICAgY2hpbGQwJywgcGFyZW50PXBhcmVudDAsIGF2YWlsYWJsZT1GYWxzZSkKY2hpbGQxID0gTm9kZShuYW1lPScgICAgICAgIGNoaWxkMScsIHBhcmVudD1wYXJlbnQwLCBhdmFpbGFibGU9RmFsc2UpCmNoaWxkMiA9IE5vZGUobmFtZT0nICAgICAgICBjaGlsZDInLCBwYXJlbnQ9cGFyZW50MSwgYXZhaWxhYmxlPUZhbHNlKQpjaGlsZDMgPSBOb2RlKG5hbWU9JyAgICAgICAgY2hpbGQzJywgcGFyZW50PXBhcmVudDEpCmNoaWxkNCA9IE5vZGUobmFtZT0nICAgICAgICBjaGlsZDQnLCBwYXJlbnQ9cGFyZW50MikKY2hpbGQ1ID0gTm9kZShuYW1lPScgICAgICAgIGNoaWxkNScsIHBhcmVudD1wYXJlbnQzKQpjaGlsZDYgPSBOb2RlKG5hbWU9JyAgICAgICAgY2hpbGQ2JywgcGFyZW50PXBhcmVudDMsIGF2YWlsYWJsZT1GYWxzZSkKZ3JhbmRjaGlsZDAgPSBOb2RlKG5hbWU9JyAgICAgICAgICAgIGdyYW5kY2hpbGQwJywgcGFyZW50PWNoaWxkMCkKZ3JhbmRjaGlsZDEgPSBOb2RlKG5hbWU9JyAgICAgICAgICAgIGdyYW5kY2hpbGQxJywgcGFyZW50PWNoaWxkMCkKZ3JhbmRjaGlsZDIgPSBOb2RlKG5hbWU9JyAgICAgICAgICAgIGdyYW5kY2hpbGQyJywgcGFyZW50PWNoaWxkMykKZ3JhbmRwYXJlbnQuY2hpbGRyZW4gPSBbcGFyZW50MCwgcGFyZW50MSwgcGFyZW50MiwgcGFyZW50M10KcGFyZW50MC5jaGlsZHJlbiA9IFtjaGlsZDAsIGNoaWxkMV0KcGFyZW50MS5jaGlsZHJlbiA9IFtjaGlsZDIsIGNoaWxkM10KcGFyZW50Mi5jaGlsZHJlbiA9IFtjaGlsZDRdCnBhcmVudDMuY2hpbGRyZW4gPSBbY2hpbGQ1LCBjaGlsZDZdCmNoaWxkMC5jaGlsZHJlbiA9IFtncmFuZGNoaWxkMCwgZ3JhbmRjaGlsZDFdCmNoaWxkMy5jaGlsZHJlbiA9IFtncmFuZGNoaWxkMl0KcHJpbnQoJ0Z1bGwgbm9kZSB0cmVlOlxuJykKcHJpbnRfdHJlZShncmFuZHBhcmVudCwgb25seV9hdmFpbGFibGU9RmFsc2UpCnByaW50KCdcblxuR29hbCBzZXF1ZW5jZTpcbicpCnByaW50X3RyZWUoZ3JhbmRwYXJlbnQsIG9ubHlfYXZhaWxhYmxlPVRydWUpCnByaW50KCdcblxuVHJhdmVyc2UgdXNpbmcgTm9kZS5uZXh0X25vZGUoKSBtZXRob2QgKG11c3QgYmUgZXF1YWwgdG8gIkdvYWwgc2VxdWVuY2UiKTpcbicpCnRyYXZlcnNlKGdyYW5kcGFyZW50KQ==