import itertools
import typing


def matrix_spiral(matrix: list[list[typing.Any]]) -> list[typing.Any]:
    return [matrix[y][x] for x, y in matrix_spiral_path(matrix)]


def matrix_spiral_path(matrix: list[list[int]]) -> list[tuple[int, int]]:
    snek = SpinSnek(matrix)

    while snek.step():
        ...

    return snek.path


COMPASS = (
    (1, 0),  # east
    (0, 1),  # south
    (-1, 0),  # west
    (0, -1),  # north
)


class SpinSnek:
    def __init__(self, board: list[list[int]], loc: tuple[int, int] = (0, 0)):
        self.max_loc: tuple[int, int] = (len(board[0]) - 1, len(board) - 1)
        self.spinner: itertools.cycle[tuple[int, int]] = itertools.cycle(COMPASS)
        self.direction = next(self.spinner)
        self.path: list[tuple[int, int]] = [loc]
        self.missteps: int = 0

    def step(self) -> bool:
        loc = self.path[-1]
        next_loc: tuple[int, int] = (
            loc[0] + self.direction[0],
            loc[1] + self.direction[1],
        )

        if (
            next_loc[0] > self.max_loc[0]
            or next_loc[1] > self.max_loc[1]
            or next_loc[0] < 0
            or next_loc[1] < 0
            or next_loc in self.path
        ):
            self.direction = next(self.spinner)
            if self.missteps > len(COMPASS) - 1:
                return False

            self.missteps += 1
            return self.step()

        self.missteps: int = 0
        self.path.append(next_loc)
        return True
