ADFGVX Project — Round 2/5
We left Round 1 with a sorted character sequence built on a validated key. Here's where we are:
import string
all_chars = string.ascii_uppercase + string.digits
final_key = ""
while len(final_key) < 6:
key = input("Please enter key: ")
clean_key = ""
for letter in key.upper():
if letter in all_chars:
clean_key += letter
final_key = ""
for letter in clean_key:
if letter not in final_key:
final_key += letter
if len(final_key) < 6:
print("Invalid key. Please try again.")
sorted_chars = ""
reference = final_key + all_chars
for letter in reference:
if letter not in sorted_chars:
sorted_chars += letter
With key WASHINGTON, sorted_chars is:
WASHINGTOBCDEFJKLMPQRUVWXYZ0123456789
Placed in the 6×6 grid:
A D F G V X
A W A S H I N
D G T O B C D
F E F J K L M
G P Q R U V X
V Y Z 0 1 2 3
X 4 5 6 7 8 9
Now we build the substitution dictionary — every character mapped to its ADFGVX pair.
There's a mathematical approach. Each character in sorted_chars has an index from 0 to 35. Dividing by 6 gives the row index. The remainder gives the column index. Both are used to look up the corresponding letter in "ADFGVX".
matrix_letters = "ADFGVX"
matrix_dict = {}
for i in range(0, len(sorted_chars)):
matrix_dict[sorted_chars[i]] = matrix_letters[i // len(matrix_letters)] + matrix_letters[i % len(matrix_letters)]
It works. But it requires comfort with integer division and modulo — concepts from outside programming. So we use a simpler approach: a pre-generated list of all 36 pairs, in order from AA to XX.
matrix_letters = [
"AA", "AD", "AF", "AG", "AV", "AX",
"DA", "DD", "DF", "DG", "DV", "DX",
"FA", "FD", "FF", "FG", "FV", "FX",
"GA", "GD", "GF", "GG", "GV", "GX",
"VA", "VD", "VF", "VG", "VV", "VX",
"XA", "XD", "XF", "XG", "XV", "XX"
]
matrix_dict = {}
for i in range(0, len(sorted_chars)):
matrix_dict[sorted_chars[i]] = matrix_letters[i]
Same result. More explicit. Index 0 in sorted_chars maps to matrix_letters[0] — which is "AA". Index 1 maps to "AD". And so on.
A few entries from the resulting matrix_dict with key WASHINGTON:
{
'W': 'AA', # index 0 → AA
'A': 'AD', # index 1 → AD
'S': 'AF', # index 2 → AF
'H': 'AG', # index 3 → AG
'T': 'DA', # index 6 → DA
'O': 'DF', # index 8 → DF
'E': 'FA', # index 12 → FA
'0': 'VA', # index 24 → VA
'9': 'XX' # index 35 → XX
}
Now the message. Minimal validation — not empty, characters cleaned and uppercased. A message can be very short. "Yes" is a valid message. We don't over-validate.
message = ""
while not message:
message = input("Enter your message: ")
clean_message = ""
for letter in message.strip().upper():
if letter in all_chars:
clean_message += letter
Spaces, punctuation, special characters — all stripped. Only what exists in all_chars survives. What remains is ready for substitution.
substituted_message = ""
for letter in clean_message:
substituted_message += matrix_dict[letter]
One line of logic. Every character in the clean message is replaced by its two-letter ADFGVX pair from the dictionary.
A simulation. Key: WASHINGTON. Message: ATTACK.
clean_message: ATTACK
A → AD
T → DA
T → DA
A → AD
C → DV
K → FG
substituted_message: ADDADADADVFG
Six characters in. Twelve characters out. Every character doubled — that's always the case with ADFGVX substitution. The message length after substitution is always exactly twice the original.
The substitution is done. Next — transposition. The second layer of the cipher. Round 3.