In 1984, German painter and artist Ralf Krempel obtained a patent for encoding messages as color codes. Each character is encoded as a unique sequence of one or more colors. According to the following table, uppercase letter C is encoded as color code yellow-blue, lowercase letter o as color code blue, and lowercase letter s as color code red-yellow.

To encode a plaintext, join the color codes for its characters, separated by a black color. Using the above color codes, plaintext Cosmopolitan is encoded into this ciphertext.

A modern version of the Krempel code represents each color in the ciphertext by an emoji of that color. As there are multiple emojis of the same color, each color can be represented by different emojis.

If we represent each color in the ciphertext for Cosmopolitan with a randomly chosen emoji of that color, we may get this ciphertext.

As each color is represented by a randomly chosen emoji of that color, this could be an alternative ciphertext for Cosmopolitan.

We simply reverse the process to decode a ciphertext. If the ciphertext is represented by emojis, we first determine the color for each emoji. Then we determine the corresponding character for each color code — with color codes separated from each other by a black color. The plaintext is obtained by concatenating these characters.
To encode and decode messages according to a Krempel code, we represent each color in the ciphertext by a unique uppercase letter (str). The color black is always represented by an asterisk (*; str).
The color codes for a Krempel code are defined in a text file. Each line of the file consists of a character that can occur in a plaintext, followed by one or more uppercase letters that represent the color code for the character in a ciphertext. For example, these are the first few lines of the file with color codes for the Krempel code we used in the introduction (krempel.txt):
AYG
aGB
BGR
CYB
iGP
JRR
KY
LYP
lP
mRB
nYR
OG
…
Using these color codes, the ciphertext (str) for Cosmopolitan is
YB*B*RY*RB*B*YY*B*P*GP*GY*GB*YR
We can also represent a color using an emoji (str) from the UTF-8 character encoding, where emojis are a single character. Multiple emojis could represent the same color, unlike uppercase letters and the asterisk that always represent a color in a unique way.
The colors of emojis for a Krempel code are defined in a text file. Each line of the file consists of an emoji and the uppercase letter or an asterisk (*) for the color of that emoji. For example, these are the first few lines of the file with emojis for the Krempel code we used in the introduction (emoji.txt):
πR
π§B
πY
πP
π«G
πG
π€*
πP
πY
π’G
π₯©R
πP
…
Using these emojis, the ciphertext (str) for Cosmopolitan can be represented as (first example from introduction)
ππ¦π¦π§π€πππ€πππ¦π¦π€πππ¦π¦π€πΎπ€π«ππ¦πππ€π’ππ€ππ
or as (second example from introduction)
πππ¦π§π¦π₯©ππ€πππ€ππ¦πππ¦π¬π€πΎπ¦π«ππ€π«ππ€π’π¦π€ππ₯©
Your task:
Write a function read_codes that takes the location (str) of a text file with color codes for a Krempel code $$\mathcal{K}$$. The function must return the dictionary with color codes for Krempel code $$\mathcal{K}$$: a dictionary (dict) that maps each character (str) that may occur in a plaintext onto its color code (str) consisting of one or more uppercase letters.
Write a function read_emojis that takes the location (str) of a text file with emojis for a Krempel code $$\mathcal{K}$$. The function must return the dictionary with emojis for Krempel code $$\mathcal{K}$$: a dictionary (dict) that maps each emoji (str) that may occur in the ciphertext onto the uppercase letter/asterisk (str) representing its color.
Write a function colored_emojis that takes the dictionary (dict) with emojis for Krempel code $$\mathcal{K}$$. The function must return the inverse dictionary (dict) that maps each color (str; uppercase letter/asterisk) of Krempel code $$\mathcal{K}$$ onto a set containing all emojis (str) of that color.
Write a function decode that takes two arguments: i) a ciphertext $$c$$ encoded according to a Krempel code $$\mathcal{K}$$ (str) and ii) the dictionary (dict) with color codes for Krempel code $$\mathcal{K}$$. The function must return the plaintext (str) obtained by decoding ciphertext $$c$$ (str) according to Krempel code $$\mathcal{K}$$. The function has a third optional parameter that may take a dictionary (dict) with emojis for Krempel code $$\mathcal{K}$$. If no dictionary with emojis is passed, the colors of ciphertext $$c$$ must be represented with uppercase letters and asterisks (*). Otherwise, the colors in ciphertext $$c$$ must be represented with emojis.
Write a function encode that takes two arguments: i) a plaintext $$t$$ (str) and ii) the dictionary (dict) with color codes for a Krempel code $$\mathcal{K}$$. The function must return the ciphertext (str) obtained by encoding plaintext $$t$$ according to Krempel code $$\mathcal{K}$$. The function has a third optional parameter that may take a dictionary (dict) with emojis for Krempel code $$\mathcal{K}$$. If no dictionary with emojis is passed, the colors in the ciphertext must be represented with uppercase letters and asterisks (*). Otherwise, each color in the ciphertext must be represented by a randomly chosen emoji of that color.
In Python, you cannot directly select a random element from a set. You can do this by first converting the set to a sequence (list or tuple) and then selecting a random element from the sequence.
The functions colored_emojis, decode and encode must not modify the dictionaries (dict) passed to them.
In this interactive session, we assume the text files krempel.txt and emoji.txt to be located in the current directory.
>>> character2colors = read_codes('krempel.txt')
>>> character2colors['C']
'YB'
>>> character2colors['o']
'B'
>>> character2colors['s']
'RY'
>>> emoji2color = read_emojis('emoji.txt')
>>> emoji2color['π']
'R'
>>> emoji2color['π']
'G'
>>> emoji2color['π¬']
'B'
>>> emoji2color['π€']
'*'
>>> color2emojis = colored_emojis(emoji2color)
>>> color2emojis['R']
{'π', 'β', 'π', 'π', 'π₯©'}
>>> color2emojis['G']
{'π', 'π«', 'π’', 'πΏ'}
>>> color2emojis['B']
{'π§', 'π¦', 'π', 'π¬'}
>>> color2emojis['*']
{'π€', 'π€', 'π¦'}
>>> decode('YB*B*RY*RB*B*YY*B*P*GP*GY*GB*YR', character2colors)
'Cosmopolitan'
>>> decode('ππ¦π¦π§π€πππ€πππ¦π¦π€πππ¦π¦π€πΎπ€π«ππ¦πππ€π’ππ€ππ', character2colors, emoji2color)
'Cosmopolitan'
>>> decode('πππ¦π§π¦π₯©ππ€πππ€ππ¦πππ¦π¬π€πΎπ¦π«ππ€π«ππ€π’π¦π€ππ₯©', character2colors, emoji2color)
'Cosmopolitan'
>>> encode('Cosmopolitan', character2colors)
'YB*B*RY*RB*B*YY*B*P*GP*GY*GB*YR'
>>> encode('Cosmopolitan', character2colors, emoji2color)
'ππ¦π¦π§π€πππ€πππ¦π¦π€πππ¦π¦π€πΎπ€π«ππ¦πππ€π’ππ€ππ'
>>> encode('Cosmopolitan', character2colors, emoji2color)
'πππ¦π§π¦π₯©ππ€πππ€ππ¦πππ¦π¬π€πΎπ¦π«ππ€π«ππ€π’π¦π€ππ₯©'