# Problem Description
This is a binary tree transformation problem where we need to modify certain node values in the tree according to specific rules. The function takes a binary tree's root node as input and should return the transformed tree's root node. The transformation needs to be done in-place by manipulating the existing nodes rather than creating a new tree.

# Visual Facts
1. The image shows three different examples of binary tree transformations (before and after).
2. The nodes that change are highlighted in orange in the result trees.
3. Values in the nodes can be:
   - Positive integers (e.g., 3, 4)
   - Negative integers (e.g., -2, -4)
   - Special value "null"
4. The tree structure (topology) remains unchanged after transformation.
5. The root node value remains unchanged in all examples (3).

# Visual Patterns
1. Value Transformation Pattern:
   - Iterate over all nodes, for each node X
   - read the value of X's left child (L)
   - assign value(L) to X's right child (R)
   - move on to the next node

# Solution
class Node:
    def __init__(self, val = 0, left = None, right = None):
        self.left = left
        self.right = right
        self.val = val

def solution(root: Node) -> Node:
    """
    Transforms a binary tree according to the illustrated rule by manipulating its nodes.

    Parameters:
        root (Node): The root node of the input binary tree.

    Returns:
        Node: The root node of the transformed binary tree.
    """
    if root is None:
        return None
    queue = [root]
    while queue:
        current = queue.pop(0)
        if current.left:
            if current.right:
                current.right.val = current.left.val
            else:
                current.right = Node(current.left.val)
        if current.left:
            queue.append(current.left)
        if current.right:
            queue.append(current.right)
    return root


# Test Script
class Node:
    def __init__(self, val = 0, left = None, right = None):
        self.left = left
        self.right = right
        self.val = val

def tree_to_list(root):
    def maxDepth(root):
        if not root:
            return 0
        return 1 + max(maxDepth(root.left), maxDepth(root.right))
    li_res = [None for _ in range( 2 ** maxDepth(root) - 1)]
    if not root:
        return []
    def dfs(node, idx):
        if not node:
            return
        li_res[idx] = node.val
        dfs(node.left, 2*idx+1)
        dfs(node.right, 2*idx+2)
    dfs(root, 0)
    return li_res
    

def list_to_tree(lst):
    """
    Converts a list into a binary tree structure and returns the root node.
    Args:
        lst (list): List of elements to form the binary tree.
                   Use `None` for empty nodes.
    Returns:
        Node: The root of the binary tree.
    """
    if not lst:  # If the list is empty, return None
        return None

    # Create a list of nodes, where None in the list corresponds to None in the tree
    nodes = [Node(val = value) for value in lst]
    
    # Link the nodes to form the tree
    for i in range(len(lst)):
        if nodes[i] is not None:  # Skip None nodes
            left_index = 2 * i + 1  # Left child index
            right_index = 2 * i + 2  # Right child index
            if left_index < len(lst):  # Check if left child exists
                nodes[i].left = nodes[left_index]
            if right_index < len(lst):  # Check if right child exists
                nodes[i].right = nodes[right_index]

    # Return the root node
    return nodes[0]

def is_same_tree(tree1, tree2):
    """
    Checks if two binary trees are identical in structure and values.
    
    Args:
        tree1 (Node): Root of the first binary tree.
        tree2 (Node): Root of the second binary tree.
    
    Returns:
        bool: True if the trees are identical, False otherwise.
    """
    # Both trees are empty
    return tree_to_list(tree1) == tree_to_list(tree2)

def test():
    test_cases = [
        ([3,None, 4], [3, None, None]),
        ([3, -5, 4, None, -4, -7, -2],  [3, -5, -5, None, None, -7, -7]),
        ([3, -2, 4, 1, -4, None, -2, None, None , 0, None, None, None, 9, None], [3, -2, -2, 1, 1, None, None, None, None, 0, 0, None, None, 9, 9]),
        ([1, None, 2, None, None, 4, 5], [1, None, None, None, None, 4, 4]),
        ([1, 2, 3, None, None, 4, None, None, None, None, None, 5, None],[1, 2, 2, None, None, 4, 4, None, None, None, None, 5, 5, None, None]),
        ([1, 2, 5, None, None, 3, 4, None, None, None, None, None, 5],[1, 2, 2, None, None, 3, 3, None, None, None, None, None, None, None, None]),
    ]

    for input_list, expected_list in test_cases:
        try:
            root = list_to_tree(input_list)
            expected = list_to_tree(expected_list)
            output = solution(root)
        except Exception as e:
            error_message = (
                f"An exception occurred while running the test case:\n"
                f"`root`: Binary Tree {input_list}\n"
                f"Exception: '{str(e)}'"
            )
            assert False, error_message

        if not is_same_tree(output, expected):
            error_message = (
                f"The following Test Case failed:\n"
                f"`root`: Binary Tree {input_list}\n\n"
                f"Actual Output Tree: {tree_to_list(output)}\n"
                f"Expected Output Tree: {tree_to_list(expected)}"
            )
            assert False, error_message

test()