





from __future__ import annotations

import time

A   : Any			=				list[tuple[int, int]]

A   : Any			=				[
    [0, 0, 0, 0, 0, 0, 0],
    [0, 1, 0, 0, 0, 0, 0],  # 0 are free path whereas 1's are obstacles
    [0, 0, 0, 0, 0, 0, 0],
    [0, 0, 1, 0, 0, 0, 0],
    [1, 0, 1, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 1, 0, 0],
]

A   : Tuple			=				[[-1, 0], [0, -1], [1, 0], [0, 1]]  # up, left, down, right


class   A      :
			'''simple docstring'''




			def __init__(      self       :   List[Any]							,     __lowerCAmelCase       :   int							,     __lowerCAmelCase       :   int							,     __lowerCAmelCase       :   int							,     __lowerCAmelCase       :   int							,     __lowerCAmelCase       :   Node | None       )     ->     int:







					"""simple docstring"""






					A__  				=       pos_x
					A__  				=       pos_y
					A__  				=       (pos_y, pos_x)
					A__  				=       goal_x
					A__  				=       goal_y
					A__  				=       parent


class   A      :
			'''simple docstring'''




			def __init__(      self       :   Optional[Any]							,     __lowerCAmelCase       :   tuple[int, int]							,     __lowerCAmelCase       :   tuple[int, int]       )     ->     List[str]:







					"""simple docstring"""






					A__  				=       Node(start[1]							,     start[0]							,     goal[1]							,     goal[0]							,     __lowerCAmelCase       )
					A__  				=       Node(goal[1]							,     goal[0]							,     goal[1]							,     goal[0]							,     __lowerCAmelCase       )

					A__  				=       [self.start]
					A__  				=       False






			def        a_	(      self       :   List[str]       )     ->     Path | None:







					"""simple docstring"""






					while self.node_queue:
							A__  				=       self.node_queue.pop(0       )

							if current_node.pos == self.target.pos:
									A__  				=       True
									return self.retrace_path(__lowerCAmelCase       )

							A__  				=       self.get_successors(__lowerCAmelCase       )

							for node in successors:
									self.node_queue.append(__lowerCAmelCase       )

					if not self.reached:
							return [self.start.pos]
					return None






			def        a_	(      self       :   Any							,     __lowerCAmelCase       :   Node       )     ->     list[Node]:







					"""simple docstring"""






					A__  				=       []
					for action in delta:
							A__  				=       parent.pos_x + action[1]
							A__  				=       parent.pos_y + action[0]
							if not (0 <= pos_x <= len(grid[0]       ) - 1 and 0 <= pos_y <= len(__lowerCAmelCase       ) - 1):
									continue

							if grid[pos_y][pos_x] != 0:
									continue

							successors.append(
							    Node(__lowerCAmelCase							,     __lowerCAmelCase							,     self.target.pos_y							,     self.target.pos_x							,     __lowerCAmelCase       )       )
					return successors







			def        a_	(      self       :   List[Any]							,     __lowerCAmelCase       :   Node | None       )     ->     Path:







					"""simple docstring"""






					A__  				=       node
					A__  				=       []
					while current_node is not None:
							path.append((current_node.pos_y, current_node.pos_x)       )
							A__  				=       current_node.parent
					path.reverse()
					return path


class   A      :
			'''simple docstring'''




			def __init__(      self       :   int							,     __lowerCAmelCase       :   Optional[Any]							,     __lowerCAmelCase       :   int       )     ->     Union[str, Any]:







					"""simple docstring"""






					A__  				=       BreadthFirstSearch(__lowerCAmelCase							,     __lowerCAmelCase       )
					A__  				=       BreadthFirstSearch(__lowerCAmelCase							,     __lowerCAmelCase       )
					A__  				=       False






			def        a_	(      self       :   Optional[Any]       )     ->     Path | None:







					"""simple docstring"""






					while self.fwd_bfs.node_queue or self.bwd_bfs.node_queue:
							A__  				=       self.fwd_bfs.node_queue.pop(0       )
							A__  				=       self.bwd_bfs.node_queue.pop(0       )

							if current_bwd_node.pos == current_fwd_node.pos:
									A__  				=       True
									return self.retrace_bidirectional_path(
									    __lowerCAmelCase							,     __lowerCAmelCase       )

							A__  				=       current_bwd_node
							A__  				=       current_fwd_node

							A__  				=       {
							    self.fwd_bfs: self.fwd_bfs.get_successors(__lowerCAmelCase       ),
							    self.bwd_bfs: self.bwd_bfs.get_successors(__lowerCAmelCase       ),
							}

							for bfs in [self.fwd_bfs, self.bwd_bfs]:
									for node in successors[bfs]:
											bfs.node_queue.append(__lowerCAmelCase       )

					if not self.reached:
							return [self.fwd_bfs.start.pos]
					return None







			def        a_	(      self       :   int							,     __lowerCAmelCase       :   Node							,     __lowerCAmelCase       :   Node       )     ->     Path:







					"""simple docstring"""






					A__  				=       self.fwd_bfs.retrace_path(__lowerCAmelCase       )
					A__  				=       self.bwd_bfs.retrace_path(__lowerCAmelCase       )
					bwd_path.pop()
					bwd_path.reverse()
					A__  				=       fwd_path + bwd_path
					return path


if __name__ == "__main__":
					# all coordinates are given in format [y,x]
					import doctest

					doctest.testmod()
					A   : str			=				(0, 0)
					A   : List[str]			=				(len(grid) - 1, len(grid[0]) - 1)
					for elem in grid:
										print(elem)

					A   : Dict			=				time.time()
					A   : Any			=				BreadthFirstSearch(init, goal)
					A   : Union[str, Any]			=				bfs.search()
					A   : Any			=				time.time() - start_bfs_time

					print('''Unidirectional BFS computation time : ''', bfs_time)

					A   : Optional[int]			=				time.time()
					A   : str			=				BidirectionalBreadthFirstSearch(init, goal)
					A   : List[Any]			=				bd_bfs.search()
					A   : Dict			=				time.time() - start_bd_bfs_time

					print('''Bidirectional BFS computation time : ''', bd_bfs_time)










from maths.is_square_free import is_square_free
from maths.prime_factors import prime_factors







def        __lowerCamelCase (							__a       :int   )		->    int:






		"""simple docstring"""

		A__  				=       prime_factors(__a   )
		if is_square_free(__a   ):
				return -1 if len(__a   ) % 2 else 1
		return 0


if __name__ == "__main__":
					import doctest

					doctest.testmod()



