






from __future__ import annotations

UpperCamelCase    							=      tuple[int, int, int]
UpperCamelCase    							=      tuple[str, str, str]


# used alphabet --------------------------
# from string.ascii_uppercase
UpperCamelCase    							=      'ABCDEFGHIJKLMNOPQRSTUVWXYZ'

# -------------------------- default selection --------------------------
# rotors --------------------------
UpperCamelCase    							=      'EGZWVONAHDCLFQMSIPJBYUKXTR'
UpperCamelCase    							=      'FOBHMDKEXQNRAULPGSJVTYICZW'
UpperCamelCase    							=      'ZJXESIUQLHAVRMDOYGTNFWPBKC'
# reflector --------------------------
UpperCamelCase    							=      {
    'A': 'N',
    'N': 'A',
    'B': 'O',
    'O': 'B',
    'C': 'P',
    'P': 'C',
    'D': 'Q',
    'Q': 'D',
    'E': 'R',
    'R': 'E',
    'F': 'S',
    'S': 'F',
    'G': 'T',
    'T': 'G',
    'H': 'U',
    'U': 'H',
    'I': 'V',
    'V': 'I',
    'J': 'W',
    'W': 'J',
    'K': 'X',
    'X': 'K',
    'L': 'Y',
    'Y': 'L',
    'M': 'Z',
    'Z': 'M',
}

# -------------------------- extra rotors --------------------------
UpperCamelCase    							=      'RMDJXFUWGISLHVTCQNKYPBEZOA'
UpperCamelCase    							=      'SGLCPQWZHKXAREONTFBVIYJUDM'
UpperCamelCase    							=      'HVSICLTYKQUBXDWAJZOMFGPREN'
UpperCamelCase    							=      'RZWQHFMVDBKICJLNTUXAGYPSOE'
UpperCamelCase    							=      'LFKIJODBEGAMQPXVUHYSTCZRWN'
UpperCamelCase    							=      'KOAEGVDHXPQZMLFTYWJNBRCIUS'


def 				__lowerCamelCase     (							__lowerCAmelCase							:					RotorPositionT					,							__lowerCAmelCase							:					RotorSelectionT					,							__lowerCAmelCase							:					str							)     ->  tuple[RotorPositionT, RotorSelectionT, dict[str, str]]:
   # Checks if there are 3 unique rotors

   if (unique_rotsel := len(set(__lowerCAmelCase							)							)) < 3:
      __UpperCamelCase	:			int					=					f'Please use 3 unique rotors (not {unique_rotsel})'
      raise Exception(__lowerCAmelCase							)

   # Checks if rotor positions are valid
   __UpperCamelCase	,     __UpperCamelCase	,     __UpperCamelCase	:			int					=					rotpos
   if not 0 < rotorposa <= len(__lowerCAmelCase							):
      __UpperCamelCase	:			Dict					=					f'First rotor position is not within range of 1..26 ({rotorposa}'
      raise ValueError(__lowerCAmelCase							)
   if not 0 < rotorposa <= len(__lowerCAmelCase							):
      __UpperCamelCase	:			Any					=					f'Second rotor position is not within range of 1..26 ({rotorposa})'
      raise ValueError(__lowerCAmelCase							)
   if not 0 < rotorposa <= len(__lowerCAmelCase							):
      __UpperCamelCase	:			List[str]					=					f'Third rotor position is not within range of 1..26 ({rotorposa})'
      raise ValueError(__lowerCAmelCase							)

   # Validates string and returns dict
   __UpperCamelCase	:			Any					=					_plugboard(__lowerCAmelCase							)

   return rotpos, rotsel, pbdict


