ADFGVX Project — Round 1/5
We start with substitution. As we discussed in the concept article, the cipher begins with a 6×6 grid — rows and columns labeled with the six letters: A, D, F, G, V, X. Every character in the message gets replaced with its row-column pair.
In its standard form, the grid looks like this — characters placed in alphabetical order:
A D F G V X
A A B C D E F
D G H I J K L
F M N O P Q R
G S T U V W X
V Y Z 0 1 2 3
X 4 5 6 7 8 9
In this grid, A is at row A, column A → AA. T is at row G, column D → GD. 9 is at row X, column X → XX.
But a fixed grid is a weak grid. The whole point of the cipher is variation — personalization. In practice, characters are rearranged based on a keyword. Let's use WASHINGTON.
The keyword goes first — unique characters only, in order. WASHINGTON becomes WASHINGT0 — we drop the second N. Then we continue with the remaining characters from the full alphabet and digits, in order, skipping anything already used. The result: WASHINGTOBCDEFJKLMPQRUVWXYZ0123456789.
Placed in the 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 A is at row A, column D → AD. T is at row D, column D → DD. The same message produces completely different ciphertext. That's the point.
Let's build it. We need the full character set first.
import string
print(string.ascii_uppercase)
# ABCDEFGHIJKLMNOPQRSTUVWXYZ
print(string.digits)
# 0123456789
all_chars = string.ascii_uppercase + string.digits
# ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789
Now the key. We start simple — fixed value, no input yet:
key = "WASHINGTON"
sorted_chars = ""
reference = key.upper() + all_chars
for letter in reference:
if letter not in sorted_chars:
sorted_chars += letter
print(sorted_chars)
# WASHINGTOBCDEFJKLMPQRUVWXYZ0123456789
We concatenate the key and the full character set. Then we iterate — if the character isn't already in sorted_chars, we add it. Duplicates are ignored. The result is the personalized character order for our grid.
But a fixed key defeats the purpose. We want input. And we want that input to meet some quality standards — not empty, not full of characters that don't belong to all_chars, and with enough unique valid characters to make the reordering meaningful.
We build the validation in three layers.
Layer 1 — not empty. Simple while not key catches an empty string. But a key like "@@@" passes this check — it's not empty, but it contains no valid characters.
Layer 2 — contains valid characters. We clean the key — keep only characters that exist in all_chars. If nothing survives the cleaning, the key is useless.
Layer 3 — minimum 6 unique valid characters. A key like "MAMAMAMA" has 8 characters, but after removing duplicates we're left with just MA — two characters. That's a minimal reordering, easy to guess. We require at least 6 unique valid characters after cleaning.
All three layers, combined:
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.")
From here we only use final_key. Not key, not clean_key. They served their purpose — final_key is what matters.
The full block, clean:
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
A simulation. The user enters MANHATTAN:
Please enter key: MANHATTAN
clean_key → MANHATTAN — all characters valid. final_key → MANHTA — 6 unique characters. Passes.
sorted_chars result:
MANHTABCDEFGIJKLOPQRSUVWXYZ0123456789
Placed in the grid:
A D F G V X
A M A N H T A ← wait
Wait — A appears twice in MANHTA? No. MANHATTAN → unique characters in order → M, A, N, H, T — the second A is dropped, the second N is dropped. final_key is MANHT — only 5 unique characters. The validation rejects it.
Please enter key: MANHATTAN
Invalid key. Please try again.
Please enter key: WASHINGTON
final_key → WASHINGT — 8 unique characters. Passes.
sorted_chars:
WASHINGTOBCDEFJKLMPQRUVWXYZ0123456789
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
The grid is ready. Next — we map every character to its ADFGVX pair. That's the substitution dictionary. Round 2.