/*      SOME NOTES ON NES GAME GENIE DECODING


   (Copyright/trademark credits included either
   where used, or at the end of README)

   While cleaning out my room in the process of moving, I came upon
   the original manual for the NES Game Genie.  I then went about trying to
   figure out how to translate *its* codes to hex.  Welcome to the wonderful
   world of reverse-engineering.

   NOTE:  I do *not* have a NES or a NES Game Genie anymore, so this is
   guesswork.  It seems right, though.

   The first thing to remember is that unlike the SNES, the NES is an
   8-bit system, but still needs one-byte data.  It puzzled me at first how
   it was possible, but I soon figured it out:

   As the manual says, the first and second letters can be changed to
   any of eight possibilities, like so:

   A P Z L G I T Y
   E O X U K S V N

   If the first or second letters are in one line, any of
   the other letters in that line can serve to replace it.

   So, 8 (first letter) * 8 (second letter) == 64 possiblities...
   but we're not done yet!

   The first and *last* letters can be changed as well.  Look at the
   above table.  Replace any of the letters with the letter above or below.

   This is 2 (top/bottom for first) * 2 (top/bottom for second) == 4,
   which when multiplied by 64, gives us the 256 that makes us programmers
   so happy!

   Now comes the trickier part - what do all the letters mean?  Let's
   look at a few codes, shall we?  Look at BUB codes 4-7...

   ZAUGEZPE  Start at level 10
   PPUGEZPE  Start at level 25
   ZLUGEZPA  Start at level 50
   LGUGEZPE  Start at level 75

   Now, these jumps are a bit broad, so lets look at something finer,
   like CITY 6-10...

   PEKEIIAA  Start at level 1 (Gosh...)
   ZEKEIIAA  Start at level 2
   LEKEIIAA  Start at level 3
   GEKEIIAA  Start at level 4
   IEKEIIAA  Start at level 5

   Finally, we see some order.  (In the discussions that follow, until
   specified, I'll ignore the address bits:  ddaaaaad for 8-letter codes and
   ddaaad for 6-letter codes, where d=data, and a=address.  Note that this
   is fudging a bit.)

   PEA brings us to level 1, so could PEA mean one?  It makes sense.
   Imagine A=0, P=1, Z=2, and so on.  So, AEKEIIAA is level 0.  (And will
   likely crash the game...)

   Now, look back up at the first BUB code, ZAE, which brings us to
   level 10.  Z=2, but we're 8 out... note the last letter, though.  It's an
   E instead of an A.  So:  we take the numerical equivalent of the first
   letter, and if the last letter is in the second line, we add 8.

   Now check out the BUB code for level 25:  PPE.  P=1, and E hints that
   we have to add 8... still, we're 25-8-1 == 16 out.  Hmmm... 16.  perhaps
   that's what the second letter means.  PPE = (1*1) + (1*16) + (1*8), which
   gives us 25!  Let's test it with the last BUB code, LGE:

   LGE = (3*1) + (4*16) + (1*8) = 3 + 64 + 8 = 75...  Eureka!

   This gives us codes up to (7*1) + (7*16) + (1*8) = 127, or (since we
   started at zero) 128 different possiblities.  But what about the other
   128?

   Although you can probably work out how from what I've already
   explained, let's look at another code, ULT 7, which is

   EKEOAPGV     200 gold at start

   EKV = 200.  How, though?  V is in group 2, so we have to add 8.  But
   so are the other two letters.  Let's guess that the if the first letter
   is in group two (Since it's the only letter left that can be changed
   according to the 'programming' rules in the codebook.) we have to add 128:

   (1*128) + (0*1) + (4*16) + (1*8) = 200!  Woohoo!

   Or, to put it bitwise:

   GG:  A       E       P       O       Z       X       L       U
   bin: 0000    0001    0010    0011    0100    0101    0110    0111
   hex: 0       1       2       3       4       5       6       7

   GG:  G       K       I       S       T       V       Y       N
   bin: 1000    1001    1010    1011    1100    1101    1110    1111
   hex: 8       9       A       B       C       D       E       F

   Code bitmap (assuming 8 letters):
               11 1111 1111 2222 2222 2233
   0123 4567 8901 2345 6789 0123 4567 8901
   DDDD DDDA AAAA AAAA AAAA AAAA AAAA AAAD
   (D'ya see what I mean by fudging, now?)

   Hex:
        3                                 
   3456 1012 ???? ???? ???? ???? ???? ????
   DDDD DDDD AAAA AAAA AAAA AAAA AAAA AAAA

   To test:  ULT7 == EKV == 0001 100x ... xxx1 == 1100 1000 == C8 == 200

   To go further would really require a NES, a Game Genie, and a
   heck of a lot of patience.  Along with the address bits, there might
   be another that locks in a number instead of just changing it at the
   beginning.  (Mind you, SZG == 1011 010x ... xxx0 == 1010 0101 -- note
   the pattern of the bits.  Another bit may not be necessary, unless one
   really needs the value A5 == 165...)

   If you want to help, find a code that has a numerical effect,
   then make that number zero.  Make sure the number can be greater than
   255 -- money or XP in an RPG, for instance.  This'll be your base code.
   (AExxxxxA, most likely) Now, futz around with the letters in the x's,
   one at a time, until you make the number 256.  This may require you to
   change the second letter too, but keep it 'even.'  If you succeed at
   that, write the code down, then try for 65536 (3 bytes) and 16777216
   (4 bytes).

   You could try 4294967296, but the number requires 5 bytes to
   display, which is unlikely.  If it *does* work, try for 1099511627776,
   281474976710656, and 72057594037927936, (which is 64 bits wide!)

   Regardless, send me the codes (including the 'zero' code), the
   game you played, and what each code does.  Any codes you send me will
   still be your own no matter where you're from, due to the Berne
   Convention, so don't worry about me stealing them.
   -----------------------------------------------------------------------
   Some promising codes that affect addresses:

   DEM 12 13 14 15 16 (in 'sorted' order)

   Base code: XZNZGPSA +

   VANXLOSE
   VANXTOSE
   VEEZPOSE
   VEEZYOSE
   VEEXZOSE

   A = xxx0     N = 1111        X = 0101 
   E = xxx1     E = 0001        Z = 0100 (Remember, 1111 + 1 == 10000...)

   FORT 7

   ... +
   PASOUZYA +
   VASOKZSA

   U = 0111     Y = 1110 
   K = 1001     S = 1011

   GOON 5

   GAUIZGZA +
   AGUIYGAZ

   Z = 0100     Z= 0100
   Y = 1110     A= 0000

   QEST 9

   GAXEGIZA +
   GAUEGIZA     (Only one letter different)

   X = 0101     U = 0111        (Only one bit different, too)

   CAS 2 3

   KZSSEZKA +
   KXESUZKA

   S = 1011     E = 0001
   E = 0001     U = 0111

   PANKXPGA +
   PANGSAGA

   K = 1001     X = 0101        P = 0010
   G = 1000     S = 1011        A = 0000

   CHER 6

   IEOALZPA +
   GEOAPZAA

   L = 0110     P = 0010
   P = 0010     A = 0000

   TRI 6

   SZEVNOVK +
   SZVTSOVK

   E = 0001     V = 1101        N = 1111
   V = 1101     T = 1100        S = 1011

   NOID 15

   GZKXAOSE +
   GZKZIOSE

   A = 0000     I = 1010
   X = 0101     Z = 0100

   HYDE 1

   GZXVTKVK +
   GZXTTSVK

   V = 1101     K = 1001
   T = 1100     S = 1011


   Possibly promising codes (not included):

   DUCK 7
   ULT (Mr. Nose!) 3
   FIST 10
   SYND 12
   BURG 9
 */

