# Problem Description
The problem requires implementing a matrix traversal function that follows a specific spiral pattern. Given a matrix of M x N dimensions, we need to return the elements in a specific order that follows a spiral path starting from the bottom-left corner, moving initially rightward, and then following a counter-clockwise spiral pattern towards the inside of the matrix.

# Visual Facts
1. The image shows 4 different matrix examples:
   - 4x1 matrix (top-right)
   - 4x2 matrix (top-left)
   - 4x3 matrix (bottom-left)
   - 4x4 matrix (bottom-right)
2. Each matrix is numbered sequentially from 1 to its size (4, 8, 12, or 16)
3. Arrows indicate the direction of traversal
4. All examples start from the bottom-left corner

# Visual Patterns
1. Movement Direction Pattern:
   - Follows a consistent sequence: Right → Up → Left → Down → Right → ...
   - Arrows show the traversal direction changes at boundaries or visited cells

2. Traversal Rules:
   - First move: Always move right along the bottom row
   - Each cell is visited exactly once
   - When can't move in current direction, rotate counter-clockwise
   - Forms a spiral pattern inward
   - Continue until all cells are visited


# Solution
from typing import List


def solution(matrix: List[List[int]]) -> List[int]:
    """
    Given an M x N 2D matrix, traverse the matrix according to the spiral pattern shown in the figure

    Parameters:
    matrix (List[List[int]]): A 2D list of integers representing the matrix.

    Returns:
    List[int]: A list of integers representing the elements of the matrix in the order as shown in the picture.
    """
    result = []
    top, bottom = 0, len(matrix) - 1
    left, right = 0, len(matrix[0]) - 1

    while top <= bottom and left <= right:
        # Traverse from left to right
        for i in range(left, right + 1):
            result.append(matrix[bottom][i])
        bottom -= 1

        # Traverse from bottom to top
        for i in range(bottom, top - 1, -1):
            result.append(matrix[i][right])
        right -= 1

        if top <= bottom:
            # Traverse from right to left
            for i in range(right, left - 1, -1):
                result.append(matrix[top][i])
            top += 1

        if left <= right:
            # Traverse from top to bottom
            for i in range(top, bottom + 1):
                result.append(matrix[i][left])
            left += 1

    return result


# Test Script
def test():
    test_cases = [
        ([[1, 2]], [1, 2]),
        ([[1, 2], [3, 4]], [3, 4, 2, 1]),
        ([[1, 2, 3], 
          [4, 5, 6], 
          [7, 8 , 9]], [7, 8, 9, 6, 3, 2, 1, 4, 5]),
        ([[1,2,3,4],
          [5,6,7,8],
          [9,10,11,12]], [9, 10, 11, 12, 8, 4, 3, 2, 1, 5, 6, 7]),
        ([[1, 3, 5, 6, 2], 
          [43, 23, 19, 22, 33], 
          [12, 11, 6, 8, 4]], [12, 11, 6, 8, 4, 33, 2, 6, 5, 3, 1, 43, 23, 19, 22]),
        ([[1, 2], 
          [3, 4], 
          [5, 6], 
          [7, 8]], [7, 8, 6, 4, 2, 1, 3, 5]),
        ([[1, 2, 3, 4, 5, 6, 7], 
          [8, 9, 10, 11, 12, 13, 14]], [8, 9, 10, 11, 12, 13, 14, 7, 6, 5, 4, 3, 2, 1]),
        ([[1, 2, 3, 4, 5, 6, 7, 8], 
          [13, 24, 32, 41, 54, 65, 76, 87], 
          [43, 2, 87, 5, 4, 66, 13, 94], 
          [0, 12, 87, 43, 56, 36, 92, 44], 
          [32, 33, 34, 55, 56, 72, 73, 77]], [32, 33, 34, 55, 56, 72, 73, 77, 44, 94, 87, 8, 7, 6, 5, 4, 3, 2, 1, 13, 43, 0, 12, 87, 43, 56, 36, 92, 13, 76, 65, 54, 41, 32, 24, 2, 87, 5, 4, 66]),
        ([[1, 3, 5], 
          [7, 9, 11], 
          [2, 4, 6], 
          [8, 10, 14]], [8, 10, 14, 6, 11, 5, 3, 1, 7, 2, 4, 9]),
        ([[1, 2, 3, 4, 5, 6], 
          [7, 8, 9, 10, 11, 17],
          [13, 15, 16, 19, 20, 91]], [13, 15, 16, 19, 20, 91, 17, 6, 5, 4, 3, 2, 1, 7, 8, 9, 10, 11]),
    ]

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

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

test()