# Problem Description
This is a binary tree classification problem where we need to determine if a given binary tree belongs to Type 1 or Type 2. The main task is to determine if a binary tree follows a special pattern where the left subtree is exactly identical (same structure and values) to the right subtree. Type 1 represents trees with identical subtrees, while Type 2 represents trees without this property.

# Visual Facts
1. The image shows two categories of trees (Type 1 and Type 2), each with 4 examples
2. Type 1 trees have:
   - Green dashed vertical lines through the root node
   - Binary tree structure with maximum 2 children per node
   
3. Type 2 trees have:
   - Red dashed lines with X marks
   - At least one difference between left and right subtrees

4. Each tree is properly structured as a binary tree with:
   - A single root node
   - Maximum two children per node

# Visual Patterns
1. Type 1 Pattern Requirements:
   - The left subtree must be exactly identical to the right subtree in both:
     * Structure (same arrangement of nodes)
     * Values (corresponding nodes must have same values)
   - This pattern must hold at the root level
   - Example: Tree with root 3 has identical 4's as children

2. Type 2 Pattern Characteristics:
   - A tree becomes Type 2 if there's any violation of the Type 1 pattern:
     * Different values in corresponding positions
     * Different structure between left and right subtrees
     * Even a single node mismatch makes it Type 2
   
3. Additional Pattern Rules:
   - The root value itself doesn't determine the type
   - The comparison is about exact equality, not mirror symmetry
   - Null children (missing nodes) must also match on both sides


# Solution
from typing import List
class TreeNode:
    """
    This class represents a node in a tree. Each node contains a value and a list of children.
    """

    def __init__(self, value: int, children=[None, None]):
        self.value = value
        self.children = children

def are_identical(left: TreeNode, right: TreeNode) -> bool:
    """
    Determine if two subtrees are identical.

    Parameters:
        left (TreeNode): The root node of the left subtree.
        right (TreeNode): The root node of the right subtree.

    Returns:
        bool: True if the subtrees are identical, False otherwise.    
    """
    if left is None and right is None:
        return True
    if left is None or right is None:
        return False
    if left.value != right.value:
        return False
    return are_identical(left.children[0], right.children[0]) and are_identical(left.children[1], right.children[1])

def solution(root: TreeNode) -> int:
    """
    Determine which type the binary tree belongs to.

    Parameters:
        root (TreeNode): The root node of a binary tree.

    Returns:
        int: Type 1 if the tree has identical left and right subtrees, Type 2 otherwise.
    """
    if root is None:
        return 2
    left = root.children[0]
    right = root.children[1]
    if are_identical(left, right):
        return 1
    else:
        return 2


# Test Script
def print_tree(node: TreeNode, level=0, prefix="Root: "):
    """Helper function to create a string representation of the tree"""
    if node is None:
        return prefix + "None\n"
    
    result = prefix + str(node.value) + "\n"
    for i, child in enumerate(node.children):
        if child:
            result += print_tree(child, level + 1, "  " * (level + 1) + f"Child {i}: ")
        else:
            result += "  " * (level + 1) + f"Child {i}: None\n"
    return result

def test():
    Tree1 = TreeNode(1, [
        TreeNode(1),
        TreeNode(2)
    ]) # 2
    Tree2 = TreeNode(1, [
        TreeNode(2),
        TreeNode(2)
    ]) # 1
    Tree3 = TreeNode(3, [
        TreeNode(3), 
        None
    ]) # 2
    Tree4 = TreeNode(2, [
        TreeNode(2), 
        TreeNode(2, [
            TreeNode(2),
            None
        ])
    ]) # 2
    Tree5 = TreeNode(2, [
        TreeNode(2, [
            TreeNode(2),
            None
        ]), 
        TreeNode(2, [
            TreeNode(2),
            None
        ])
    ]) # 1
    Tree6 = TreeNode(2, [
        TreeNode(2, [
            TreeNode(2),
            None
            
        ]), 
        TreeNode(2, [
            None,
            TreeNode(2)
        ])
    ]) # 2
    Tree7 = TreeNode(2, [
        TreeNode(1, [TreeNode(2), None]), 
        TreeNode(2, [TreeNode(3), None])
    ]) # 2
    Tree8 = TreeNode(2, [
        TreeNode(1, [
            TreeNode(3, [TreeNode(2), TreeNode(3)]),
            TreeNode(2, [TreeNode(3), TreeNode(2)])
        ]), 
        TreeNode(1, [
            TreeNode(3, [TreeNode(2), TreeNode(3)]),
            TreeNode(2, [TreeNode(3), TreeNode(2)])
        ])
    ]) # 1

    test_cases = [
        (Tree1, 2),
        (Tree2, 1),
        (Tree3, 2),
        (Tree4, 2),
        (Tree5, 1),
        (Tree6, 2),
        (Tree7, 2),
        (Tree8, 1)
    ]

    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 the test case:\n"
                f"`root`: Tree structure:\n{print_tree(root)}\n"
                f"Exception: '{str(e)}'"
            )
            assert False, error_message

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

test()