I'm trying to write some code that will create a pseudo-random integer sequence that uses every digit from 0 to n, and then repeats. The naive approach would be to create an array of n integers, and then scramble them somehow, then loop through them all. That's trading space for speed, but I need to preserve space if possible.
Thinking about this reminded me of "FizzleFade", the algorithm Wolfenstein 3D used to fill the screen with red, one pixel at a time, without filling the same pixel twice. It's quite simple (this example just prints the X and Y coordinates):
uint32_t rndval = 1;
uint16_t x, y;
do {
y = rndval & 0x000FF;
x = (rndval & 0x1FF00) >> 8;
unsigned lsb = rndval & 1;
rndval >>= 1;
if (lsb) {
rndval ^= 0x00012000;
}
if (x < 320 && y < 200)
printf("x: %d y: %d\n", x, y);
} while (rndval != 1);
At least, it looks simple. This appears to be a Linear Feedback Shift Register. However, I don't know how to adapt this code for n bits. I don't know how they determined that XOR value. I first tried to adapt the above code to 8-bit values like this:
#include <stdio.h>
#include <stdint.h>
int fizzlefade(void) {
uint8_t rndval = 1;
uint16_t values = 0;
do {
unsigned lsb = rndval & 1;
rndval >>= 1;
if (lsb) {
rndval ^= 0x21;
}
printf("%d\n", rndval);
values++;
} while (rndval != 1);
printf("Total number of values: %d\n", values);
return 0;
}
int main(void) {
printf("Fizzlefade demo\n");
fizzlefade();
return 0;
}
However, no matter what I change the XOR value to, I only get N values, where N < n, usually less than 100 values for an 8-bit value. How I do I determine the XOR taps? Do I need a different starting value? Is there a faster/smaller way than using an LFSR?
EDIT: I made a bit of progress. I noticed that in the original, the rndval was double the size of the output values. So I changed my rndval to a 16-bit unsigned, then changed the XOR to 0x1200 to mimic the original code. This gives me 250 random values, all unique -- so close! Still not sure what to do.