
from __future__ import annotations

import time

UpperCamelCase_   	=	list[tuple[int, int]]

UpperCamelCase_   	=	[
    [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],
]

UpperCamelCase_   	=	[[-1, 0], [0, -1], [1, 0], [0, 1]]  # up, left, down, right

class       a		:







							def __init__(						self  :  Any      ,				snake_case__  :  int      ,				snake_case__  :  int      ,				snake_case__  :  int      ,				snake_case__  :  int      ,				snake_case__  :  Node | None ):
								"""simple docstring"""







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

class       a		:







							def __init__(						self  :  Union[str, Any]      ,				snake_case__  :  tuple[int, int]      ,				snake_case__  :  tuple[int, int] ):
								"""simple docstring"""







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

								__lowerCAmelCase         =							[self.start]
								__lowerCAmelCase         =							False







							def       UpperCAmelCase__					(						self  :  Any ):
								"""simple docstring"""







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

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

									__lowerCAmelCase         =							self.get_successors(snake_case__ )

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

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







							def       UpperCAmelCase__					(						self  :  Optional[int]      ,				snake_case__  :  Node ):
								"""simple docstring"""







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

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

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







							def       UpperCAmelCase__					(						self  :  Tuple      ,				snake_case__  :  Node | None ):
								"""simple docstring"""







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

class       a		:







							def __init__(						self  :  int      ,				snake_case__  :  int      ,				snake_case__  :  Optional[Any] ):
								"""simple docstring"""







								__lowerCAmelCase         =							BreadthFirstSearch(snake_case__      ,				snake_case__ )
								__lowerCAmelCase         =							BreadthFirstSearch(snake_case__      ,				snake_case__ )
								__lowerCAmelCase         =							False







							def       UpperCAmelCase__					(						self  :  List[str] ):
								"""simple docstring"""







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

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

									__lowerCAmelCase         =							current_bwd_node
									__lowerCAmelCase         =							current_fwd_node

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

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

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







							def       UpperCAmelCase__					(						self  :  Tuple      ,				snake_case__  :  Node      ,				snake_case__  :  Node ):
								"""simple docstring"""







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


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

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

					UpperCamelCase_   	=	time.time()
					UpperCamelCase_   	=	BreadthFirstSearch(init, goal)
					UpperCamelCase_   	=	bfs.search()
					UpperCamelCase_   	=	time.time() - start_bfs_time

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

					UpperCamelCase_   	=	time.time()
					UpperCamelCase_   	=	BidirectionalBreadthFirstSearch(init, goal)
					UpperCamelCase_   	=	bd_bfs.search()
					UpperCamelCase_   	=	time.time() - start_bd_bfs_time

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








import fire

from utils import calculate_rouge, save_json






def 		_UpperCAmelCase   (	UpperCamelCase:     Any			,							UpperCamelCase:     Union[str, Any]			,							UpperCamelCase:     List[Any]=None			,							**UpperCamelCase:     Optional[int]  ):






	"""simple docstring"""


	__lowerCAmelCase         =							[x.strip() for x in open(UpperCamelCase  ).readlines()]
	__lowerCAmelCase         =							[x.strip() for x in open(UpperCamelCase  ).readlines()][: len(UpperCamelCase  )]
	__lowerCAmelCase         =							calculate_rouge(UpperCamelCase			,							UpperCamelCase			,							**UpperCamelCase  )
	if save_path is not None:
		save_json(UpperCamelCase			,							UpperCamelCase			,							indent=UpperCamelCase  )
	return metrics  # these print nicely


if __name__ == "__main__":
					fire.Fire(calculate_rouge_path)






