#include #include #include #include #define BAG_SIZE 63 #define NUM_DIFF_PIECES 7 typedef struct { u_int8_t pieces_remaining; u_int8_t pieces[BAG_SIZE]; u_int32_t seed; } Bag_t; u_int32_t gen_game(u_int32_t *p_seed); u_int32_t next_rand(u_int32_t seed); void init_bag(Bag_t *p_bag); u_int8_t next_piece(Bag_t *p_bag); u_int32_t gen_game(u_int32_t *p_seed) { Bag_t bag; u_int8_t holdPiece, nextPiece; u_int32_t nextBagSeed; u_int8_t i; init_bag(&bag); bag.seed = *p_seed; /* In actuality, the game keeps a buffer of 25 pieces plucked from the bag, of which 24 slots are to be filled before the first call to next_piece. This has an effect on the seed that will be used to choose the holdPiece. */ for (i = 0; i < 24; i++) { *p_seed = next_rand(*p_seed); } holdPiece = next_rand(*p_seed) % NUM_DIFF_PIECES; printf("%u ", holdPiece); for (i = 0; i < BAG_SIZE; i++) { nextPiece = next_piece(&bag); printf("%u", nextPiece); } nextBagSeed = bag.seed; printf(" %08x\n", nextBagSeed); return nextBagSeed; } u_int32_t next_rand(u_int32_t seed) { u_int32_t retVal; u_int8_t i; seed++; retVal = 0; i = 0; do { seed = (seed << 3 | seed >> 29) ^ 0x80500000; // magic numbers retVal |= (seed & 1) << i; } while (++i < 32); return retVal; } /* Initializes 63-bag 9 copies of each piece 0 1 2 3 4 5 6 0 1 2 ... 4 5 6 resets decrementer counter to 63 */ void init_bag(Bag_t *p_bag) { u_int8_t *p; u_int8_t i, j; p = p_bag->pieces; i = 0; do { j = 0; do { *p = j; p++; } while (++j < NUM_DIFF_PIECES); } while (++i < BAG_SIZE / NUM_DIFF_PIECES); p_bag->pieces_remaining = BAG_SIZE; } u_int8_t next_piece(Bag_t *p_bag) { u_int8_t bag_idx; u_int8_t *p; u_int8_t piece; p_bag->seed = next_rand(p_bag->seed); bag_idx = p_bag->seed % p_bag->pieces_remaining; // Randomly pluck a piece from the bag. piece = p_bag->pieces[bag_idx]; p = p_bag->pieces + bag_idx; // Fill the hole left by the plucked piece by shifting left every piece after it. while (bag_idx < BAG_SIZE - 1) { bag_idx++; *p = p[1]; p++; } p_bag->pieces_remaining--; if (p_bag->pieces_remaining == 0) { init_bag(p_bag); } return piece; } int main(int argc, char **argv) { u_int64_t cycles; u_int64_t nsec; u_int32_t seed; int nflag = 0; long iterations = 1; int c; opterr = 0; while ((c = getopt(argc, argv, "ni:")) != -1) { switch (c) { case 'n': nflag = 1; break; case 'i': iterations = strtol(optarg, NULL, 10); if (iterations < 1) { iterations = 1; } break; case '?': if (optopt == 'i') fprintf (stderr, "Option -%c requires an argument.\n", optopt); else if (isprint(optopt)) fprintf (stderr, "Unknown option `-%c'.\n", optopt); else fprintf (stderr, "Unknown option character `\\x%x'.\n", optopt); return 1; default: abort(); } } if (nflag == 0) { /* The N64 has a CPU count register that increments at 46.875 MHz, with 1 cycle equal to 64/3 nanoseconds. This cycle count is written to and read from the cart's sram, converted to nanoseconds, and used to seed the randomizer. */ // Input is a 32 bit hexadecimal number. For example, 0bff234a cycles = (u_int32_t)strtoul(argv[optind], NULL, 16); // multiply by 64/3 nsec = ((cycles / 3) << 6) + (((cycles % 3) << 6) / 3); seed = (u_int32_t)nsec; } else { seed = (u_int32_t)strtoul(argv[optind], NULL, 16); } for (; iterations > 0; iterations--) { seed = gen_game(&seed); } /* Output is in the format of: holdPiece 63-bag nextBagSeed For example, 6 001150146450116635656435023453415464605002253133462632321422012 a5b8b448 */ /* N64 New Tetris colors 0 L pink 1 J purple 2 Z red 3 S green 4 T yellow 5 I blue 6 O gray */ return 0; }