
"""simple docstring"""




# Author: OMKAR PATHAK, Nwachukwu Chidiebere

# Use a Python dictionary to construct the graph.
from __future__ import annotations

from pprint import pformat
from typing import Generic, TypeVar

UpperCAmelCase__      :    str    							= TypeVar('T')



class 	lowerCAmelCase_						(Generic[T]  ):


				"""simple docstring"""



				def __init__(self   ,       SCREAMING_SNAKE_CASE__ = True    )					->		None:



											"""simple docstring"""




											SCREAMING_SNAKE_CASE__						:       dict[T, list[T]]           =   {}  # dictionary of lists
											SCREAMING_SNAKE_CASE__						:       Tuple           =   directed



				def 	__magic_name__    (self   ,       SCREAMING_SNAKE_CASE__   ,       SCREAMING_SNAKE_CASE__    )					->		GraphAdjacencyList[T]:



											"""simple docstring"""




											if not self.directed:  # For undirected graphs
																		# if both source vertex and destination vertex are both present in the
																		# adjacency list, add destination vertex to source vertex list of adjacent
																		# vertices and add source vertex to destination vertex list of adjacent
																		# vertices.
																		if source_vertex in self.adj_list and destination_vertex in self.adj_list:
																									self.adj_list[source_vertex].append(SCREAMING_SNAKE_CASE__    )
																									self.adj_list[destination_vertex].append(SCREAMING_SNAKE_CASE__    )
																		# if only source vertex is present in adjacency list, add destination vertex
																		# to source vertex list of adjacent vertices, then create a new vertex with
																		# destination vertex as key and assign a list containing the source vertex
																		# as it's first adjacent vertex.
																		elif source_vertex in self.adj_list:
																									self.adj_list[source_vertex].append(SCREAMING_SNAKE_CASE__    )
																									SCREAMING_SNAKE_CASE__						:       Any           =   [source_vertex]
																		# if only destination vertex is present in adjacency list, add source vertex
																		# to destination vertex list of adjacent vertices, then create a new vertex
																		# with source vertex as key and assign a list containing the source vertex
																		# as it's first adjacent vertex.
																		elif destination_vertex in self.adj_list:
																									self.adj_list[destination_vertex].append(SCREAMING_SNAKE_CASE__    )
																									SCREAMING_SNAKE_CASE__						:       int           =   [destination_vertex]
																		# if both source vertex and destination vertex are not present in adjacency
																		# list, create a new vertex with source vertex as key and assign a list
																		# containing the destination vertex as it's first adjacent vertex also
																		# create a new vertex with destination vertex as key and assign a list
																		# containing the source vertex as it's first adjacent vertex.
																		else:
																									SCREAMING_SNAKE_CASE__						:       Optional[Any]           =   [destination_vertex]
																									SCREAMING_SNAKE_CASE__						:       Tuple           =   [source_vertex]
											else:  # For directed graphs
																		# if both source vertex and destination vertex are present in adjacency
																		# list, add destination vertex to source vertex list of adjacent vertices.
																		if source_vertex in self.adj_list and destination_vertex in self.adj_list:
																									self.adj_list[source_vertex].append(SCREAMING_SNAKE_CASE__    )
																		# if only source vertex is present in adjacency list, add destination
																		# vertex to source vertex list of adjacent vertices and create a new vertex
																		# with destination vertex as key, which has no adjacent vertex
																		elif source_vertex in self.adj_list:
																									self.adj_list[source_vertex].append(SCREAMING_SNAKE_CASE__    )
																									SCREAMING_SNAKE_CASE__						:       int           =   []
																		# if only destination vertex is present in adjacency list, create a new
																		# vertex with source vertex as key and assign a list containing destination
																		# vertex as first adjacent vertex
																		elif destination_vertex in self.adj_list:
																									SCREAMING_SNAKE_CASE__						:       Any           =   [destination_vertex]
																		# if both source vertex and destination vertex are not present in adjacency
																		# list, create a new vertex with source vertex as key and a list containing
																		# destination vertex as it's first adjacent vertex. Then create a new vertex
																		# with destination vertex as key, which has no adjacent vertex
																		else:
																									SCREAMING_SNAKE_CASE__						:       Any           =   [destination_vertex]
																									SCREAMING_SNAKE_CASE__						:       Optional[int]           =   []

											return self



				def __repr__(self    )					->		str:



											"""simple docstring"""




											return pformat(self.adj_list    )









'''simple docstring'''






from math import isclose, sqrt


def  snake_case_     (					_lowerCAmelCase  :						float   ,      _lowerCAmelCase  :						float   ,      _lowerCAmelCase  :						float  )      ->   tuple[float, float, float]:
							UpperCAmelCase :       Optional[int] 							=		point_y / 4 / point_x
							UpperCAmelCase :       str 							=		2 * normal_gradient / (1 + normal_gradient * normal_gradient)
							UpperCAmelCase :       Any 							=		(1 - normal_gradient * normal_gradient) / (
							    1 + normal_gradient * normal_gradient
							)
							UpperCAmelCase :       Union[str, Any] 							=		(sa - ca * incoming_gradient) / (ca + sa * incoming_gradient)

							# to find the next point, solve the simultaeneous equations:
							# y^2 + 4x^2 = 100
							# y - b = m * (x - a)
							# ==> A x^2 + B x + C = 0
							UpperCAmelCase :       Union[str, Any] 							=		outgoing_gradient**2 + 4
							UpperCAmelCase :       Dict 							=		2 * outgoing_gradient * (point_y - outgoing_gradient * point_x)
							UpperCAmelCase :       List[Any] 							=		(point_y - outgoing_gradient * point_x) ** 2 - 100

							UpperCAmelCase :       List[str] 							=		(
							    -linear_term - sqrt(linear_term**2 - 4 * quadratic_term * constant_term  )
							) / (2 * quadratic_term)
							UpperCAmelCase :       Optional[int] 							=		(
							    -linear_term + sqrt(linear_term**2 - 4 * quadratic_term * constant_term  )
							) / (2 * quadratic_term)

							# two solutions, one of which is our input point
							UpperCAmelCase :       Optional[Any] 							=		x_minus if isclose(_lowerCAmelCase   ,      _lowerCAmelCase  ) else x_plus
							UpperCAmelCase :       Union[str, Any] 							=		point_y + outgoing_gradient * (next_x - point_x)

							return next_x, next_y, outgoing_gradient


def  snake_case_     (					_lowerCAmelCase  :						float = 1.4   ,      _lowerCAmelCase  :						float = -9.6  )      ->   int:
							UpperCAmelCase :       int 							=		0
							UpperCAmelCase :       float 							=		first_x_coord
							UpperCAmelCase :       float 							=		first_y_coord
							UpperCAmelCase :       float 							=		(1_0.1 - point_y) / (0.0 - point_x)

							while not (-0.0_1 <= point_x <= 0.0_1 and point_y > 0):
														UpperCAmelCase							,		UpperCAmelCase							,		UpperCAmelCase :       str 							=		next_point(_lowerCAmelCase   ,      _lowerCAmelCase   ,      _lowerCAmelCase  )
														num_reflections += 1

							return num_reflections


if __name__ == "__main__":
						print(F"{solution() = }")





