forked from TheAlgorithms/Python
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added (Open) Knight Tour Algorithm (TheAlgorithms#2132)
* Added (Open) Knight Tour Algorithm * Implemented Suggestions
- Loading branch information
1 parent
19b713a
commit b9e7c89
Showing
1 changed file
with
98 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
# Knight Tour Intro: https://www.youtube.com/watch?v=ab_dY3dZFHM | ||
|
||
from typing import List, Tuple | ||
|
||
|
||
def get_valid_pos(position: Tuple[int], n: int) -> List[Tuple[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], 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 | ||
|
||
raise ValueError(f"Open Kight Tour cannot be performed on a board of size {n}") | ||
|
||
|
||
if __name__ == "__main__": | ||
import doctest | ||
|
||
doctest.testmod() |