Skip to content

Added (Open) Knight Tour Algorithm #2132

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 18, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 98 additions & 0 deletions backtracking/knight_tour.py
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()