mirror of
https://github.com/TheAlgorithms/Python.git
synced 2024-11-24 05:21:09 +00:00
4b79d771cd
* Add more ruff rules * Add more ruff rules * pre-commit: Update ruff v0.0.269 -> v0.0.270 * Apply suggestions from code review * Fix doctest * Fix doctest (ignore whitespace) * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: Dhruv Manilawala <dhruvmanila@gmail.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
102 lines
2.4 KiB
Python
102 lines
2.4 KiB
Python
# Knight Tour Intro: https://www.youtube.com/watch?v=ab_dY3dZFHM
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
def get_valid_pos(position: tuple[int, int], n: int) -> list[tuple[int, int]]:
|
|
"""
|
|
Find all the valid positions a knight can move to from the current position.
|
|
|
|
>>> get_valid_pos((1, 3), 4)
|
|
[(2, 1), (0, 1), (3, 2)]
|
|
"""
|
|
|
|
y, x = position
|
|
positions = [
|
|
(y + 1, x + 2),
|
|
(y - 1, x + 2),
|
|
(y + 1, x - 2),
|
|
(y - 1, x - 2),
|
|
(y + 2, x + 1),
|
|
(y + 2, x - 1),
|
|
(y - 2, x + 1),
|
|
(y - 2, x - 1),
|
|
]
|
|
permissible_positions = []
|
|
|
|
for position in positions:
|
|
y_test, x_test = position
|
|
if 0 <= y_test < n and 0 <= x_test < n:
|
|
permissible_positions.append(position)
|
|
|
|
return permissible_positions
|
|
|
|
|
|
def is_complete(board: list[list[int]]) -> bool:
|
|
"""
|
|
Check if the board (matrix) has been completely filled with non-zero values.
|
|
|
|
>>> is_complete([[1]])
|
|
True
|
|
|
|
>>> is_complete([[1, 2], [3, 0]])
|
|
False
|
|
"""
|
|
|
|
return not any(elem == 0 for row in board for elem in row)
|
|
|
|
|
|
def open_knight_tour_helper(
|
|
board: list[list[int]], pos: tuple[int, int], curr: int
|
|
) -> bool:
|
|
"""
|
|
Helper function to solve knight tour problem.
|
|
"""
|
|
|
|
if is_complete(board):
|
|
return True
|
|
|
|
for position in get_valid_pos(pos, len(board)):
|
|
y, x = position
|
|
|
|
if board[y][x] == 0:
|
|
board[y][x] = curr + 1
|
|
if open_knight_tour_helper(board, position, curr + 1):
|
|
return True
|
|
board[y][x] = 0
|
|
|
|
return False
|
|
|
|
|
|
def open_knight_tour(n: int) -> list[list[int]]:
|
|
"""
|
|
Find the solution for the knight tour problem for a board of size n. Raises
|
|
ValueError if the tour cannot be performed for the given size.
|
|
|
|
>>> open_knight_tour(1)
|
|
[[1]]
|
|
|
|
>>> open_knight_tour(2)
|
|
Traceback (most recent call last):
|
|
...
|
|
ValueError: Open Kight Tour cannot be performed on a board of size 2
|
|
"""
|
|
|
|
board = [[0 for i in range(n)] for j in range(n)]
|
|
|
|
for i in range(n):
|
|
for j in range(n):
|
|
board[i][j] = 1
|
|
if open_knight_tour_helper(board, (i, j), 1):
|
|
return board
|
|
board[i][j] = 0
|
|
|
|
msg = f"Open Kight Tour cannot be performed on a board of size {n}"
|
|
raise ValueError(msg)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
import doctest
|
|
|
|
doctest.testmod()
|