
import string

import numpy


def 				SCREAMING_SNAKE_CASE_   (      UpperCamelCase__			,		UpperCamelCase__		):
      return b if a == 0 else greatest_common_divisor(b % a			,		lowercase_		)




class 					_lowerCamelCase			:





     """simple docstring"""







     SCREAMING_SNAKE_CASE_		 =	string.ascii_uppercase + string.digits
     # This cipher takes alphanumerics into account
     # i.e. a total of 36 characters

     # take x and return x % len(key_string)
     SCREAMING_SNAKE_CASE_		 =	numpy.vectorize(lambda UpperCamelCase_			: x % 36			)

     SCREAMING_SNAKE_CASE_		 =	numpy.vectorize(lowerCamelCase__			)






     def __init__(				self    ,    __SCREAMING_SNAKE_CASE	)	-> Union[str, Any]:




           """simple docstring"""







           UpperCamelCase__     : Tuple											=					self.modulus(a__	)  # mod36 calc's on the encrypt key
           self.check_determinant()  # validate the determinant of the encryption key
           UpperCamelCase__     : Dict											=					encrypt_key.shape[0]






     def  __SCREAMING_SNAKE_CASE      (				self    ,    __SCREAMING_SNAKE_CASE	)	-> Any:




           """simple docstring"""







           return self.key_string.index(a__	)






     def  __SCREAMING_SNAKE_CASE      (				self    ,    __SCREAMING_SNAKE_CASE	)	-> Dict:




           """simple docstring"""







           return self.key_string[round(a__	)]






     def  __SCREAMING_SNAKE_CASE      (				self	)	-> str:




           """simple docstring"""







           UpperCamelCase__     : Tuple											=					round(numpy.linalg.det(self.encrypt_key	)	)

           if det < 0:
                 UpperCamelCase__     : Union[str, Any]											=					det % len(self.key_string	)

           UpperCamelCase__     : int											=					len(self.key_string	)
           if greatest_common_divisor(a__    ,    len(self.key_string	)	) != 1:
                 UpperCamelCase__     : int											=					(
                     F'''determinant modular {req_l} of encryption key({det}) '''
                     F'''is not co prime w.r.t {req_l}.\nTry another key.'''
                 )
                 raise ValueError(a__	)






     def  __SCREAMING_SNAKE_CASE      (				self    ,    __SCREAMING_SNAKE_CASE	)	-> Optional[Any]:




           """simple docstring"""







           UpperCamelCase__     : Optional[int]											=					[char for char in text.upper() if char in self.key_string]

           UpperCamelCase__     : int											=					chars[-1]
           while len(a__	) % self.break_key != 0:
                 chars.append(a__	)

           return "".join(a__	)






     def  __SCREAMING_SNAKE_CASE      (				self    ,    __SCREAMING_SNAKE_CASE	)	-> Optional[int]:




           """simple docstring"""







           UpperCamelCase__     : List[Any]											=					self.process_text(text.upper()	)
           UpperCamelCase__     : int											=					''''''

           for i in range(0    ,    len(a__	) - self.break_key + 1    ,    self.break_key	):
                 UpperCamelCase__     : Optional[int]											=					text[i : i + self.break_key]
                 UpperCamelCase__     : List[str]											=					[self.replace_letters(a__	) for char in batch]
                 UpperCamelCase__     : Dict											=					numpy.array([vec]	).T
                 UpperCamelCase__     : List[Any]											=					self.modulus(self.encrypt_key.dot(a__	)	).T.tolist()[
                     0
                 ]
                 UpperCamelCase__     : Dict											=					''''''.join(
                     self.replace_digits(a__	) for num in batch_encrypted	)
                 encrypted += encrypted_batch

           return encrypted






     def  __SCREAMING_SNAKE_CASE      (				self	)	-> str:




           """simple docstring"""







           UpperCamelCase__     : Optional[Any]											=					round(numpy.linalg.det(self.encrypt_key	)	)

           if det < 0:
                 UpperCamelCase__     : str											=					det % len(self.key_string	)
           UpperCamelCase__     : str											=					None
           for i in range(len(self.key_string	)	):
                 if (det * i) % len(self.key_string	) == 1:
                       UpperCamelCase__     : str											=					i
                       break

           UpperCamelCase__     : Tuple											=					(
               det_inv
               * numpy.linalg.det(self.encrypt_key	)
               * numpy.linalg.inv(self.encrypt_key	)
           )

           return self.to_int(self.modulus(a__	)	)






     def  __SCREAMING_SNAKE_CASE      (				self    ,    __SCREAMING_SNAKE_CASE	)	-> int:




           """simple docstring"""







           UpperCamelCase__     : Optional[Any]											=					self.make_decrypt_key()
           UpperCamelCase__     : Optional[int]											=					self.process_text(text.upper()	)
           UpperCamelCase__     : Optional[Any]											=					''''''

           for i in range(0    ,    len(a__	) - self.break_key + 1    ,    self.break_key	):
                 UpperCamelCase__     : Union[str, Any]											=					text[i : i + self.break_key]
                 UpperCamelCase__     : Optional[int]											=					[self.replace_letters(a__	) for char in batch]
                 UpperCamelCase__     : Union[str, Any]											=					numpy.array([vec]	).T
                 UpperCamelCase__     : Optional[int]											=					self.modulus(decrypt_key.dot(a__	)	).T.tolist()[0]
                 UpperCamelCase__     : str											=					''''''.join(
                     self.replace_digits(a__	) for num in batch_decrypted	)
                 decrypted += decrypted_batch

           return decrypted