def 				__lowerCamelCase     (							__lowerCAmelCase							:					str							)     ->  dict[str, str]:

   # tests the input string if it
   # a) is type string
   # b) has even length (so pairs can be made)
   if not isinstance(__lowerCAmelCase					,							__lowerCAmelCase							):
      __UpperCamelCase	:			Optional[Any]					=					f'Plugboard setting isn\'t type string ({type(__lowerCAmelCase							)})'
      raise TypeError(__lowerCAmelCase							)
   elif len(__lowerCAmelCase							) % 2 != 0:
      __UpperCamelCase	:			Any					=					f'Odd number of symbols ({len(__lowerCAmelCase							)})'
      raise Exception(__lowerCAmelCase							)
   elif pbstring == "":
      return {}

   pbstring.replace(""" """					,							""""""							)

   # Checks if all characters are unique
   __UpperCamelCase	:			int					=					set()
   for i in pbstring:
      if i not in abc:
         __UpperCamelCase	:			int					=					f'\'{i}\' not in list of symbols'
         raise Exception(__lowerCAmelCase							)
      elif i in tmppbl:
         __UpperCamelCase	:			str					=					f'Duplicate symbol ({i})'
         raise Exception(__lowerCAmelCase							)
      else:
         tmppbl.add(__lowerCAmelCase							)
   del tmppbl

   # Created the dictionary
   __UpperCamelCase	:			Union[str, Any]					=					{}
   for j in range(0					,							len(__lowerCAmelCase							) - 1					,							2							):
      __UpperCamelCase	:			Optional[int]					=					pbstring[j + 1]
      __UpperCamelCase	:			Dict					=					pbstring[j]

   return pb


def 				__lowerCamelCase     (							__lowerCAmelCase							:					str					,							__lowerCAmelCase							:					RotorPositionT					,							__lowerCAmelCase							:					RotorSelectionT = (rotora, rotora, rotora)					,							__lowerCAmelCase							:					str = ""					,							)     ->  str:
   __UpperCamelCase	:			Dict					=					text.upper()
   __UpperCamelCase	,     __UpperCamelCase	,     __UpperCamelCase	:			Optional[int]					=					_validator(
       __lowerCAmelCase					,							__lowerCAmelCase					,							plugb.upper()							)

   __UpperCamelCase	,     __UpperCamelCase	,     __UpperCamelCase	:			Optional[Any]					=					rotor_position
   __UpperCamelCase	,     __UpperCamelCase	,     __UpperCamelCase	:			List[Any]					=					rotor_selection
   rotorposa -= 1
   rotorposa -= 1
   rotorposa -= 1

   __UpperCamelCase	:			int					=					[]

   # encryption/decryption process --------------------------
   for symbol in text:
      if symbol in abc:
         # 1st plugboard --------------------------
         if symbol in plugboard:
            __UpperCamelCase	:			str					=					plugboard[symbol]

         # rotor ra --------------------------
         __UpperCamelCase	:			List[str]					=					abc.index(__lowerCAmelCase							) + rotorposa
         __UpperCamelCase	:			List[str]					=					rotora[index % len(__lowerCAmelCase							)]

         # rotor rb --------------------------
         __UpperCamelCase	:			Dict					=					abc.index(__lowerCAmelCase							) + rotorposa
         __UpperCamelCase	:			Optional[Any]					=					rotora[index % len(__lowerCAmelCase							)]

         # rotor rc --------------------------
         __UpperCamelCase	:			List[Any]					=					abc.index(__lowerCAmelCase							) + rotorposa
         __UpperCamelCase	:			Dict					=					rotora[index % len(__lowerCAmelCase							)]

         # reflector --------------------------
         # this is the reason you don't need another machine to decipher

         __UpperCamelCase	:			Any					=					reflector[symbol]

         # 2nd rotors
         __UpperCamelCase	:			List[str]					=					abc[rotora.index(__lowerCAmelCase							) - rotorposa]
         __UpperCamelCase	:			Union[str, Any]					=					abc[rotora.index(__lowerCAmelCase							) - rotorposa]
         __UpperCamelCase	:			Optional[Any]					=					abc[rotora.index(__lowerCAmelCase							) - rotorposa]

         # 2nd plugboard
         if symbol in plugboard:
            __UpperCamelCase	:			Any					=					plugboard[symbol]

         # moves/resets rotor positions
         rotorposa += 1
         if rotorposa >= len(__lowerCAmelCase							):
            __UpperCamelCase	:			List[str]					=					0
            rotorposa += 1
         if rotorposa >= len(__lowerCAmelCase							):
            __UpperCamelCase	:			Tuple					=					0
            rotorposa += 1
         if rotorposa >= len(__lowerCAmelCase							):
            __UpperCamelCase	:			Optional[Any]					=					0

        # else:
        #    pass
        #    Error could be also raised
        #    raise ValueError(
        #       'Invalid symbol('+repr(symbol)+')')
      result.append(__lowerCAmelCase							)

   return "".join(__lowerCAmelCase							)


