# Problem Description
The problem requires implementing a function that processes a binary tree and returns a sequence of node values based on specific rules. The function takes a root node of a tree as input and should return a list of integers representing the "leaf" nodes in the tree. The leaf nodes are those that do not have any children.

# Visual Facts
1. Each example shows a binary tree with numbered nodes (1 to 8 maximum).
2. Some nodes are highlighted in orange, while others are in black.
3. Each example has an associated output sequence shown below it.
4. Orange arrows point upwards from the output sequence to the corresponding nodes in the tree.
5. The trees have different shapes and depths:
   - Example 1: depth 4, 8 nodes.
   - Example 2: depth 3, 7 nodes.
   - Example 3: depth 3, 5 nodes.
6. The output sequence consists of the values of the nodes highlighted in orange.
7. The highlighted nodes are the leaf nodes of the tree.

# Visual Patterns
Output Sequence Pattern:
- The output sequence consists of only the leaf nodes (nodes without children).
- The sequence follows the left-to-right order of the leaf nodes as they appear in the tree.
- The root node is never included in the output if it has children.
- The output sequence includes all the leaf nodes at each level, ordered from left to right.

# Solution
class TreeNode:
    """
    Represents a node in a tree. Each node contains an integer value and a list of child TreeNodes.
    
    Attributes:
        value (int): The integer value of the node.
        children (list): A list of child nodes (TreeNode objects).
    """
    def __init__(self, value: int, children: list=[]):
        self.value = value
        self.children = children

def solution(root: TreeNode) -> list[int]:
    """
    Computes the output sequence based on the given tree structure.

    Parameters:
        root (TreeNode): The root node of the tree.

    Returns:
        list[int]: A list of integers representing the output sequence as illustrated in the figure.
    """

    def dfs(node: TreeNode) -> list[int]:
        # Base case: if the node has no children, it's a leaf node
        if not node.children:
            return [node.value]

        # Recursively visit all children and collect their leaf nodes
        leaves = []
        for child in node.children:
            leaves.extend(dfs(child))  # Collect leaf nodes from all children
        return leaves

    if not root:
        return []

    return dfs(root)


# Test Script
def tree_to_string(node, level=0):
    """Helper function to convert a tree to a readable string format"""
    if not node:
        return "None"
    
    result = f"TreeNode({node.value})"
    if node.children:
        result += " → ["
        children_str = ", ".join(tree_to_string(child, level + 1) for child in node.children)
        result += children_str + "]"
    return result

def test():
    Tree0 = TreeNode(0)
    Tree1 = TreeNode(1, [TreeNode(1), TreeNode(2)])
    Tree2 = TreeNode(3, [TreeNode(3)])
    Tree3 = TreeNode(2, [TreeNode(2), TreeNode(2, [TreeNode(2)])])
    Tree4 = TreeNode(2, [TreeNode(1, [TreeNode(2)]), TreeNode(2, [TreeNode(3)])])
    Tree5 = TreeNode(5, [TreeNode(5, [TreeNode(5, [TreeNode(5)]), TreeNode(5)]), TreeNode(5, [TreeNode(5), TreeNode(5)])])
    Tree6 = TreeNode(8, [TreeNode(8, [TreeNode(8, [TreeNode(8)]), TreeNode(8)]), TreeNode(8, [TreeNode(8, [TreeNode(8)]), TreeNode(8)])])
    Tree7 = TreeNode(2, [TreeNode(2, [TreeNode(2, [TreeNode(1)]), TreeNode(2)]), TreeNode(2, [TreeNode(2), TreeNode(1, [TreeNode(2)])])])
    Tree8 = TreeNode(3, [TreeNode(3, [TreeNode(3, [TreeNode(3)]), TreeNode(3)]), TreeNode(3, [TreeNode(3), TreeNode(3, [TreeNode(3)])])])
    Tree9 = TreeNode(3, [TreeNode(3, [TreeNode(3, [TreeNode(3)]), TreeNode(8, [TreeNode(3)])]), TreeNode(3, [TreeNode(6), TreeNode(8, [TreeNode(3)])])])
    Tree10 = TreeNode(3, [TreeNode(3, [TreeNode(3, [TreeNode(3)]), TreeNode(1, [TreeNode(1)])]), TreeNode(3, [TreeNode(3, [TreeNode(1)]), TreeNode(3, [TreeNode(3)])])])

    test_cases = [
        (Tree0, [0]),
        (Tree1, [1, 2]),
        (Tree2, [3]),
        (Tree3, [2, 2]),
        (Tree4, [2, 3]),
        (Tree5, [5, 5, 5, 5]),
        (Tree6, [8, 8, 8, 8]),
        (Tree7, [1, 2, 2, 2]),
        (Tree8, [3, 3, 3, 3]),
        (Tree9, [3, 3, 6, 3]),
        (Tree10, [3, 1, 1, 3]),
    ]
    for i, (root, expected_output) in enumerate(test_cases):
        try:
            output = solution(root)
        except Exception as e:
            error_message = (
                f"An exception occurred while running test case {i}:\n"
                f"`root`: {tree_to_string(root)}\n\n"
                f"Exception: '{str(e)}'"
            )
            assert False, error_message

        if output != expected_output:
            error_message = (
                f"The following Test Case {i} failed:\n"
                f"`root`: {tree_to_string(root)}\n\n"
                f"Actual Output: {output}\n"
                f"Expected Output: {expected_output}"
            )
            assert False, error_message

test()