Herzog Zwei is a game made by Technosoft back in 1989 for the Genesis and Mega Drive game systems. The game can be completed by playing as either the red player or blue player. Either campaign consists of 8 levels played at 4 difficulty settings making a total of 32 different scenerios to complete the game. There is no battery in the cartridge so in order for the game to 'remember' where you last left off, a password is provided to the player at the end of each level. When the player wants to pick up where they last left off, they enter the password and the scenerios they have played already finished are greyed out, allowing them to pick up where they last left off. This document shows how the password is generated and, very interestingly, shows the hidden message that was programmed into the password cipher. So, let's get started!
First, on the password entry screen, one will notice that the only characters they are given are the letters A through P. That makes for exactly 16 different characters. If you substitute A for 0, B for 1, C for 2 and so on, you will find that you can easily substitute all of these characters for those of the hexadecimal numbering system. Specifically instead of using:
ABCDEFGHIJKLMNOP
... you can now use:
0123456789ABCDEF
... to illustrate the same set of characters using a standard well-accepted system of digits:
This is important because it makes it easier to encode each of these characters into binary by simply using one nibble (four binary digits) to express each character uniquely (and assign it an individual weight to calculate the checksum - more on that later)... specifically:
Char: | Dec: | Hex: | Binary: |
A | 0 | 0 | 0000 |
B | 1 | 1 | 0001 |
C | 2 | 2 | 0010 |
D | 3 | 3 | 0011 |
E | 4 | 4 | 0100 |
F | 5 | 5 | 0101 |
G | 6 | 6 | 0110 |
H | 7 | 7 | 0111 |
I | 8 | 8 | 1000 |
J | 9 | 9 | 1001 |
K | 10 | A | 1010 |
L | 11 | B | 1011 |
M | 12 | C | 1100 |
N | 13 | D | 1101 |
O | 14 | E | 1110 |
P | 15 | F | 1111 |
So, for a password such as:
CPGHCACACNL
Each character can be expressed in decimal as:
2 | 15 | 6 | 7 | 2 | 0 | 2 | 0 | 2 | 13 | 11 |
C | P | G | H | C | A | C | A | C | N | L |
Here it is in HEX:
2 | F | 6 | 7 | 2 | 0 | 2 | 0 | 2 | D | B |
C | P | G | H | C | A | C | A | C | N | L |
And, finally, here it is in Binary (stay with me!):
0010 | 1111 | 0110 | 0111 | 0010 | 0000 | 0010 | 0000 | 0010 | 1101 | 1011 |
C | P | G | H | C | A | C | A | C | N | L |
The first two characters in this password example, "CP", show all of the 8 levels that were beaten at the "A" (easiest) difficulty. The second pair of characters "GH" show the beaten "B" levels. The third and fourth pair of characters *just so happen* to be identical, "CA", and show the "C" and "D" levels beaten.
Here's how it works; I'll re-arrange the first 8 characters of the password top-down like this:
2nd 4 Levels: | C | G | C | C |
1st 4 Levels: | P | H | A | A |
Notice that the levels are listed in reverse order from what you'd be used to seeing at the in-game selection screen:
Converting the password arranged in this way into binary:
Difficulty: | A | B | C | D |
2nd 4 Levels: | ||||
Oase: | 0 | 0 | 0 | 0 |
Waldung: | 0 | 1 | 0 | 0 |
Eisfrei: | 1 | 1 | 1 | 1 |
Stadt: | 0 | 0 | 0 | 0 |
1st 4 Levels: | ||||
Strand: | 1 | 0 | 0 | 0 |
Loch: | 1 | 1 | 0 | 0 |
Vulkan: | 1 | 1 | 0 | 0 |
Abgrund: | 1 | 1 | 0 | 0 |
"X" indicates beaten levels (in this case, only Waldung:difficulty "A" was beaten):
Difficulty: | A | B | C | D |
Oase: | o | o | o | o |
Waldung: | X | o | o | o |
Eisfrei: | o | o | o | o |
Stadt: | o | o | o | o |
Strand: | o | o | o | o |
Loch: | o | o | o | o |
Vulkan: | o | o | o | o |
Abgrund: | o | o | o | o |
If any of the bits are toggled from 1 to 0 or 0 to 1, then they will be set to the opposite of whether that level was beaten or not. So, in other words, if I want a password that has all the levels beaten EXCEPT Waldung, like this:
Difficulty: | A | B | C | D |
Oase: | X | X | X | X |
Waldung: | o | X | X | X |
Eisfrei: | X | X | X | X |
Stadt: | X | X | X | X |
Strand: | X | X | X | X |
Loch: | X | X | X | X |
Vulkan: | X | X | X | X |
Abgrund: | X | X | X | X |
... then the binary mask should look like this (all 1's are inverted to 0's and all 0's are inverted to 1's):
Difficulty: | A | B | C | D |
2nd 4 Levels: | ||||
Oase: | 1 | 1 | 1 | 1 |
Waldung: | 1 | 0 | 1 | 1 |
Eisfrei: | 0 | 0 | 0 | 0 |
Stadt: | 1 | 1 | 1 | 1 |
1st 4 Levels: | ||||
Strand: | 0 | 1 | 1 | 1 |
Loch: | 0 | 0 | 1 | 1 |
Vulkan: | 0 | 0 | 1 | 1 |
Abgrund: | 0 | 0 | 1 | 1 |
Which, illustrated top-down in the password characters, should look like this:
2nd 4 Levels: | N | J | N | N |
1st 4 Levels: | A | I | P | P |
Laid out straight, it looks like this:
NAJINPNP
To complete this password, we need three more characters which we will cover now:
NAJINPNP | CKH |
So, let's take a look at these three characters "CKH" at the end of the password and see what information they contain, shall we? The first of these last three characters is "C". This character can be broken up into its binary parts:
Character | Binary |
C | 0010 |
The first three digits of this binary nibble (001) show us the 'chosen' cipher. In this case, it is the 2nd of a total of 8 available ciphers! The last digit of this binary nibble (0) shows whether or not the password shows the status of the red player or blue player. In this case, it is the red player. If it were the blue character, it would have been a (1), changing the password character from a "C"(0010) to a "D"(0011).
Finally, the last two characters are the checksum and they are the sole reason you cannot simply enter a bunch of random characters in the password entry screen and expect it to work. All the characters prior to these last two characters must add up to the value contained in these last two characters. BUT - it's not quite that simple! Each of their binary values are actually inverted so you have to go through one extra step to get the right characters. At least it's an easy step:
Character | Binary | Inverted | New Char |
A | 0000 | 1111 | P |
B | 0001 | 1110 | O |
C | 0010 | 1101 | N |
D | 0011 | 1100 | M |
E | 0100 | 1011 | L |
F | 0101 | 1010 | K |
G | 0110 | 1001 | J |
H | 0111 | 1000 | I |
I | 1000 | 0111 | H |
J | 1001 | 0110 | G |
K | 1010 | 0101 | F |
L | 1011 | 0100 | E |
M | 1100 | 0011 | D |
N | 1101 | 0100 | C |
O | 1110 | 0001 | B |
P | 1111 | 0000 | A |
So, to calculate the two checksum characters in our loyal example above,
CPGHCACACNL
We will need to take the sum of the decimal values of the first 9 characters:
2+15+6+7+2+0+2+0+2 = 36
And now to come up with the last two characters, find out how many times 36 can be divided by 16 (the answer is twice, with a remainder of 4)... so write down the corresponding characters that associate to the decimal values of 2 (for twice) and 4 (for the remainder):
C E
Now, go and change them to nibbles:
0010 0100
And invert them (change 1's to 0's and 0's to 1's):
1101 1011
Now, change the inverted nibbles back to our password characters:
N L
So the entire password, in all it's glory, including valid checksum characters is:
CPGHCACACNL
That wasn't too hard, was it?
Now, we're getting close to the truly fascinating part!! Remember how I said there were 8 ciphers? You never know which one will get 'chosen' and it is the reason why you may find that resetting the game and then beating Waldung again may yield a different password such as:
MIGFHCHKAMG
Which is an equivalent password to our example: CPGHCACACNL. Entering either one will yield the same result. As you may have guessed, the 9th character in MIGFHCHKAMG, "A" implies that the 1st of 8 ciphers was used to generate this password (for the red player as the blue player character would have been "B" instead of "A")... here, let's just put all those ciphers in one place (in the form of password characters and in order):
Index | Cipher | 9th Character |
000 | EIGFHCHK | (A or B) |
001 | GPGHCACA | (C or D) |
010 | FKHHGFGJ | (E or F) |
011 | CAGIGBCA | (G or H) |
100 | EHEBEOCA | (I or J) |
101 | GDGIGBGO | (K or L) |
110 | HDGBGLHF | (M or N) |
111 | GEGBHJGP | (O or P) |
Looks like a mess, doesn't it? If we convert these to their HEX equivalents, here's the result (again, stay with me, because at the end, I'm gonna blow your mind!!):
Index | Cipher |
000 | 48 65 72 7A |
001 | 6F 67 20 20 |
010 | 51 77 65 69 |
011 | 20 68 61 20 |
100 | 47 41 4E 20 |
101 | 63 68 61 6E |
110 | 73 61 6B 61 |
111 | 64 61 79 6F |
Now, look up your old trusty ASCII chart and you will find that each one of the bytes (pairs of nibbles) translate into the following:
Index | Cipher |
000 | H e r z |
001 | o g _ _ |
010 | Z w e i |
011 | _ h a _ |
100 | G A N _ |
101 | c h a n |
110 | s a k a |
111 | d a y o |
And lay it out straight, it reads:
"Herzog Zwei ha GAN chan sakadayo"
Here it is in Japanese katakana/hiragana/kanji:
Which, translated from Japanese, means:
"Herzog Zwei is the work of Gan-chan"
Who is Gan-chan, you ask? Well, the programmer's family name is Iwanaga . If you take the Japanese character for the "Iwa" part of his name and couple it with another character that means "rock", it changes the pronunciation of that "Iwa" character to "Gan", to make the word "Ganseki" (stone). Hence, Takeshi Iwanaga's nick name must have been "Gan-chan".
Is that cool or what?
OK, it took me almost an entire month to figure all of this out, so please be nice and download my silly Herzog Zwei Password app on the iTunes store today!! If you still play this awesome game, you'll find the app very handy (and fund my daughter's college tuition at the same time by contributing [my share of] the $.99!).
Thanks for sharing this moment of discovery with me. :)
PS - Special thanks to Gye and Nori for help with the Japanese translation!