Coverage for kryptic_cypher/cypher/ceasar.py: 94%

53 statements  

« prev     ^ index     » next       coverage.py v7.14.2, created at 2026-06-20 18:52 +0000

1"""Caesar cipher implementation for encrypting and decrypting text with a numeric key.""" 

2 

3from .base import CypherResult, CypherWithKey, ValidationResult 

4 

5UPPER_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 

6LOWER_ALPHABET = "abcdefghijklmnopqrstuvwxyz" 

7 

8 

9def create_alpahbet(key: int): 

10 translation_dictionary = {} 

11 for cypher_index, original_index in zip( 

12 range(key, key + len(UPPER_ALPHABET)), 

13 range(len(UPPER_ALPHABET)), 

14 ): 

15 cypher_index_character = cypher_index % len(UPPER_ALPHABET) 

16 translation_dictionary[UPPER_ALPHABET[original_index]] = UPPER_ALPHABET[ 

17 cypher_index_character 

18 ] 

19 

20 for cypher_index, original_index in zip( 

21 range(key, key + len(LOWER_ALPHABET)), 

22 range(len(LOWER_ALPHABET)), 

23 ): 

24 cypher_index_character = cypher_index % len(LOWER_ALPHABET) 

25 translation_dictionary[LOWER_ALPHABET[original_index]] = LOWER_ALPHABET[ 

26 cypher_index_character 

27 ] 

28 

29 return translation_dictionary 

30 

31 

32def create_reverse_alphabet(key: int): 

33 upper_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 

34 lower_alphabet = "abcdefghijklmnopqrstuvwxyz" 

35 translation_dictionary = {} 

36 for cypher_index, original_index in zip( 

37 range(key, key + len(upper_alphabet)), 

38 range(len(upper_alphabet)), 

39 ): 

40 cypher_index_character = cypher_index % len(upper_alphabet) 

41 translation_dictionary[upper_alphabet[cypher_index_character]] = upper_alphabet[ 

42 original_index 

43 ] 

44 

45 for cypher_index, original_index in zip( 

46 range(key, key + len(lower_alphabet)), 

47 range(len(lower_alphabet)), 

48 ): 

49 cypher_index_character = cypher_index % len(lower_alphabet) 

50 translation_dictionary[lower_alphabet[cypher_index_character]] = lower_alphabet[ 

51 original_index 

52 ] 

53 

54 return translation_dictionary 

55 

56 

57class Ceasar(CypherWithKey): 

58 """ 

59 The Caeser Cypher uses each letter and shifts it the given number of times in the alphabet. 

60 

61 EX: 

62 

63 Given Phrase: Caesar 

64 Key: 2 

65 

66 To encrypt the given phrase we first get the full alphabet and shift each letter by the key. 

67 

68 ABCDEFGHIJKLMNOPQRSTUVWXYZ 

69 CDEFGHIJKLMNOPQRSTUVWXYZAB 

70 

71 After shifting the alphabet we can then input our new letters for our phrase. 

72 

73 Encrypted: Ecguct 

74 

75 To decrypt just do the opposite to the alphabet with the key shifting. 

76 

77 ABCDEFGHIJKLMNOPQRSTUVWXYZ 

78 YZABCDEFGHIJKLMNOPQRSTUVWX 

79 

80 Again we just input the shifted text into the decoded text. 

81 

82 Decoded: Caesar 

83 """ 

84 

85 @classmethod 

86 def validate_key(cls, key): 

87 if not key.isnumeric(): 

88 return ValidationResult.fail("Key must be numeric") 

89 return ValidationResult.ok() 

90 

91 def encode(self, text: str, key: str) -> CypherResult: 

92 try: 

93 true_key = int(key) 

94 except ValueError: 

95 return CypherResult.fail(text, "Key must be numeric") 

96 

97 if true_key < 0: 

98 return CypherResult.fail(text, "Key must be positive") 

99 

100 alphabet = create_alpahbet(true_key) 

101 encoded_text = "" 

102 for letter in text: 

103 # If the letter is a space then just add it 

104 encoded_text += alphabet.get(letter, letter) 

105 return CypherResult.ok(text, encoded_text) 

106 

107 def decode(self, text: str, key: str) -> CypherResult: 

108 try: 

109 true_key = int(key) 

110 except ValueError: 

111 return CypherResult.fail(text, "Key must be numeric") 

112 

113 if true_key < 0: 

114 return CypherResult.fail(text, "Key must be positive") 

115 

116 alphabet = create_reverse_alphabet(true_key) 

117 decoded_text = "" 

118 for letter in text: 

119 # If the letter is a space then just add it 

120 decoded_text += alphabet.get(letter, letter) 

121 return CypherResult.ok(text, decoded_text)