Skip to content

Commit

Permalink
[mypy] Add/fix type annotations for backtracking algorithms (TheAlgor…
Browse files Browse the repository at this point in the history
…ithms#4055)

* Fix mypy errors for backtracking algorithms

* Fix CI failure
  • Loading branch information
dhruvmanila authored Dec 24, 2020
1 parent 0ccb213 commit f3ba9b6
Show file tree
Hide file tree
Showing 7 changed files with 98 additions and 106 deletions.
28 changes: 11 additions & 17 deletions backtracking/all_subsequences.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
from typing import Any, List

"""
In this problem, we want to determine all possible subsequences
of the given sequence. We use backtracking to solve this problem.
In this problem, we want to determine all possible subsequences
of the given sequence. We use backtracking to solve this problem.
Time complexity: O(2^n),
where n denotes the length of the given sequence.
Time complexity: O(2^n),
where n denotes the length of the given sequence.
"""
from typing import Any, List


def generate_all_subsequences(sequence: List[Any]) -> None:
Expand All @@ -32,15 +31,10 @@ def create_state_space_tree(
current_subsequence.pop()


"""
remove the comment to take an input from the user
print("Enter the elements")
sequence = list(map(int, input().split()))
"""

sequence = [3, 1, 2, 4]
generate_all_subsequences(sequence)
if __name__ == "__main__":
seq: List[Any] = [3, 1, 2, 4]
generate_all_subsequences(seq)

sequence = ["A", "B", "C"]
generate_all_subsequences(sequence)
seq.clear()
seq.extend(["A", "B", "C"])
generate_all_subsequences(seq)
8 changes: 4 additions & 4 deletions backtracking/coloring.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
Wikipedia: https://en.wikipedia.org/wiki/Graph_coloring
"""
from __future__ import annotations
from typing import List


def valid_coloring(
neighbours: list[int], colored_vertices: list[int], color: int
neighbours: List[int], colored_vertices: List[int], color: int
) -> bool:
"""
For each neighbour check if coloring constraint is satisfied
Expand All @@ -35,7 +35,7 @@ def valid_coloring(


def util_color(
graph: list[list[int]], max_colors: int, colored_vertices: list[int], index: int
graph: List[List[int]], max_colors: int, colored_vertices: List[int], index: int
) -> bool:
"""
Pseudo-Code
Expand Down Expand Up @@ -86,7 +86,7 @@ def util_color(
return False


def color(graph: list[list[int]], max_colors: int) -> list[int]:
def color(graph: List[List[int]], max_colors: int) -> List[int]:
"""
Wrapper function to call subroutine called util_color
which will either return True or False.
Expand Down
8 changes: 4 additions & 4 deletions backtracking/hamiltonian_cycle.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
Wikipedia: https://en.wikipedia.org/wiki/Hamiltonian_path
"""
from __future__ import annotations
from typing import List


def valid_connection(
graph: list[list[int]], next_ver: int, curr_ind: int, path: list[int]
graph: List[List[int]], next_ver: int, curr_ind: int, path: List[int]
) -> bool:
"""
Checks whether it is possible to add next into path by validating 2 statements
Expand Down Expand Up @@ -47,7 +47,7 @@ def valid_connection(
return not any(vertex == next_ver for vertex in path)


def util_hamilton_cycle(graph: list[list[int]], path: list[int], curr_ind: int) -> bool:
def util_hamilton_cycle(graph: List[List[int]], path: List[int], curr_ind: int) -> bool:
"""
Pseudo-Code
Base Case:
Expand Down Expand Up @@ -108,7 +108,7 @@ def util_hamilton_cycle(graph: list[list[int]], path: list[int], curr_ind: int)
return False


def hamilton_cycle(graph: list[list[int]], start_index: int = 0) -> list[int]:
def hamilton_cycle(graph: List[List[int]], start_index: int = 0) -> List[int]:
r"""
Wrapper function to call subroutine called util_hamilton_cycle,
which will either return array of vertices indicating hamiltonian cycle
Expand Down
12 changes: 7 additions & 5 deletions backtracking/knight_tour.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# Knight Tour Intro: https://www.youtube.com/watch?v=ab_dY3dZFHM

from __future__ import annotations
from typing import List, Tuple


def get_valid_pos(position: tuple[int], n: int) -> list[tuple[int]]:
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.
Expand Down Expand Up @@ -32,7 +32,7 @@ def get_valid_pos(position: tuple[int], n: int) -> list[tuple[int]]:
return permissible_positions


def is_complete(board: list[list[int]]) -> bool:
def is_complete(board: List[List[int]]) -> bool:
"""
Check if the board (matrix) has been completely filled with non-zero values.
Expand All @@ -46,7 +46,9 @@ def is_complete(board: list[list[int]]) -> bool:
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:
def open_knight_tour_helper(
board: List[List[int]], pos: Tuple[int, int], curr: int
) -> bool:
"""
Helper function to solve knight tour problem.
"""
Expand All @@ -66,7 +68,7 @@ def open_knight_tour_helper(board: list[list[int]], pos: tuple[int], curr: int)
return False


def open_knight_tour(n: int) -> list[list[int]]:
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.
Expand Down
26 changes: 11 additions & 15 deletions backtracking/minimax.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
from __future__ import annotations

import math
"""
Minimax helps to achieve maximum score in a game by checking all possible moves
depth is current depth in game tree.
""" Minimax helps to achieve maximum score in a game by checking all possible moves
depth is current depth in game tree.
nodeIndex is index of current node in scores[].
if move is of maximizer return true else false
leaves of game tree is stored in scores[]
height is maximum height of Game tree
nodeIndex is index of current node in scores[].
if move is of maximizer return true else false
leaves of game tree is stored in scores[]
height is maximum height of Game tree
"""
import math
from typing import List


def minimax(
depth: int, node_index: int, is_max: bool, scores: list[int], height: float
depth: int, node_index: int, is_max: bool, scores: List[int], height: float
) -> int:
"""
>>> import math
Expand All @@ -32,10 +32,6 @@ def minimax(
>>> height = math.log(len(scores), 2)
>>> minimax(0, 0, True, scores, height)
12
>>> minimax('1', 2, True, [], 2 )
Traceback (most recent call last):
...
TypeError: '<' not supported between instances of 'str' and 'int'
"""

if depth < 0:
Expand All @@ -59,7 +55,7 @@ def minimax(
)


def main():
def main() -> None:
scores = [90, 23, 6, 33, 21, 65, 123, 34423]
height = math.log(len(scores), 2)
print("Optimal value : ", end="")
Expand Down
63 changes: 28 additions & 35 deletions backtracking/n_queens_math.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,14 @@
for another one or vice versa.
"""
from __future__ import annotations
from typing import List


def depth_first_search(
possible_board: list[int],
diagonal_right_collisions: list[int],
diagonal_left_collisions: list[int],
boards: list[list[str]],
possible_board: List[int],
diagonal_right_collisions: List[int],
diagonal_left_collisions: List[int],
boards: List[List[str]],
n: int,
) -> None:
"""
Expand All @@ -94,48 +94,41 @@ def depth_first_search(
['. . Q . ', 'Q . . . ', '. . . Q ', '. Q . . ']
"""

""" Get next row in the current board (possible_board) to fill it with a queen """
# Get next row in the current board (possible_board) to fill it with a queen
row = len(possible_board)

"""
If row is equal to the size of the board it means there are a queen in each row in
the current board (possible_board)
"""
# If row is equal to the size of the board it means there are a queen in each row in
# the current board (possible_board)
if row == n:
"""
We convert the variable possible_board that looks like this: [1, 3, 0, 2] to
this: ['. Q . . ', '. . . Q ', 'Q . . . ', '. . Q . ']
"""
possible_board = [". " * i + "Q " + ". " * (n - 1 - i) for i in possible_board]
boards.append(possible_board)
# We convert the variable possible_board that looks like this: [1, 3, 0, 2] to
# this: ['. Q . . ', '. . . Q ', 'Q . . . ', '. . Q . ']
boards.append([". " * i + "Q " + ". " * (n - 1 - i) for i in possible_board])
return

""" We iterate each column in the row to find all possible results in each row """
# We iterate each column in the row to find all possible results in each row
for col in range(n):

"""
We apply that we learned previously. First we check that in the current board
(possible_board) there are not other same value because if there is it means
that there are a collision in vertical. Then we apply the two formulas we
learned before:
45º: y - x = b or 45: row - col = b
135º: y + x = b or row + col = b.
And we verify if the results of this two formulas not exist in their variables
respectively. (diagonal_right_collisions, diagonal_left_collisions)
If any or these are True it means there is a collision so we continue to the
next value in the for loop.
"""
# We apply that we learned previously. First we check that in the current board
# (possible_board) there are not other same value because if there is it means
# that there are a collision in vertical. Then we apply the two formulas we
# learned before:
#
# 45º: y - x = b or 45: row - col = b
# 135º: y + x = b or row + col = b.
#
# And we verify if the results of this two formulas not exist in their variables
# respectively. (diagonal_right_collisions, diagonal_left_collisions)
#
# If any or these are True it means there is a collision so we continue to the
# next value in the for loop.
if (
col in possible_board
or row - col in diagonal_right_collisions
or row + col in diagonal_left_collisions
):
continue

""" If it is False we call dfs function again and we update the inputs """
# If it is False we call dfs function again and we update the inputs
depth_first_search(
possible_board + [col],
diagonal_right_collisions + [row - col],
Expand All @@ -146,10 +139,10 @@ def depth_first_search(


def n_queens_solution(n: int) -> None:
boards = []
boards: List[List[str]] = []
depth_first_search([], [], [], boards, n)

""" Print all the boards """
# Print all the boards
for board in boards:
for column in board:
print(column)
Expand Down
Loading

0 comments on commit f3ba9b6

Please sign in to comment.