



'''simple docstring'''

import builtins
import sys

from ...utils.imports import _is_package_available
from . import cursor, input
from .helpers import Direction, clear_line, forceWrite, linebreak, move_cursor, reset_cursor, writeColor
from .keymap import KEYMAP


SCREAMING_SNAKE_CASE__     :						Union[str, Any]	=  False
try:
			SCREAMING_SNAKE_CASE__     :						Optional[int]	=  _is_package_available('''google.colab''')
except ModuleNotFoundError:
			pass

@input.register
class 							a__:






			def __init__(     self					,   _UpperCAmelCase = None					,   _UpperCAmelCase = []						)							->							Any:
					snake_case__	     =0
					snake_case__	     =choices
					snake_case__	     =prompt
					if sys.platform == "win32":
							snake_case__	     ='*'
					else:
							snake_case__	     ='➔ '






			def 						_lowercase  (     self					,   _UpperCAmelCase					,   _UpperCAmelCase = ""						)							->							List[Any]:
					if sys.platform != "win32":
							writeColor(self.choices[index]					,   32					,   _UpperCAmelCase						)
					else:
							forceWrite(self.choices[index]					,   _UpperCAmelCase						)






			def 						_lowercase  (     self					,   _UpperCAmelCase						)							->							Optional[int]:
					if index == self.position:
							forceWrite(f""" {self.arrow_char} """						)
							self.write_choice(_UpperCAmelCase						)
					else:
							forceWrite(f"""    {self.choices[index]}"""						)
					reset_cursor()






			def 						_lowercase  (     self					,   _UpperCAmelCase					,   _UpperCAmelCase = 1						)							->							Union[str, Any]:
					snake_case__	     =self.position
					if direction == Direction.DOWN:
							if self.position + 1 >= len(self.choices						):
									return
							self.position += num_spaces
					else:
							if self.position - 1 < 0:
									return
							self.position -= num_spaces
					clear_line()
					self.print_choice(_UpperCAmelCase						)
					move_cursor(_UpperCAmelCase					,   direction.name						)
					self.print_choice(self.position						)






			@input.mark(KEYMAP['up']						)
			def 						_lowercase  (     self						)							->							List[Any]:
					self.move_direction(Direction.UP						)






			@input.mark(KEYMAP['down']						)
			def 						_lowercase  (     self						)							->							str:
					self.move_direction(Direction.DOWN						)






			@input.mark(KEYMAP['newline']						)
			def 						_lowercase  (     self						)							->							List[Any]:
					move_cursor(len(self.choices						) - self.position					,   'DOWN'						)
					return self.position






			@input.mark(KEYMAP['interrupt']						)
			def 						_lowercase  (     self						)							->							int:
					move_cursor(len(self.choices						) - self.position					,   'DOWN'						)
					raise KeyboardInterrupt






			@input.mark_multiple(*[KEYMAP[str(_UpperCAmelCase						)] for number in range(10						)]						)
			def 						_lowercase  (     self						)							->							List[Any]:
					snake_case__	     =int(chr(self.current_selection						)						)
					snake_case__	     =index - self.position
					if index == self.position:
							return
					if index < len(self.choices						):
							if self.position > index:
									self.move_direction(Direction.UP					,   -movement						)
							elif self.position < index:
									self.move_direction(Direction.DOWN					,   _UpperCAmelCase						)
							else:
									return
					else:
							return






			def 						_lowercase  (     self					,   _UpperCAmelCase = 0						)							->							Dict:
					if self.prompt:
							linebreak()
							forceWrite(self.prompt					,   '\n'						)
							if in_colab:
									forceWrite('Please input a choice index (starting from 0), and press enter'					,   '\n'						)
							else:
									forceWrite('Please select a choice using the arrow or number keys, and selecting with enter'					,   '\n'						)
					snake_case__	     =default_choice
					for i in range(len(self.choices						)						):
							self.print_choice(_UpperCAmelCase						)
							forceWrite('\n'						)
					move_cursor(len(self.choices						) - self.position					,   'UP'						)
					with cursor.hide():
							while True:
									if in_colab:
											try:
													snake_case__	     =int(builtins.input()						)
											except ValueError:
													snake_case__	     =default_choice
									else:
											snake_case__	     =self.handle_input()
									if choice is not None:
											reset_cursor()
											for _ in range(len(self.choices						) + 1						):
													move_cursor(1					,   'UP'						)
													clear_line()
											self.write_choice(_UpperCAmelCase					,   '\n'						)
											return choice









'''simple docstring'''

from __future__ import annotations






