2023-10-20 12:11:07 +00:00
|
|
|
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
|
|
|
|
|
|
|
|
|
2023-10-20 12:22:16 +00:00
|
|
|
COMPASS = (
|
|
|
|
(1, 0), # east
|
|
|
|
(0, 1), # south
|
|
|
|
(-1, 0), # west
|
|
|
|
(0, -1), # north
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2023-10-20 12:11:07 +00:00
|
|
|
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)
|
2023-10-20 12:22:16 +00:00
|
|
|
self.spinner: itertools.cycle[tuple[int, int]] = itertools.cycle(COMPASS)
|
2023-10-20 12:11:07 +00:00
|
|
|
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)
|
2023-10-20 12:22:16 +00:00
|
|
|
if self.missteps > len(COMPASS) - 1:
|
2023-10-20 12:11:07 +00:00
|
|
|
return False
|
|
|
|
|
|
|
|
self.missteps += 1
|
|
|
|
return self.step()
|
|
|
|
|
|
|
|
self.missteps: int = 0
|
|
|
|
self.path.append(next_loc)
|
|
|
|
return True
|