if __name__ == "__main__":
       UpperCamelCase    							=      'This is my Python script that emulates the Enigma machine from WWII.'
       UpperCamelCase    							=      (1, 1, 1)
       UpperCamelCase    							=      'pictures'
       UpperCamelCase    							=      (rotora, rotora, rotora)
       UpperCamelCase    							=      enigma(message, rotor_pos, rotor_sel, pb)

       print('Encrypted message:', en)
       print('Decrypted message:', enigma(en, rotor_pos, rotor_sel, pb))











from manim import *







class 		_A						( UpperCAmelCase_ ):

  def    a					(    self						:	Dict			):
     """simple docstring"""

     __UpperCamelCase	:			Tuple					=					Rectangle(height=0.5   ,				width=0.5			)
     __UpperCamelCase	:			Tuple					=					Rectangle(height=0.46   ,				width=0.46			).set_stroke(width=0			)

     __UpperCamelCase	:			Optional[Any]					=					Rectangle(height=0.25   ,				width=0.25			)

     __UpperCamelCase	:			Any					=					[mem.copy() for i in range(6			)]
     __UpperCamelCase	:			str					=					[mem.copy() for i in range(6			)]
     __UpperCamelCase	:			int					=					VGroup(*lowerCamelCase__			).arrange(lowerCamelCase__   ,				buff=0			)
     __UpperCamelCase	:			Optional[int]					=					VGroup(*lowerCamelCase__			).arrange(lowerCamelCase__   ,				buff=0			)
     __UpperCamelCase	:			Dict					=					VGroup(lowerCamelCase__   ,				lowerCamelCase__			).arrange(lowerCamelCase__   ,				buff=0			)
     __UpperCamelCase	:			List[Any]					=					Text("""CPU"""   ,				font_size=24			)
     __UpperCamelCase	:			Any					=					Group(lowerCamelCase__   ,				lowerCamelCase__			).arrange(lowerCamelCase__   ,				buff=0.5   ,				aligned_edge=lowerCamelCase__			)
     cpu.move_to([-2.5, -0.5, 0]			)
     self.add(lowerCamelCase__			)

     __UpperCamelCase	:			Tuple					=					[mem.copy() for i in range(4			)]
     __UpperCamelCase	:			Optional[Any]					=					VGroup(*lowerCamelCase__			).arrange(lowerCamelCase__   ,				buff=0			)
     __UpperCamelCase	:			Optional[Any]					=					Text("""GPU"""   ,				font_size=24			)
     __UpperCamelCase	:			Union[str, Any]					=					Group(lowerCamelCase__   ,				lowerCamelCase__			).arrange(lowerCamelCase__   ,				buff=0.5   ,				aligned_edge=lowerCamelCase__			)
     gpu.move_to([-1, -1, 0]			)
     self.add(lowerCamelCase__			)

     __UpperCamelCase	:			Dict					=					[mem.copy() for i in range(6			)]
     __UpperCamelCase	:			Tuple					=					VGroup(*lowerCamelCase__			).arrange(lowerCamelCase__   ,				buff=0			)

     __UpperCamelCase	:			Tuple					=					Text("""Model"""   ,				font_size=24			)
     __UpperCamelCase	:			List[str]					=					Group(lowerCamelCase__   ,				lowerCamelCase__			).arrange(lowerCamelCase__   ,				buff=0.5   ,				aligned_edge=lowerCamelCase__			)
     model.move_to([3, -1.0, 0]			)
     self.add(lowerCamelCase__			)

     __UpperCamelCase	:			Tuple					=					[]
     __UpperCamelCase	:			str					=					[]

     for i, rect in enumerate(lowerCamelCase__			):
        __UpperCamelCase	:			Optional[Any]					=					fill.copy().set_fill(lowerCamelCase__   ,				opacity=0.8			)
        target.move_to(lowerCamelCase__			)
        model_arr.append(lowerCamelCase__			)

        __UpperCamelCase	:			Tuple					=					Rectangle(height=0.46   ,				width=0.46			).set_stroke(width=0.0			).set_fill(lowerCamelCase__   ,				opacity=0.8			)
        cpu_target.move_to(cpu_left_col_base[i]			)
        model_cpu_arr.append(lowerCamelCase__			)

     self.add(*lowerCamelCase__   ,				*lowerCamelCase__			)

     __UpperCamelCase	:			Union[str, Any]					=					[meta_mem.copy() for i in range(6			)]
     __UpperCamelCase	:			Any					=					[meta_mem.copy() for i in range(6			)]
     __UpperCamelCase	:			int					=					VGroup(*lowerCamelCase__			).arrange(lowerCamelCase__   ,				buff=0			)
     __UpperCamelCase	:			Union[str, Any]					=					VGroup(*lowerCamelCase__			).arrange(lowerCamelCase__   ,				buff=0			)
     __UpperCamelCase	:			str					=					VGroup(lowerCamelCase__   ,				lowerCamelCase__			).arrange(lowerCamelCase__   ,				buff=0			)
     __UpperCamelCase	:			Optional[Any]					=					Text("""Disk"""   ,				font_size=24			)
     __UpperCamelCase	:			Optional[Any]					=					Group(lowerCamelCase__   ,				lowerCamelCase__			).arrange(lowerCamelCase__   ,				buff=0.5   ,				aligned_edge=lowerCamelCase__			)
     disk.move_to([-4, -1.25, 0]			)
     self.add(lowerCamelCase__   ,				lowerCamelCase__			)

     __UpperCamelCase	:			Union[str, Any]					=					Square(side_length=2.2			)
     key.move_to([-5, 2, 0]			)

     __UpperCamelCase	:			Optional[Any]					=					MarkupText(
         f'<b>Key:</b>\n\n<span fgcolor=\'{YELLOW}\'>●</span> Empty Model'   ,				font_size=18   ,				)

     key_text.move_to([-5, 2.4, 0]			)

     self.add(lowerCamelCase__   ,				lowerCamelCase__			)

     __UpperCamelCase	:			Optional[int]					=					MarkupText(
         f'<span fgcolor=\'{BLUE}\'>●</span> Checkpoint'   ,				font_size=18   ,				)

     blue_text.next_to(lowerCamelCase__   ,				DOWN * 2.4   ,				aligned_edge=key_text.get_left()			)
     self.add(lowerCamelCase__			)

     __UpperCamelCase	:			Any					=					MarkupText(
         f'Now watch as an input is passed through the model\nand how the memory is utilized and handled.'   ,				font_size=24   ,				)
     step_a.move_to([2, 2, 0]			)

     self.play(Write(lowerCamelCase__			)			)

     __UpperCamelCase	:			List[str]					=					Square(0.3			)
     input.set_fill(lowerCamelCase__   ,				opacity=1.0			)
     input.set_stroke(width=0.0			)
     input.next_to(model_base[0]   ,				lowerCamelCase__   ,				buff=0.5			)

     self.play(Write(lowerCamelCase__			)			)

     input.generate_target()
     input.target.next_to(model_arr[0]   ,				direction=lowerCamelCase__   ,				buff=0.02			)
     self.play(MoveToTarget(lowerCamelCase__			)			)

     self.play(FadeOut(lowerCamelCase__			)			)

     __UpperCamelCase	:			Dict					=					Arrow(start=lowerCamelCase__   ,				end=lowerCamelCase__   ,				color=lowerCamelCase__   ,				buff=0.5			)
     a.next_to(model_arr[0].get_left()   ,				lowerCamelCase__   ,				buff=0.2			)

     model_cpu_arr[0].generate_target()
     model_cpu_arr[0].target.move_to(gpu_rect[0]			)

     __UpperCamelCase	:			int					=					MarkupText(
         f'As the input reaches a layer, the hook triggers\nand weights are moved from the CPU\nto the GPU and back.'   ,				font_size=24   ,				)
     step_a.move_to([2, 2, 0]			)

     self.play(Write(lowerCamelCase__   ,				run_time=3			)			)

     __UpperCamelCase	:			Dict					=					{"""run_time""": 1, """fade_in""": True, """fade_out""": True, """buff""": 0.02}

     self.play(
         Write(lowerCamelCase__			)   ,				Circumscribe(model_arr[0]   ,				color=lowerCamelCase__   ,				**lowerCamelCase__			)   ,				Circumscribe(model_cpu_arr[0]   ,				color=lowerCamelCase__   ,				**lowerCamelCase__			)   ,				Circumscribe(gpu_rect[0]   ,				color=lowerCamelCase__   ,				**lowerCamelCase__			)   ,				)
     self.play(MoveToTarget(model_cpu_arr[0]			)			)

     __UpperCamelCase	:			int					=					a.copy()
     for i in range(6			):
        a_c.next_to(model_arr[i].get_right() + 0.02   ,				lowerCamelCase__   ,				buff=0.2			)

        input.generate_target()
        input.target.move_to(model_arr[i].get_right() + 0.02			)

        __UpperCamelCase	:			Tuple					=					AnimationGroup(
            FadeOut(lowerCamelCase__   ,				run_time=0.5			)   ,				MoveToTarget(lowerCamelCase__   ,				run_time=0.5			)   ,				FadeIn(lowerCamelCase__   ,				run_time=0.5			)   ,				lag_ratio=0.2			)

        self.play(lowerCamelCase__			)

        model_cpu_arr[i].generate_target()
        model_cpu_arr[i].target.move_to(cpu_left_col_base[i]			)

        if i < 5:
           model_cpu_arr[i + 1].generate_target()
           model_cpu_arr[i + 1].target.move_to(gpu_rect[0]			)
           if i >= 1:
              __UpperCamelCase	:			Any					=					0.7

           self.play(
               Circumscribe(model_arr[i]   ,				**lowerCamelCase__			)   ,				Circumscribe(cpu_left_col_base[i]   ,				**lowerCamelCase__			)   ,				Circumscribe(cpu_left_col_base[i + 1]   ,				color=lowerCamelCase__   ,				**lowerCamelCase__			)   ,				Circumscribe(gpu_rect[0]   ,				color=lowerCamelCase__   ,				**lowerCamelCase__			)   ,				Circumscribe(model_arr[i + 1]   ,				color=lowerCamelCase__   ,				**lowerCamelCase__			)   ,				)
           if i < 1:
              self.play(
                  MoveToTarget(model_cpu_arr[i]			)   ,				MoveToTarget(model_cpu_arr[i + 1]			)   ,				)
           else:
              self.play(
                  MoveToTarget(model_cpu_arr[i]   ,				run_time=0.7			)   ,				MoveToTarget(model_cpu_arr[i + 1]   ,				run_time=0.7			)   ,				)
        else:
           model_cpu_arr[i].generate_target()
           model_cpu_arr[i].target.move_to(cpu_left_col_base[-1]			)
           input.generate_target()
           input.target.next_to(model_arr[-1].get_right()   ,				RIGHT + 0.02   ,				buff=0.2			)

           self.play(
               Circumscribe(model_arr[-1]   ,				color=lowerCamelCase__   ,				**lowerCamelCase__			)   ,				Circumscribe(cpu_left_col_base[-1]   ,				color=lowerCamelCase__   ,				**lowerCamelCase__			)   ,				Circumscribe(gpu_rect[0]   ,				color=lowerCamelCase__   ,				**lowerCamelCase__			)   ,				)

           self.play(MoveToTarget(model_cpu_arr[i]			)			)

        __UpperCamelCase	:			str					=					a_c
        __UpperCamelCase	:			List[Any]					=					a_c.copy()

     input.generate_target()
     input.target.next_to(model_base[-1]   ,				RIGHT + 0.02   ,				buff=0.5			)
     self.play(
         FadeOut(lowerCamelCase__			)   ,				FadeOut(lowerCamelCase__   ,				run_time=0.5			)   ,				)

     __UpperCamelCase	:			List[str]					=					MarkupText(f'Inference on a model too large for GPU memory\nis successfully completed.'   ,				font_size=24			)
     step_a.move_to([2, 2, 0]			)

     self.play(Write(lowerCamelCase__   ,				run_time=3			)   ,				MoveToTarget(lowerCamelCase__			)			)

     self.wait()



