Skip to content

Commit 814d3ce

Browse files
authored
Baconian cipher with any 2 symbols
edited encode and decode functions to support any 2 symbols
1 parent e2a78d4 commit 814d3ce

File tree

1 file changed

+53
-48
lines changed

1 file changed

+53
-48
lines changed

ciphers/baconian_cipher.py

Lines changed: 53 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,3 @@
1-
"""
2-
Program to encode and decode Baconian or Bacon's Cipher
3-
Wikipedia reference : https://en.wikipedia.org/wiki/Bacon%27s_cipher
4-
"""
5-
61
encode_dict = {
72
"a": "AAAAA",
83
"b": "AAAAB",
@@ -33,57 +28,67 @@
3328
" ": " ",
3429
}
3530

36-
3731
decode_dict = {value: key for key, value in encode_dict.items()}
3832

39-
40-
def encode(word: str) -> str:
41-
"""
42-
Encodes to Baconian cipher
43-
44-
>>> encode("hello")
45-
'AABBBAABAAABABAABABAABBAB'
46-
>>> encode("hello world")
47-
'AABBBAABAAABABAABABAABBAB BABAAABBABBAAAAABABAAAABB'
48-
>>> encode("hello world!")
49-
Traceback (most recent call last):
50-
...
51-
Exception: encode() accepts only letters of the alphabet and spaces
52-
"""
33+
def encode(word: str, symbols=("A","B")) -> str:
34+
a_sym, b_sym = symbols
5335
encoded = ""
5436
for letter in word.lower():
5537
if letter.isalpha() or letter == " ":
56-
encoded += encode_dict[letter]
38+
# replace A with a_symbol, B with b_symbol
39+
bacon = encode_dict[letter]
40+
bacon_custom = bacon.replace("A", a_sym).replace("B", b_sym)
41+
encoded += bacon_custom
5742
else:
5843
raise Exception("encode() accepts only letters of the alphabet and spaces")
5944
return encoded
6045

61-
62-
def decode(coded: str) -> str:
63-
"""
64-
Decodes from Baconian cipher
65-
66-
>>> decode("AABBBAABAAABABAABABAABBAB BABAAABBABBAAAAABABAAAABB")
67-
'hello world'
68-
>>> decode("AABBBAABAAABABAABABAABBAB")
69-
'hello'
70-
>>> decode("AABBBAABAAABABAABABAABBAB BABAAABBABBAAAAABABAAAABB!")
71-
Traceback (most recent call last):
72-
...
73-
Exception: decode() accepts only 'A', 'B' and spaces
74-
"""
75-
if set(coded) - {"A", "B", " "} != set():
76-
raise Exception("decode() accepts only 'A', 'B' and spaces")
77-
decoded = ""
78-
for word in coded.split():
79-
while len(word) != 0:
80-
decoded += decode_dict[word[:5]]
81-
word = word[5:]
82-
decoded += " "
83-
return decoded.strip()
84-
46+
def decode(coded: str, symbols=("A","B")) -> str:
47+
sym1, sym2 = symbols
48+
# check if we need to remap
49+
unique_symbols = set(coded.replace(" ", ""))
50+
if unique_symbols - {sym1, sym2} != set():
51+
raise Exception(f"decode() accepts only symbols {sym1} and {sym2} and spaces")
52+
53+
# Try both mappings: symbol1 maps to A, symbol2 maps to B or symbol1 maps to B, symbol2 maps A
54+
candidates = []
55+
for mapping in [(sym1, sym2), (sym2, sym1)]:
56+
s1, s2 = mapping
57+
# convert coded symbols to standard A/B
58+
standard = coded.replace(s1, "A").replace(s2, "B")
59+
try:
60+
decoded = ""
61+
for word in standard.split():
62+
while len(word) != 0:
63+
chunk = word[:5]
64+
if chunk not in decode_dict:
65+
raise ValueError
66+
decoded += decode_dict[chunk]
67+
word = word[5:]
68+
decoded += " "
69+
candidates.append(decoded.strip())
70+
except ValueError:
71+
candidates.append(None)
72+
73+
# return the valid decoding
74+
for candidate in candidates:
75+
if candidate is not None:
76+
return candidate
77+
raise Exception("No valid decoding found with the given symbols")
78+
def detect_unique_char (cipher):
79+
#CD CD DC returns C, D
80+
cipher = cipher.replace(" ","")
81+
unique_chars = set(cipher)
82+
unique_letters = [char for char in unique_chars if char.isalpha()]
83+
if len(unique_letters) != 2:
84+
raise Exception("Cipher must contain exactly two unique alphabetic characters for encoding.")
85+
else:
86+
list_unique = list(unique_letters)
87+
return list_unique[0], list_unique[1]
8588

8689
if __name__ == "__main__":
87-
from doctest import testmod
88-
89-
testmod()
90+
# Example usage
91+
cipher_text = "FEEFE EEFFF EEFEE EFFFF FEEFF EFEEE EEEFE EFEEF EEEEF FEEEE EFFEF FEFEE EFFEE EEFEF EFFEF FEFEF"
92+
symbol_1, symbol_2 = detect_unique_char(cipher_text)
93+
decoded = decode(cipher_text, symbols=(symbol_1, symbol_2))
94+
print(decoded) # prints the quick brown fox

0 commit comments

Comments
 (0)