Compare commits
2 Commits
d03225edce
...
accf0d0c2b
Author | SHA1 | Date | |
---|---|---|---|
accf0d0c2b | |||
b672131cfc |
@ -61,7 +61,7 @@ dependencies = [
|
|||||||
"ruff>=0.0.243",
|
"ruff>=0.0.243",
|
||||||
]
|
]
|
||||||
[tool.hatch.envs.lint.scripts]
|
[tool.hatch.envs.lint.scripts]
|
||||||
typing = "mypy --install-types --non-interactive {args:src/leetcode tests}"
|
typing = "mypy --install-types --non-interactive {args:.}"
|
||||||
style = [
|
style = [
|
||||||
"ruff {args:.}",
|
"ruff {args:.}",
|
||||||
"black --check --diff {args:.}",
|
"black --check --diff {args:.}",
|
||||||
@ -120,6 +120,10 @@ ignore = [
|
|||||||
"S105", "S106", "S107",
|
"S105", "S106", "S107",
|
||||||
# Ignore complexity
|
# Ignore complexity
|
||||||
"C901", "PLR0911", "PLR0912", "PLR0913", "PLR0915",
|
"C901", "PLR0911", "PLR0912", "PLR0913", "PLR0915",
|
||||||
|
# Allow print func
|
||||||
|
"T201",
|
||||||
|
# Allow assert statements
|
||||||
|
"S101",
|
||||||
]
|
]
|
||||||
unfixable = [
|
unfixable = [
|
||||||
# Don't touch unused imports
|
# Don't touch unused imports
|
||||||
|
57
leetcode/spiral_matrix.py
Normal file
57
leetcode/spiral_matrix.py
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
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
|
@ -1,6 +1,3 @@
|
|||||||
import enum
|
|
||||||
import itertools
|
|
||||||
import pprint
|
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
|
|
||||||
@ -75,57 +72,3 @@ def cartesian_path(p0: tuple[int, int], p1: tuple[int, int]) -> list[tuple[int,
|
|||||||
|
|
||||||
def gen_matrix(width: int, height: int) -> list[list[int]]:
|
def gen_matrix(width: int, height: int) -> list[list[int]]:
|
||||||
return [list(range(width)) for _ in range(height)]
|
return [list(range(width)) for _ in range(height)]
|
||||||
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
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(
|
|
||||||
[
|
|
||||||
(1, 0), # east
|
|
||||||
(0, 1), # south
|
|
||||||
(-1, 0), # west
|
|
||||||
(0, -1), # north
|
|
||||||
]
|
|
||||||
)
|
|
||||||
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 > 3:
|
|
||||||
return False
|
|
||||||
|
|
||||||
self.missteps += 1
|
|
||||||
return self.step()
|
|
||||||
|
|
||||||
self.missteps: int = 0
|
|
||||||
self.path.append(next_loc)
|
|
||||||
return True
|
|
||||||
|
46
leetcode/test_spiral_matrix.py
Normal file
46
leetcode/test_spiral_matrix.py
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
import spiral_matrix
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("matrix", "expected"),
|
||||||
|
[
|
||||||
|
(
|
||||||
|
[
|
||||||
|
["a", "b", "c"],
|
||||||
|
["d", "e", "f"],
|
||||||
|
["g", "h", "i"],
|
||||||
|
],
|
||||||
|
["a", "b", "c", "f", "i", "h", "g", "d", "e"],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
[
|
||||||
|
[1, 2, 3, 4],
|
||||||
|
[5, 6, 7, 8],
|
||||||
|
[9, 10, 11, 12],
|
||||||
|
],
|
||||||
|
[1, 2, 3, 4, 8, 12, 11, 10, 9, 5, 6, 7],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
[
|
||||||
|
[1, 2, 3, 4, 5, 6, 7, 8, 9],
|
||||||
|
[1, 2, 3, 4, 5, 6, 7, 8, 9],
|
||||||
|
[1, 2, 3, 4, 5, 6, 7, 8, 9],
|
||||||
|
[1, 2, 3, 4, 5, 6, 7, 8, 9],
|
||||||
|
[1, 2, 3, 4, 5, 6, 7, 8, 9],
|
||||||
|
],
|
||||||
|
[] # noqa
|
||||||
|
+ [1, 2, 3, 4, 5, 6, 7, 8, 9] # right
|
||||||
|
+ [9, 9, 9] # down
|
||||||
|
+ [9, 8, 7, 6, 5, 4, 3, 2, 1] # left
|
||||||
|
+ [1, 1] # up
|
||||||
|
+ [1, 2, 3, 4, 5, 6, 7, 8] # right
|
||||||
|
+ [8] # down
|
||||||
|
+ [8, 7, 6, 5, 4, 3, 2] # left
|
||||||
|
+ [2, 3, 4, 5, 6, 7], # right
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_matrix_spiral(matrix, expected):
|
||||||
|
assert spiral_matrix.matrix_spiral(matrix) == expected
|
@ -16,46 +16,3 @@ import stuff
|
|||||||
)
|
)
|
||||||
def test_find_sqrt_ish(n: int, expected: int):
|
def test_find_sqrt_ish(n: int, expected: int):
|
||||||
assert stuff.find_sqrt_ish(n) == expected
|
assert stuff.find_sqrt_ish(n) == expected
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
|
||||||
("matrix", "expected"),
|
|
||||||
[
|
|
||||||
(
|
|
||||||
[
|
|
||||||
["a", "b", "c"],
|
|
||||||
["d", "e", "f"],
|
|
||||||
["g", "h", "i"],
|
|
||||||
],
|
|
||||||
["a", "b", "c", "f", "i", "h", "g", "d", "e"],
|
|
||||||
),
|
|
||||||
(
|
|
||||||
[
|
|
||||||
[1, 2, 3, 4],
|
|
||||||
[5, 6, 7, 8],
|
|
||||||
[9, 10, 11, 12],
|
|
||||||
],
|
|
||||||
[1, 2, 3, 4, 8, 12, 11, 10, 9, 5, 6, 7],
|
|
||||||
),
|
|
||||||
(
|
|
||||||
[
|
|
||||||
[1, 2, 3, 4, 5, 6, 7, 8, 9],
|
|
||||||
[1, 2, 3, 4, 5, 6, 7, 8, 9],
|
|
||||||
[1, 2, 3, 4, 5, 6, 7, 8, 9],
|
|
||||||
[1, 2, 3, 4, 5, 6, 7, 8, 9],
|
|
||||||
[1, 2, 3, 4, 5, 6, 7, 8, 9],
|
|
||||||
],
|
|
||||||
[]
|
|
||||||
+ [1, 2, 3, 4, 5, 6, 7, 8, 9] # right
|
|
||||||
+ [9, 9, 9] # down
|
|
||||||
+ [9, 8, 7, 6, 5, 4, 3, 2, 1] # left
|
|
||||||
+ [1, 1] # up
|
|
||||||
+ [1, 2, 3, 4, 5, 6, 7, 8] # right
|
|
||||||
+ [8] # down
|
|
||||||
+ [8, 7, 6, 5, 4, 3, 2] # left
|
|
||||||
+ [2, 3, 4, 5, 6, 7], # right
|
|
||||||
),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
def test_matrix_spiral(matrix, expected):
|
|
||||||
assert stuff.matrix_spiral(matrix) == expected
|
|
||||||
|
Loading…
Reference in New Issue
Block a user