# Problem Description
The task involves validating a 2D matrix (`matrix`) against a set of rules (`rules`). The rules matrix contains two types of constraints:
- 'G': Denotes that the element in the matrix must be greater than its adjacent element.
- 'L': Denotes that the element in the matrix must be less than its adjacent element.
The goal is to check whether the matrix adheres to these constraints as specified by the rules matrix.

# Visual Facts
From the image, we can observe the following explicit facts:
1. **Example 1**:
    - `rules = [[G], [L, L], [G]]`
    - `matrix = [[2, 1], [3, 2]]`
    - The combined result satisfies the rules:
        - 2 > 1 (G)
        - 2 < 3 (L)
        - 1 < 2 (L)
        - 3 > 2 (G)
    - The result is valid.

2. **Example 2**:
    - `rules = [[G, L], [L, L, G], [G, L]]`
    - `matrix = [[3, 2, 5], [4, 3, 4]]`
    - The combined result satisfies the rules:
        - 3 > 2 (G)
        - 2 < 5 (L)
        - 3 < 4 (L)
        - 2 < 3 (L)
        - 5 > 4 (G)
        - 4 > 3 (G)
        - 3 < 4 (L)
    - The result is valid.

3. **Example 3**:
    - `rules = [[G, G], [G, L, G], [L, L]]`
    - `matrix = [[3, 2, 5], [4, 3, 4]]`
    - The combined result does not satisfy the rules:
        - 3 > 2 (G)
        - 2 > 5 (G) violate rule G
        - 3 > 4 (G) violate rule G
        - 2 < 3 (L)
        - 5 > 4 (G)
        - 4 < 3 (L) violate rule L
        - 3 < 4 (L)
    - The result is invalid.

# Visual Patterns
1. Greater Rules (G):
    If a cell in the rules is labeled "G," the cell to the left must be greater than the cell to the right (if the adjacent cells are in a horizontal relationship), and the cell above must be greater than the cell below (if the adjacent cells are in a vertical relationship).
2. Less Rules (L):
    If a cell in the rules is labeled "L," the cell to the left must be less than the cell to the right (if the adjacent cells are in a horizontal relationship), and the cell above must be less than the cell below (if the adjacent cells are in a vertical relationship).
3. Correspondence between rules and matrix:
    Horizontal Relationship: 
        - Rule: rules[2 * i][j]
        - Constraint: Applies to matrix[i][j] and matrix[i][j + 1], compare whether matrix[i][j] is greater than matrix[i][j + 1] (G rule) or less than matrix[i][j + 1] (L rule).
    Vertical Relationship:
        - Rule: rules[2 * i + 1][j]
        - Constraint: Applies to matrix[i][j] and matrix[i + 1][j], compare whether matrix[i][j] is greater than matrix[i + 1][j] (G rule) or less than matrix[i + 1][j] (L rule)..
4. The rules and matrix matrices must have consistent dimensions for the validation process.
    Validation Process:
    - For each pair of neighboring cells in matrix, check the corresponding entry in rules to validate whether the values satisfy the G or L condition.
    - Iterate over the entire rules matrix and check all pairs of constrained cells.
5. Invalid Scenarios:
    - The result is invalid if any single constraint in rules is violated in the matrix.

# Solution
from typing import List

def solution(rules: List[List[str]], matrix: List[List[int]]) -> bool:
    """
    Validates whether a given matrix satisfies the specified rules.

    Args:
        rules: A 2D list of strings containing 'G' or 'L', representing greater/less constraints
        matrix: A 2D list of integers to be validated against the rules

    Returns:
        bool: True if the matrix satisfies all rules, False otherwise
    """
    rows = len(matrix)
    cols = len(matrix[0])
    for i in range(rows):
        for j in range(cols):
            if i < rows - 1:
                if rules[2 * i + 1][j] == 'L':
                    if matrix[i][j] >= matrix[i + 1][j]:
                        return False
                elif rules[2 * i + 1][j] == 'G':
                    if matrix[i][j] <= matrix[i + 1][j]:
                        return False
            if j < cols - 1:
                if rules[2 * i][j] == 'L':
                    if matrix[i][j] >= matrix[i][j + 1]:
                        return False
                elif rules[2 * i][j] == 'G':
                    if matrix[i][j] <= matrix[i][j + 1]:
                        return False
    return True


