package com.thealgorithms.ciphers; import java.util.HashMap; import java.util.Map; /** * The Baconian Cipher is a substitution cipher where each letter is represented * by a group of five binary digits (A's and B's). It can also be used to hide * messages within other texts, making it a simple form of steganography. * https://en.wikipedia.org/wiki/Bacon%27s_cipher * * @author Bennybebo */ public class BaconianCipher { private static final Map BACONIAN_MAP = new HashMap<>(); private static final Map REVERSE_BACONIAN_MAP = new HashMap<>(); static { // Initialize the Baconian cipher mappings String[] baconianAlphabet = {"AAAAA", "AAAAB", "AAABA", "AAABB", "AABAA", "AABAB", "AABBA", "AABBB", "ABAAA", "ABAAB", "ABABA", "ABABB", "ABBAA", "ABBAB", "ABBBA", "ABBBB", "BAAAA", "BAAAB", "BAABA", "BAABB", "BABAA", "BABAB", "BABBA", "BABBB", "BBAAA", "BBAAB"}; char letter = 'A'; for (String code : baconianAlphabet) { BACONIAN_MAP.put(letter, code); REVERSE_BACONIAN_MAP.put(code, letter); letter++; } // Handle I/J as the same letter BACONIAN_MAP.put('I', BACONIAN_MAP.get('J')); REVERSE_BACONIAN_MAP.put(BACONIAN_MAP.get('I'), 'I'); } /** * Encrypts the given plaintext using the Baconian cipher. * * @param plaintext The plaintext message to encrypt. * @return The ciphertext as a binary (A/B) sequence. */ public String encrypt(String plaintext) { StringBuilder ciphertext = new StringBuilder(); plaintext = plaintext.toUpperCase().replaceAll("[^A-Z]", ""); // Remove non-letter characters for (char letter : plaintext.toCharArray()) { ciphertext.append(BACONIAN_MAP.get(letter)); } return ciphertext.toString(); } /** * Decrypts the given ciphertext encoded in binary (A/B) format using the Baconian cipher. * * @param ciphertext The ciphertext to decrypt. * @return The decrypted plaintext message. */ public String decrypt(String ciphertext) { StringBuilder plaintext = new StringBuilder(); for (int i = 0; i < ciphertext.length(); i += 5) { String code = ciphertext.substring(i, i + 5); if (REVERSE_BACONIAN_MAP.containsKey(code)) { plaintext.append(REVERSE_BACONIAN_MAP.get(code)); } else { throw new IllegalArgumentException("Invalid Baconian code: " + code); } } return plaintext.toString(); } }