# Problem Description
This is a geometric problem involving a grid, a polyline (chain), and a rectangular region. The task is to count the number of intersections (red regions) where the polyline crosses the boundary of a specified rectangular yellow region. The polyline consists of connected line segments that move horizontally or vertically through the grid points.

# Visual Facts
1. Grid Properties:
   - 4×4 grid (n=4)
   - Grid points are labeled with coordinates (x,y)
   - Origin (0,0) is at top-left

2. Yellow Region:
   - Rectangular area marked with dashed yellow border
   - Top-left coordinate: (1,0)
   - Bottom-right coordinate: (2,2)

3. Blue Chain:
   - Consists of connected blue line segments
   - Moves only horizontally or vertically
   - Chain points: (0,0)→(0,1)→(1,1)→(1,0)→(2,0)→(3,0)→(3,1)→(2,1)→(2,2)→(2,3)→(1,3)

4. Red Intersections:
   - four red circular markers where the blue chain crosses yellow border
   - Located at: 
     * Between (0,1) and (1,1). (0,1) is outside the yellow region, (1,1) is inside
     * Between (2,0) and (3,0). (2,0) is inside the yellow region, (3,0) is outside
     * Between (3,1) and (2,1). (3,1) is outside the yellow region, (2,1) is inside
     * Between (2,2) and (2,3). (2,2) is inside the yellow region, (2,3) is outside

# Visual Patterns
- Red regions appear only where the blue chain crosses the yellow rectangle's boundary
- Each crossing of the chain with the yellow border counts as one intersection
- Intersections occur when a line segment has one endpoint inside and one outside the yellow region


# Solution
from typing import List, Tuple

def solution(n: int, chain: List[Tuple[int, int]], top_left: Tuple[int, int], bottom_right: Tuple[int, int]) -> int:
    """
    Given a chain and a yellow region in an n x n 2D matrix, find the number of red regions that are formed.

    Parameters:
        n (int): The size of the matrix.
        chain (List[Tuple[int, int]]): Coordinates of each node in the chain in order.
        top_left (Tuple[int, int]): Coordinates of the top-left corner of the yellow region.
        bottom_right (Tuple[int, int]): Coordinates of the bottom-right corner of the yellow region.

    Returns:
        int: The number of red regions.
    """
    def is_inside(x: int, y: int) -> bool:
        """ Check if a point is inside the yellow region """
        return top_left[0] <= x <= bottom_right[0] and top_left[1] <= y <= bottom_right[1]

    crossings = 0

    for i in range(len(chain) - 1):
        x1, y1 = chain[i]
        x2, y2 = chain[i + 1]

        # Check if one point is inside and the other is outside the yellow region
        if is_inside(x1, y1) != is_inside(x2, y2):
            crossings += 1

    return crossings


# Test Script
def test():
    test_cases = [
        (2, [(0, 0), (0, 1), (1, 1), (1, 0)], (1, 0), (1, 1), 1),
        (2, [(0, 0), (0, 1), (1, 1), (1, 0)], (1, 1), (1, 1), 2),
        (2, [(0, 0), (0, 1), (1, 1), (1, 0)], (1, 1), (1, 1), 2),
        (2, [(0, 0), (0, 1), (1, 0)], (1, 1), (1, 1), 0),
        (3, [(0, 0), (0, 1), (1, 1), (1, 0), (2, 0), (2, 2), (1, 2), (1, 1)], (1, 0), (2, 1), 3),
        (3, [(0, 0), (0, 1), (1, 1), (1, 0), (2, 0), (2, 2), (1, 2), (1, 1)], (1, 0), (2, 2), 1),
        (4, [(0, 0), (0, 1), (1, 1), (1, 0), (2, 0), (3, 0), (3, 1), (2, 1), (2, 2), (2, 3), (1, 3)], (1, 0), (2, 2), 4),
        (4, [(0, 0), (0, 1), (1, 1), (1, 0), (2, 0), (3, 0), (3, 1), (2, 1), (2, 2), (2, 3), (1, 3), (1, 2)], (1, 0), (2, 2), 5),
        (4, [(0, 0), (0, 1), (1, 1), (1, 0), (2, 0), (3, 0), (3, 1), (2, 1), (2, 2), (2, 3), (1, 3), (1, 2), (0, 2)], (1, 0), (2, 2), 6),
        (4, [(0, 0), (0, 1), (1, 1), (1, 0), (2, 0), (3, 0), (3, 1), (2, 1), (2, 2), (2, 3), (1, 3), (1, 2), (0, 2)], (0, 0), (2, 2), 4),
        (4, [(0, 0), (0, 1), (1, 1), (1, 0), (2, 0), (3, 0), (3, 1), (2, 1), (2, 2), (2, 3), (1, 3), (1, 2), (0, 2)], (0, 0), (3, 3), 0),
    ]

    for i, (n, chain, top_left, bottom_right, expected_output) in enumerate(test_cases):
        try:
            output = solution(n, chain, top_left, bottom_right)
        except Exception as e:
            error_message = (
                f"An exception occurred while running the test case:\n"
                f"`n`: {n}\n"
                f"`chain`: {chain}\n"
                f"`top_left`: {top_left}\n"
                f"`bottom_right`: {bottom_right}\n\n"
                f"Exception: '{str(e)}'"
            )
            assert False, error_message

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

test()