# Test Script
def test():
    # Test case 1
    relations = [
        ['G'],
        ['L', 'L'],
        ['G']
    ]
    filled_matrix = [
        [2, 1],
        [3, 2]
    ]
    try:
        output = solution(relations, filled_matrix)
    except Exception as e:
        error_message = (
            f"An exception occurred while running the test case:\n"
            f"`rules`: {relations}\n"  
            f"`matrix`: {filled_matrix}\n\n"
            f"Exception: '{str(e)}'"
        )
        assert False, error_message
        
    if output != True:
        error_message = (
            f"The following Test Case failed:\n"
            f"`rules`: {relations}\n"
            f"`matrix`: {filled_matrix}\n\n" 
            f"Actual Output: {output}\n"
            f"Expected Output: True"
        )
        assert False, error_message

    # Test case 2    
    filled_matrix = [
        [4, 2],
        [5, 3]
    ]
    try:
        output = solution(relations, filled_matrix)
    except Exception as e:
        error_message = (
            f"An exception occurred while running the test case:\n"
            f"`rules`: {relations}\n"
            f"`matrix`: {filled_matrix}\n\n"
            f"Exception: '{str(e)}'"
        )
        assert False, error_message
        
    if output != True:
        error_message = (
            f"The following Test Case failed:\n"
            f"`rules`: {relations}\n"
            f"`matrix`: {filled_matrix}\n\n"
            f"Actual Output: {output}\n"
            f"Expected Output: True"
        )
        assert False, error_message

    # Test case 3
    filled_matrix = [
        [4, 5],
        [5, 3]
    ]
    try:
        output = solution(relations, filled_matrix)
    except Exception as e:
        error_message = (
            f"An exception occurred while running the test case:\n"
            f"`rules`: {relations}\n"
            f"`matrix`: {filled_matrix}\n\n"
            f"Exception: '{str(e)}'"
        )
        assert False, error_message
        
    if output != False:
        error_message = (
            f"The following Test Case failed:\n"
            f"`rules`: {relations}\n"
            f"`matrix`: {filled_matrix}\n\n"
            f"Actual Output: {output}\n"
            f"Expected Output: False"
        )
        assert False, error_message

    # Test case 4        
    relations = [
        ['L'],
        ['L', 'L'],
        ['G']
    ]
    filled_matrix = [
        [3, 4],
        [6, 5]
    ]
    try:
        output = solution(relations, filled_matrix)
    except Exception as e:
        error_message = (
            f"An exception occurred while running the test case:\n"
            f"`rules`: {relations}\n"
            f"`matrix`: {filled_matrix}\n\n"
            f"Exception: '{str(e)}'"
        )
        assert False, error_message
        
    if output != True:
        error_message = (
            f"The following Test Case failed:\n"
            f"`rules`: {relations}\n"
            f"`matrix`: {filled_matrix}\n\n"
            f"Actual Output: {output}\n"
            f"Expected Output: True"
        )
        assert False, error_message

    # Test case 5
    filled_matrix = [
        [4, 8],
        [16, 12]
    ]
    try:
        output = solution(relations, filled_matrix)
    except Exception as e:
        error_message = (
            f"An exception occurred while running the test case:\n"
            f"`rules`: {relations}\n"
            f"`matrix`: {filled_matrix}\n\n"
            f"Exception: '{str(e)}'"
        )
        assert False, error_message
        
    if output != True:
        error_message = (
            f"The following Test Case failed:\n"
            f"`rules`: {relations}\n"
            f"`matrix`: {filled_matrix}\n\n"
            f"Actual Output: {output}\n"
            f"Expected Output: True"
        )
        assert False, error_message

    # Test case 6
    filled_matrix = [
        [4, 8],
        [1, 12]
    ]
    try:
        output = solution(relations, filled_matrix)
    except Exception as e:
        error_message = (
            f"An exception occurred while running the test case:\n"
            f"`rules`: {relations}\n"
            f"`matrix`: {filled_matrix}\n\n"
            f"Exception: '{str(e)}'"
        )
        assert False, error_message
        
    if output != False:
        error_message = (
            f"The following Test Case failed:\n"
            f"`rules`: {relations}\n"
            f"`matrix`: {filled_matrix}\n\n"
            f"Actual Output: {output}\n"
            f"Expected Output: False"
        )
        assert False, error_message

    # Test case 7
    relations = [
        ['G', 'L'],
        ['L', 'L', 'G'],
        ['G', 'L']
    ]
    filled_matrix = [
        [3, 2, 5],
        [4, 3, 4]
    ]
    try:
        output = solution(relations, filled_matrix)
    except Exception as e:
        error_message = (
            f"An exception occurred while running the test case:\n"
            f"`rules`: {relations}\n"
            f"`matrix`: {filled_matrix}\n\n"
            f"Exception: '{str(e)}'"
        )
        assert False, error_message
        
    if output != True:
        error_message = (
            f"The following Test Case failed:\n"
            f"`rules`: {relations}\n"
            f"`matrix`: {filled_matrix}\n\n"
            f"Actual Output: {output}\n"
            f"Expected Output: True"
        )
        assert False, error_message

    # Test case 8    
    filled_matrix = [
        [4, 3, 6],
        [5, 4, 5]
    ]
    try:
        output = solution(relations, filled_matrix)
    except Exception as e:
        error_message = (
            f"An exception occurred while running the test case:\n"
            f"`rules`: {relations}\n"
            f"`matrix`: {filled_matrix}\n\n"
            f"Exception: '{str(e)}'"
        )
        assert False, error_message
        
    if output != True:
        error_message = (
            f"The following Test Case failed:\n"
            f"`rules`: {relations}\n"
            f"`matrix`: {filled_matrix}\n\n"
            f"Actual Output: {output}\n"
            f"Expected Output: True"
        )
        assert False, error_message

    # Test case 9
    filled_matrix = [
        [4, 3, 6],
        [1, 4, 5]
    ]
    try:
        output = solution(relations, filled_matrix)
    except Exception as e:
        error_message = (
            f"An exception occurred while running the test case:\n"
            f"`rules`: {relations}\n"
            f"`matrix`: {filled_matrix}\n\n"
            f"Exception: '{str(e)}'"
        )
        assert False, error_message
        
    if output != False:
        error_message = (
            f"The following Test Case failed:\n"
            f"`rules`: {relations}\n"
            f"`matrix`: {filled_matrix}\n\n"
            f"Actual Output: {output}\n"
            f"Expected Output: False"
        )
        assert False, error_message

    # Test case 10
    relations = [
        ['L', 'L', 'L'],
        ['L', 'L', 'L', 'L'],
        ['G', 'G', 'G'],
        ['L', 'L', 'L', 'L'],
        ['L', 'L', 'L']
    ]
    filled_matrix = [
        [3, 4, 5, 6],
        [10, 9, 8, 7],
        [11, 12, 13, 14],
    ]
    try:
        output = solution(relations, filled_matrix)
    except Exception as e:
        error_message = (
            f"An exception occurred while running the test case:\n"
            f"`rules`: {relations}\n"
            f"`matrix`: {filled_matrix}\n\n"
            f"Exception: '{str(e)}'"
        )
        assert False, error_message
        
    if output != True:
        error_message = (
            f"The following Test Case failed:\n"
            f"`rules`: {relations}\n"
            f"`matrix`: {filled_matrix}\n\n"
            f"Actual Output: {output}\n"
            f"Expected Output: True"
        )
        assert False, error_message

    # Test case 11
    filled_matrix = [
        [1, 2, 3, 4],
        [8, 7, 6, 5],
        [9, 10, 11, 12],
    ]
    try:
        output = solution(relations, filled_matrix)
    except Exception as e:
        error_message = (
            f"An exception occurred while running the test case:\n"
            f"`rules`: {relations}\n"
            f"`matrix`: {filled_matrix}\n\n"
            f"Exception: '{str(e)}'"
        )
        assert False, error_message
        
    if output != True:
        error_message = (
            f"The following Test Case failed:\n"
            f"`rules`: {relations}\n"
            f"`matrix`: {filled_matrix}\n\n"
            f"Actual Output: {output}\n"
            f"Expected Output: True"
        )
        assert False, error_message

    # Test case 12
    filled_matrix = [
        [1, 2, 3, 0],
        [8, 7, 6, 5],
        [9, 1, 11, 12],
    ]
    try:
        output = solution(relations, filled_matrix)
    except Exception as e:
        error_message = (
            f"An exception occurred while running the test case:\n"
            f"`rules`: {relations}\n"
            f"`matrix`: {filled_matrix}\n\n"
            f"Exception: '{str(e)}'"
        )
        assert False, error_message
        
    if output != False:
        error_message = (
            f"The following Test Case failed:\n"
            f"`rules`: {relations}\n"
            f"`matrix`: {filled_matrix}\n\n"
            f"Actual Output: {output}\n"
            f"Expected Output: False"
        )
        assert False, error_message

test()