Coverage for kryptic_cypher/cypher/ceasar_word.py: 97%
36 statements
« prev ^ index » next coverage.py v7.14.2, created at 2026-06-20 18:52 +0000
« prev ^ index » next coverage.py v7.14.2, created at 2026-06-20 18:52 +0000
1import string
3from kryptic_cypher.cypher.base import CypherResult, CypherWithKey, ValidationResult
6class Direction:
7 ENCODE = "encode"
8 DECODE = "decode"
11def transform_word_into_alphabet(word: str, direction: Direction):
12 unique_letters_in_order = []
13 alphabet = string.ascii_lowercase
14 for letter in word.lower():
15 if letter not in unique_letters_in_order and letter in string.ascii_lowercase:
16 unique_letters_in_order.append(letter)
17 alphabet = alphabet.replace(letter, "")
19 # Shift the letters to the front.
20 alphabet = "".join(unique_letters_in_order) + alphabet
21 translation = {}
23 if direction == Direction.ENCODE:
24 translation.update(zip(string.ascii_lowercase, alphabet))
25 translation.update(zip(string.ascii_uppercase, alphabet.upper()))
27 elif direction == Direction.DECODE:
28 translation.update(zip(alphabet, string.ascii_lowercase))
29 translation.update(zip(alphabet.upper(), string.ascii_uppercase))
30 else:
31 raise ValueError(f"Invalid direction: {direction}")
33 return translation
36class CaesarWordCypher(CypherWithKey):
37 """
38 The caesar word cypher might actually be a misnomer because it isn't really the same as a caesar cypher. in fact, i would argue it would have nothign to do with it.
39 it involves using a word and taking out the alphabetical order of the letters from that and leaving the other letters of the alphabet that are unused the same.
42 lets say our key is: Goat
43 so we would make a new Alphabet starting with the Characters in sequence
44 G O A T
45 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
46 then we check off which ones we took on the actually alphabet line
47 G O A T
48 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
49 x x x x
50 and we fill in the blanks with the rest of the remaining alphabet in alphabetical order like this.
52 G O A T B C D E F H I J K L M N P Q R S U V W X Y Z
53 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
54 and now you have the the alpahbet to use to change your message
56 So lets say your message is: alex this is cool.
57 we look at the regular alphabet for a then we know that should become the letter above it i.e. G
58 so
59 G
60 and then keep going with it
61 GJBX SEFR FR AMMN
62 and to decrypt you recreate the alphabet again
63 and work in reverse i.e. read the top to find the letter on the bottom that matches
64 so we notice our G becomes an A.
65 and just repeat through the cyphered text
66 ALEX THIS IS COOL
67 then blammo that would be the decrypted text.
68 """
70 @classmethod
71 def validate_key(cls, key: str) -> ValidationResult:
72 if not key:
73 return ValidationResult.fail("Key cannot be empty.")
75 if any(c not in string.ascii_letters for c in key):
76 return ValidationResult.fail("Key must be only letters.")
78 return ValidationResult.ok()
80 def encode(self, text: str, key: str) -> CypherResult:
81 translate = transform_word_into_alphabet(key, Direction.ENCODE)
82 return CypherResult.ok(text, "".join(translate.get(c, c) for c in text))
84 def decode(self, text: str, key: str) -> CypherResult:
85 translate = transform_word_into_alphabet(key, Direction.DECODE)
86 return CypherResult.ok(text, "".join(translate.get(c, c) for c in text))