def 				a  (     UpperCamelCase_    :    str      ,					UpperCamelCase_    :    list[str] | None = None      ,					UpperCamelCase_    :    dict[str, float] | None = None      ,					UpperCamelCase_    :    bool = False      ,					)       ->	tuple[int, float, str]:
		snake_case__	     =cipher_alphabet or [chr(UpperCamelCase_			) for i in range(97      ,					123			)]

		# If the argument is None or the user provided an empty dictionary
		if not frequencies_dict:
				# Frequencies of letters in the english language (how much they show up)
				snake_case__	     ={
				    'a': 0.0_8_4_9_7,
				    'b': 0.0_1_4_9_2,
				    'c': 0.0_2_2_0_2,
				    'd': 0.0_4_2_5_3,
				    'e': 0.1_1_1_6_2,
				    'f': 0.0_2_2_2_8,
				    'g': 0.0_2_0_1_5,
				    'h': 0.0_6_0_9_4,
				    'i': 0.0_7_5_4_6,
				    'j': 0.0_0_1_5_3,
				    'k': 0.0_1_2_9_2,
				    'l': 0.0_4_0_2_5,
				    'm': 0.0_2_4_0_6,
				    'n': 0.0_6_7_4_9,
				    'o': 0.0_7_5_0_7,
				    'p': 0.0_1_9_2_9,
				    'q': 0.0_0_0_9_5,
				    'r': 0.0_7_5_8_7,
				    's': 0.0_6_3_2_7,
				    't': 0.0_9_3_5_6,
				    'u': 0.0_2_7_5_8,
				    'v': 0.0_0_9_7_8,
				    'w': 0.0_2_5_6_0,
				    'x': 0.0_0_1_5_0,
				    'y': 0.0_1_9_9_4,
				    'z': 0.0_0_0_7_7,
				}
		else:
				# Custom frequencies dictionary
				snake_case__	     =frequencies_dict

		if not case_sensitive:
				snake_case__	     =ciphertext.lower()

		# Chi squared statistic values
		snake_case__	     ={}

		# cycle through all of the shifts
		for shift in range(len(UpperCamelCase_			)			):
				snake_case__	     =''

				# decrypt the message with the shift
				for letter in ciphertext:
						try:
								# Try to index the letter in the alphabet
								snake_case__	     =(alphabet_letters.index(letter.lower()			) - shift) % len(
								    UpperCamelCase_			)
								decrypted_with_shift += (
								    alphabet_letters[new_key].upper()
								    if case_sensitive and letter.isupper()
								    else alphabet_letters[new_key]
								)
						except ValueError:
								# Append the character if it isn't in the alphabet
								decrypted_with_shift += letter

				snake_case__	     =0.0

				# Loop through each letter in the decoded message with the shift
				for letter in decrypted_with_shift:
						if case_sensitive:
								snake_case__	     =letter.lower()
								if letter in frequencies:
										# Get the amount of times the letter occurs in the message
										snake_case__	     =decrypted_with_shift.lower().count(UpperCamelCase_			)

										# Get the excepcted amount of times the letter should appear based
										# on letter frequencies
										snake_case__	     =frequencies[letter] * occurrences

										# Complete the chi squared statistic formula
										snake_case__	     =((occurrences - expected) ** 2) / expected

										# Add the margin of error to the total chi squared statistic
										chi_squared_statistic += chi_letter_value
						else:
								if letter.lower() in frequencies:
										# Get the amount of times the letter occurs in the message
										snake_case__	     =decrypted_with_shift.count(UpperCamelCase_			)

										# Get the excepcted amount of times the letter should appear based
										# on letter frequencies
										snake_case__	     =frequencies[letter] * occurrences

										# Complete the chi squared statistic formula
										snake_case__	     =((occurrences - expected) ** 2) / expected

										# Add the margin of error to the total chi squared statistic
										chi_squared_statistic += chi_letter_value

        # Add the data to the chi_squared_statistic_values dictionary
				snake_case__	     =(
				    chi_squared_statistic,
				    decrypted_with_shift,
				)

		# Get the most likely cipher by finding the cipher with the smallest chi squared
		# statistic
		def chi_squared_statistic_values_sorting_key(UpperCamelCase_    :    int			) -> tuple[float, str]:
				return chi_squared_statistic_values[key]

		snake_case__	     =min(
		    UpperCamelCase_      ,					key=UpperCamelCase_      ,					)

		# Get all the data from the most likely cipher (key, decoded message)
		(
		    (
		    snake_case__
		)     ,	(
		    snake_case__
		)     ,	
		)	     =chi_squared_statistic_values[most_likely_cipher]

		# Return the data on the most likely shift
		return (
		    most_likely_cipher,
		    most_likely_cipher_chi_squared_value,
		    decoded_most_likely_cipher,
		)