/* This program will translate a GG code to the equivalent binary
   and was put together in about 20 minutes */

#include <stdio.h>
#include <string.h>

void failure(void)
{
    printf("Usage: 'ggnes XXXXXX' or 'ggnes XXXXXXXX'\n");
    exit(1);
}

int main(int argc, char **argv)
{
    char ggcode[9];		/* 8, plus the end-of-string NUL */
    char i = 0;
    if (argc != 2)		/* Program name, plus only one code */
	failure();
    strcpy(ggcode, argv[1]);
    if (!((strlen(ggcode) == 6) | (strlen(ggcode) == 8)))
	failure();
    for (i = 0; i < strlen(ggcode); i++)
	printf("   %c\t", ggcode[i]);
    printf("\n");
    for (i = 0; i < strlen(ggcode); i++) {
	switch (ggcode[i]) {	/* AEPOZXLUGKISTVYN */
	case 'a':
	case 'A':
	    printf("0000\t");
	    break;
	case 'e':
	case 'E':
	    printf("0001\t");
	    break;
	case 'p':
	case 'P':
	    printf("0010\t");
	    break;
	case 'o':
	case 'O':
	    printf("0011\t");
	    break;
	case 'z':
	case 'Z':
	    printf("0100\t");
	    break;
	case 'x':
	case 'X':
	    printf("0101\t");
	    break;
	case 'l':
	case 'L':
	    printf("0110\t");
	    break;
	case 'u':
	case 'U':
	    printf("0111\t");
	    break;
	case 'g':
	case 'G':
	    printf("1000\t");
	    break;
	case 'k':
	case 'K':
	    printf("1001\t");
	    break;
	case 'i':
	case 'I':
	    printf("1010\t");
	    break;
	case 's':
	case 'S':
	    printf("1011\t");
	    break;
	case 't':
	case 'T':
	    printf("1100\t");
	    break;
	case 'v':
	case 'V':
	    printf("1101\t");
	    break;
	case 'y':
	case 'Y':
	    printf("1110\t");
	    break;
	case 'n':
	case 'N':
	    printf("1111\t");
	    break;
	default:
	    printf("\n\nError in character %d", i);
	}
    }
    printf("\n");
    return 0;
}
