My "guess" function is outputting gibberish when replacing the most frequent bytes by the most frequent characters
16:23 23 Nov 2025

I have two files: a text file that will be used to count the most frequent characters, and a binary file that will be used to count the most frequent bytes.

I need to write a function that replaces the most frequent characters with the most frequent bytes.

Here's the output I'm getting after testing the function:

gibberish output

However, the output needs to have 80% of the characters correctly mapped.

What am I doing wrong? I tried increasing the number of pairs from 17 to 100, but the output is still gibberish.

Here's the content of the text file:

Exploring the breathtaking landscapes of the English countryside is truly a remarkable experience.

From the rolling hills covered in vibrant green to the charming little villages nestled along meandering rivers, there is an undeniable sense of tranquility and beauty.

The picturesque scenery, combined with the rich history and culture, creates a perfect blend of old-world charm and modern-day allure.

Whether you choose to stroll through the enchanting gardens, visit historic castles, or indulge in traditional afternoon tea, there is something for everyone to enjoy in this captivating destination.

Here's the script:

def frq_txt(text: str) -> List[Tuple[str, int]]:
    """
    Finds how often each character appears in a plaintext string.
    The function returns a list of (character, count) pairs ordered
    from the most frequent to the least frequent character.
    """
    counts = Counter(text)

    # Convert the Counter into (char, count) pairs and sort them.
    # The lambda picks item[1] (the count) so sorting is based on frequency.
    # reverse=True ensures the most frequent characters come first.
    freq_list = sorted(counts.items(), key=lambda item: item[1], reverse=True)
    return freq_list


def frq_cpr(cipher_bytes: bytes) -> List[Tuple[int, int]]:
    """
    Finds how often each byte value appears in a ciphertext.
    The function returns (byte_value, count) pairs ordered from
    the most frequent byte to the least frequent.
    """
    counts = Counter(cipher_bytes)

    # Convert counts to (byte, count) pairs and sort by count descending.
    # The lambda selects item[1] (the count) so the sorting is based on frequency.
    freq_list = sorted(counts.items(), key=lambda item: item[1], reverse=True)
    return freq_list


def build_dec_key(
    plain_freq: List[Tuple[str, int]],
    cipher_freq: List[Tuple[int, int]],
    top_n: int = 17,
) -> Dict[int, str]:
    """
    Builds a partial decryption key by pairing the top-N most frequent plaintext
    characters with the top-N most frequent ciphertext byte values.

    Args:
        plain_freq:  List of (char, count) sorted from most to least frequent.
        cipher_freq: List of (byte_value, count) sorted from most to least frequent.
        top_n:       Number of most frequent symbols to pair.

    Returns:
        A dictionary mapping ciphertext byte values (int) to guessed
        plaintext characters (str).
    """
    dec_key: Dict[int, str] = {}

    # Take only the top N from each list
    plain_top = plain_freq[:top_n]
    cipher_top = cipher_freq[:top_n]

    # Pair: most frequent plaintext char with most frequent ciphertext byte, etc.
    for (ch, _), (byte_val, _) in zip(plain_top, cipher_top):
        dec_key[byte_val] = ch

    return dec_key


def guess_txt(cipher_bytes: bytes, dec_key: Dict[int, str]) -> str:
    """
    Attempts to decrypt ciphertext using a partial decryption key.

    Args:
        cipher_bytes: The ciphertext (sequence of bytes).
        dec_key: A partial decryption key mapping ciphertext byte values (0–255)
                 to guessed plaintext characters.

    Returns:
        A string where known bytes are replaced with their guessed plaintext
        character, and unknown bytes are replaced with '$'.
    """
    result = []

    for b in cipher_bytes:
        if b in dec_key:
            result.append(dec_key[b])
        else:
            result.append("$")

    return "".join(result)
python