def 				SCREAMING_SNAKE_CASE_   (      ):
      UpperCamelCase__     : List[Any]											=					int(input('''Enter the order of the encryption key: '''		)		)
      UpperCamelCase__     : Any											=					[]

      print('''Enter each row of the encryption key with space separated integers'''		)
      for _ in range(lowercase_		):
            UpperCamelCase__     : str											=					[int(lowercase_		) for x in input().split()]
            hill_matrix.append(lowercase_		)

      UpperCamelCase__     : Optional[int]											=					HillCipher(numpy.array(lowercase_		)		)

      print('''Would you like to encrypt or decrypt some text? (1 or 2)'''		)
      UpperCamelCase__     : List[str]											=					input('''\n1. Encrypt\n2. Decrypt\n'''		)
      if option == "1":
            UpperCamelCase__     : Tuple											=					input('''What text would you like to encrypt?: '''		)
            print('''Your encrypted text is:'''		)
            print(hc.encrypt(lowercase_		)		)
      elif option == "2":
            UpperCamelCase__     : int											=					input('''What text would you like to decrypt?: '''		)
            print('''Your decrypted text is:'''		)
            print(hc.decrypt(lowercase_		)		)


if __name__ == "__main__":
    import doctest

    doctest.testmod()

    main()









from __future__ import annotations

from scipy.special import comb  # type: ignore







class       __A							:




      """simple docstring"""







      def __init__(		self   ,				a__):



             """simple docstring"""





             _lowerCamelCase				:  str						=		list_of_points
             # Degree determines the flexibility of the curve.
             # Degree = 1 will produce a straight line.
             _lowerCamelCase				:  List[Any]						=		len(a__) - 1


      def 					__snake_case      (		self   ,				a__):



             """simple docstring"""





             assert 0 <= t <= 1, "Time t must be between 0 and 1."
             _lowerCamelCase				:  list[float]						=		[]
             for i in range(len(self.list_of_points)):
                    # basis function for each i
                    output_values.append(
                        comb(self.degree   ,				a__) * ((1 - t) ** (self.degree - i)) * (t**i))
             # the basis must sum up to 1 for it to produce a valid Bezier curve.
             assert round(sum(a__)   ,				5) == 1
             return output_values


      def 					__snake_case      (		self   ,				a__):



             """simple docstring"""





             assert 0 <= t <= 1, "Time t must be between 0 and 1."

             _lowerCamelCase				:  Any						=		self.basis_function(a__)
             _lowerCamelCase				:  List[Any]						=		0.0
             _lowerCamelCase				:  List[Any]						=		0.0
             for i in range(len(self.list_of_points)):
                    # For all points, sum up the product of i-th basis function and i-th point.
                    x += basis_function[i] * self.list_of_points[i][0]
                    y += basis_function[i] * self.list_of_points[i][1]
             return (x, y)



      def 					__snake_case      (		self   ,				a__ = 0.01):



             """simple docstring"""





             from matplotlib import pyplot as plt  # type: ignore

             _lowerCamelCase				:  list[float]						=		[]  # x coordinates of points to plot
             _lowerCamelCase				:  list[float]						=		[]  # y coordinates of points to plot

             _lowerCamelCase				:  List[Any]						=		0.0
             while t <= 1:
                    _lowerCamelCase				:  Tuple						=		self.bezier_curve_function(a__)
                    to_plot_x.append(value[0])
                    to_plot_y.append(value[1])
                    t += step_size

             _lowerCamelCase				:  List[Any]						=		[i[0] for i in self.list_of_points]
             _lowerCamelCase				:  Union[str, Any]						=		[i[1] for i in self.list_of_points]

             plt.plot(
                 a__   ,				a__   ,				color='''blue'''   ,				label='''Curve of Degree ''' + str(self.degree)   ,				)
             plt.scatter(a__   ,				a__   ,				color='''red'''   ,				label='''Control Points''')
             plt.legend()
             plt.show()


if __name__ == "__main__":
       import doctest

       doctest.testmod()

       BezierCurve([(1, 2), (3, 5)]).plot_curve()  # degree 1
       BezierCurve([(0, 0), (5, 5), (5, 0)]).plot_curve()  # degree 2
       BezierCurve([(0, 0), (5, 5), (5, 0), (2.5, -2.5)]).plot_curve()  # degree 3

