



from __future__ import annotations

import time

lowerCAmelCase__					  =  list[tuple[int, int]]

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

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

class 				snake_case__:

					"""simple docstring"""






					def __init__(							self :     Union[str, Any]				,       SCREAMING_SNAKE_CASE :     Optional[int]				,       SCREAMING_SNAKE_CASE :     str				,       SCREAMING_SNAKE_CASE :     Optional[Any]				,       SCREAMING_SNAKE_CASE :     Dict				,       SCREAMING_SNAKE_CASE :     str					):
								lowercase__					:   Optional[int]													=					pos_x
								lowercase__					:   int													=					pos_y
								lowercase__					:   Dict													=					(pos_y, pos_x)
								lowercase__					:   Union[str, Any]													=					goal_x
								lowercase__					:   Optional[int]													=					goal_y
								lowercase__					:   Tuple													=					parent






class 				snake_case__:

					"""simple docstring"""






					def __init__(							self :     Union[str, Any]				,       SCREAMING_SNAKE_CASE :     int				,       SCREAMING_SNAKE_CASE :     int					):
								lowercase__					:   Optional[Any]													=					Node(start[1]				,       start[0]				,       goal[1]				,       goal[0]				,       lowerCamelCase__					)
								lowercase__					:   Any													=					Node(goal[1]				,       goal[0]				,       goal[1]				,       goal[0]				,       lowerCamelCase__					)

								lowercase__					:   Optional[Any]													=					[self.start]
								lowercase__					:   List[Any]													=					False







					def 			snake_case					(							self :     Any					):
								while self.node_queue:
											lowercase__					:   Optional[int]													=					self.node_queue.pop(0					)

											if current_node.pos == self.target.pos:
														lowercase__					:   Any													=					True
														return self.retrace_path(lowerCamelCase__					)

											lowercase__					:   Tuple													=					self.get_successors(lowerCamelCase__					)

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

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







					def 			snake_case					(							self :     Dict				,       SCREAMING_SNAKE_CASE :     List[str]					):
								lowercase__					:   str													=					[]
								for action in delta:
											lowercase__					:   Dict													=					parent.pos_x + action[1]
											lowercase__					:   Any													=					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 			snake_case					(							self :     Tuple				,       SCREAMING_SNAKE_CASE :     int					):
								lowercase__					:   Union[str, Any]													=					node
								lowercase__					:   List[Any]													=					[]
								while current_node is not None:
											path.append((current_node.pos_y, current_node.pos_x)					)
											lowercase__					:   Tuple													=					current_node.parent
								path.reverse()
								return path






class 				snake_case__:

					"""simple docstring"""






					def __init__(							self :     List[str]				,       SCREAMING_SNAKE_CASE :     Union[str, Any]				,       SCREAMING_SNAKE_CASE :     Dict					):
								lowercase__					:   Any													=					BreadthFirstSearch(lowerCamelCase__				,       lowerCamelCase__					)
								lowercase__					:   List[Any]													=					BreadthFirstSearch(lowerCamelCase__				,       lowerCamelCase__					)
								lowercase__					:   List[str]													=					False







					def 			snake_case					(							self :     Dict					):
								while self.fwd_bfs.node_queue or self.bwd_bfs.node_queue:
											lowercase__					:   List[str]													=					self.fwd_bfs.node_queue.pop(0					)
											lowercase__					:   Union[str, Any]													=					self.bwd_bfs.node_queue.pop(0					)

											if current_bwd_node.pos == current_fwd_node.pos:
														lowercase__					:   Optional[Any]													=					True
														return self.retrace_bidirectional_path(
														    lowerCamelCase__				,       lowerCamelCase__					)

											lowercase__					:   Dict													=					current_bwd_node
											lowercase__					:   List[Any]													=					current_fwd_node

											lowercase__					:   Tuple													=					{
											    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 			snake_case					(							self :     Tuple				,       SCREAMING_SNAKE_CASE :     Tuple				,       SCREAMING_SNAKE_CASE :     str					):
								lowercase__					:   Dict													=					self.fwd_bfs.retrace_path(lowerCamelCase__					)
								lowercase__					:   Dict													=					self.bwd_bfs.retrace_path(lowerCamelCase__					)
								bwd_path.pop()
								bwd_path.reverse()
								lowercase__					:   int													=					fwd_path + bwd_path
								return path


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

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

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

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

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

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









from collections import Counter
from timeit import timeit


def  __lowerCamelCase (       lowerCamelCase__ = ""					,			):

				"""simple docstring"""


				return sum(c % 2 for c in Counter(input_str.replace(" "					,			""						).lower()						).values()						) < 2


def  __lowerCamelCase (       lowerCamelCase__ = ""						):

				"""simple docstring"""


				if len(lowerCamelCase__						) == 0:
								return True
				lowercase__					:   str													=					input_str.replace(" "					,			""						).lower()
				# character_freq_dict: Stores the frequency of every character in the input string
				lowercase__					:   dict[str, int]													=					{}

				for character in lower_case_input_str:
								lowercase__					:   List[Any]													=					character_freq_dict.get(lowerCamelCase__					,			0						) + 1
				lowercase__					:   List[Any]													=					0

				for character_count in character_freq_dict.values():
								if character_count % 2:
												odd_char += 1
				if odd_char > 1:
								return False
				return True


def  __lowerCamelCase (       lowerCamelCase__ = ""						):

				"""simple docstring"""


				print("\nFor string = "					,			lowerCamelCase__					,			":"						)
				print(
				    "> can_string_be_rearranged_as_palindrome_counter()"					,			"\tans ="					,			can_string_be_rearranged_as_palindrome_counter(lowerCamelCase__						)					,			"\ttime ="					,			timeit(
				        "z.can_string_be_rearranged_as_palindrome_counter(z.check_str)"					,			setup="import __main__ as z"					,			)					,			"seconds"					,			)
				print(
				    "> can_string_be_rearranged_as_palindrome()"					,			"\tans ="					,			can_string_be_rearranged_as_palindrome(lowerCamelCase__						)					,			"\ttime ="					,			timeit(
				        "z.can_string_be_rearranged_as_palindrome(z.check_str)"					,			setup="import __main__ as z"					,			)					,			"seconds"					,			)


if __name__ == "__main__":
				lowerCAmelCase__					  =  input(
				    '''Enter string to determine if it can be rearranged as a palindrome or not: '''
				).strip()
				benchmark(check_str)
				lowerCAmelCase__					  =  can_string_be_rearranged_as_palindrome_counter(check_str)
				print(f'''{check_str} can {"" if status else "not "}be rearranged as a palindrome''')




