diff --git a/tennis.c b/tennis.c index fee55a7..96c79ec 100644 --- a/tennis.c +++ b/tennis.c @@ -27,23 +27,63 @@ const char *lut[] = { "J", "K", "L", "M", }; -enum {lutlen = LEN(lut)}; // should be 28. +enum {lutlen = LEN(lut)}; // should be 28. -const u32 c0 = 64; -const u32 c1 = 11; -const u32 c2 = 21; -const u32 c3 = 2; -const u32 c4 = 21; -const u32 c5 = 8; +const u32 bases[] = { + 64, + 11, + 21, + 2, + 21, + 8, + 6, // dummy value. +}; + +enum { + MT_CHOICE = -1, +}; + +typedef enum { + MT_YOSHI, + MT_PEACH, + MT_MARIO, + MT_BOWSER, + MT_BOO, + MT_DK, + MT_BABY_MARIO, + MT_TOAD, + MT_WALUIGI, + MT_WARIO, + MT_LUIGI, + MT_DAISY, + MT_BIRDO, + MT_SHYGUY, + MT_DK_JR, + MT_PARATROOPA, +} character_t; + +typedef enum { + MT_SINGLES_GAME, + MT_SINGLES_TIME_3, + MT_SINGLES_TIME_5, + MT_SINGLES_BALL_1, + MT_SINGLES_BALL_3, + MT_SINGLES_POINT_3, + MT_SINGLES_POINT_5, + MT_DOUBLES_GAME_1, + MT_DOUBLES_TIME_3, + MT_DOUBLES_BALL_1, + MT_DOUBLES_POINT_3, +} gamemode_t; typedef struct { char code[9]; // data[0]: cup name - // data[1]: ? + // data[1]: gamemode // data[2]: player character (-1 for player's choice) - // data[3]: game mode? (boolean) + // data[3]: unknown (boolean) // data[4]: opponent character (-1 for player's choice) - // data[5]: ? + // data[5]: unknown // data[6]: court (-1 for player's choice) u32 data[7]; } code_t; @@ -69,16 +109,20 @@ code_t translate(const char *entry) { return code; } -int check_ranges(code_t *code) { - int within_range = 1; - within_range &= code->data[0] < c0; - within_range &= code->data[1] < c1; - within_range &= code->data[2] + 1 < c2 - 4; - within_range &= code->data[3] < c3; - within_range &= code->data[4] + 1 < c2 - 4; - within_range &= code->data[5] < c5; - within_range &= code->data[6] + 1 < 6; - return within_range; +int check_ranges(const code_t *code) { + const u32 neg1 = (u32)-1; + const u32 *data = code->data; + + return + (data[0] < bases[0]) && + (data[1] < bases[1]) && + (data[2] + 1 < bases[2] - 4) && + (data[3] < bases[3]) && + (data[4] + 1 < bases[4] - 4) && + (data[5] < bases[5]) && + (data[6] + 1 < bases[6]) && + (data[2] == neg1 || data[2] != data[4]) && + (data[1] < 7 || (data[2] != neg1 && data[4] != neg1)); } int decode_data(code_t *code) { @@ -95,12 +139,12 @@ int decode_data(code_t *code) { u32 leftover = part0 ^ 0x02AAAAAA; - code->data[0] = leftover % c0; leftover /= c0; - code->data[1] = leftover % c1; leftover /= c1; - code->data[2] = leftover % c2; leftover /= c2; - code->data[3] = leftover % c3; leftover /= c3; - code->data[4] = leftover % c4; leftover /= c4; - code->data[5] = leftover % c5; leftover /= c5; + code->data[0] = leftover % bases[0]; leftover /= bases[0]; + code->data[1] = leftover % bases[1]; leftover /= bases[1]; + code->data[2] = leftover % bases[2]; leftover /= bases[2]; + code->data[3] = leftover % bases[3]; leftover /= bases[3]; + code->data[4] = leftover % bases[4]; leftover /= bases[4]; + code->data[5] = leftover % bases[5]; leftover /= bases[5]; code->data[6] = leftover; code->data[2]--; @@ -117,29 +161,20 @@ int decode_data(code_t *code) { if (!check_ranges(code)) return 0; - // TODO: refactor so this isn't repeated in encode_data. - const u32 neg1 = (u32)-1; - if (code->data[2] == neg1 || code->data[2] != code->data[4]); else return 0; - if (code->data[1] < 7 || (code->data[2] != neg1 && code->data[4] != neg1)); else return 0; - return 1; } int encode_data(code_t *code) { - const u32 neg1 = (u32)-1; - if (code->data[2] == neg1 || code->data[2] != code->data[4]); else return 0; - if (code->data[1] < 7 || (code->data[2] != neg1 && code->data[4] != neg1)); else return 0; - if (!check_ranges(code)) return 0; u32 combined = 0; combined = code->data[6] + 1; - combined = combined * c5 + code->data[5]; - combined = combined * c4 + code->data[4] + 1; - combined = combined * c3 + code->data[3]; - combined = combined * c2 + code->data[2] + 1; - combined = combined * c1 + code->data[1]; - combined = combined * c0 + code->data[0]; + combined = combined * bases[5] + code->data[5]; + combined = combined * bases[4] + code->data[4] + 1; + combined = combined * bases[3] + code->data[3]; + combined = combined * bases[2] + code->data[2] + 1; + combined = combined * bases[1] + code->data[1]; + combined = combined * bases[0] + code->data[0]; combined = combined ^ 0x02AAAAAA; u32 checksum = (combined + 0x2AE0) % (lutlen * lutlen * lutlen); @@ -174,7 +209,7 @@ int validate_entry(const char *entry) { return decode_data(&code); } -static void print_code(code_t *code) { +static void print_code(const code_t *code) { for (int j = 0; j < 9; j++) { int index = code->code[j]; printf("%c", lut[index][0]); @@ -188,10 +223,24 @@ static u32 prng() { return prng_state ^ (prng_state >> 32); } -int bruteforce() { // with a fixed seed, this is useful for testing. +int bruteforce(int count) { + /* with a fixed seed, this is useful for testing. + the first 10 results should be: + 8RPEHR8R4 + MNXKWQMNE + CE922RCER + MQ1KMQMQG + 2N9GGR2NR + 25L53R250 + 15R09R159 + 9R9LMQ9RR + L312MQL3G + P93M6QP9N + */ + int found = 0; code_t code = {0}; - while (found < 10) { + while (found < count) { for (int j = 0; j < 9; j++) { code.code[j] = prng() % lutlen; } @@ -250,7 +299,7 @@ int main(int argc, char **argv) { //if (validate_entry(arg)) printf("%s\n", arg); invalid_count += !validate_entry(arg); } else if (!strcmp(arg, "bruteforce")) { - invalid_count += !bruteforce(); + invalid_count += !bruteforce(10); } else { u32 datum = strtoul(arg, NULL, 0); code.data[code_i] = datum;