Advertisement
B1KMusic

[Refactored] Mario 64's RNG algorithm

Oct 8th, 2016
267
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 2.24 KB | None | 0 0
  1. /*
  2.  * This is a refactored version of Mario64's RNG method (as seen
  3.  * in pannenkoek's video*), designed as a module to be put in its own file.
  4.  *
  5.  * Pannenkoek's RNG video: https://www.youtube.com/watch?v=MiuLeTE2MeQ
  6.  *
  7.  * Uses more descriptive type names and avoids casting in favor of bit masking.
  8.  * Runs exactly as fast as the original code according to my benchmarks.
  9.  * But that's not surprising as modern compilers do an excellent job optimizing.
  10.  *
  11.  * The functions shigeru() and miyamoto() were named as such because they
  12.  * are completely random operations that add unnecessary cyclomatic complexity
  13.  * to the algorithm. Thus the function names are also completely random.
  14.  *
  15.  * There aren't that many ways to break it down. In my opinion, the original algorithm
  16.  * is very poorly written. It's not so simple to "fix" it without altering its functionality,
  17.  * as no matter how it is altered, you'll always end up with a dense mess of bitwise operation and
  18.  * hand-optimized (not to mention, inconsistent) code--a telling sign of unmaintainable code
  19.  * that was written once and never touched again.
  20.  */
  21.  
  22. typedef unsigned char uint8;
  23. typedef unsigned short uint16;
  24. typedef signed short sint16;
  25.  
  26. static const uint16 MAGIC[] = { 0x560A, 0xFF80, 0xAA55, 0x1FF4, 0x8180 };
  27.  
  28. static uint16
  29. high_byte(uint16 n)
  30. {
  31.     return n & 0xFF00;
  32. }
  33.  
  34. static uint16
  35. low_byte(uint16 n)
  36. {
  37.     return n & 0x00FF;
  38. }
  39.  
  40. static uint16
  41. low_to_high(uint16 n)
  42. {
  43.     return low_byte(n) << 8;
  44. }
  45.  
  46. static uint16
  47. high_to_low(uint16 n)
  48. {
  49.     return high_byte(n) >> 8;
  50. }
  51.  
  52. static uint16
  53. swap_bytes(uint16 n)
  54. {
  55.     return low_to_high(n) | high_to_low(n);
  56. }
  57.  
  58. static uint8
  59. is_odd(uint16 n)
  60. {
  61.     return n % 2 == 1;
  62. }
  63.  
  64. static sint16
  65. shigeru(sint16 n)
  66. {
  67.     return n ^ MAGIC[4];
  68. }
  69.  
  70. static uint16
  71. miyamoto(sint16 n)
  72. {
  73.     return (n == MAGIC[2]) ? 0 : (n ^ MAGIC[3]);
  74. }
  75.  
  76. uint16
  77. get_random_number(uint16 input)
  78. {
  79.     uint16 s0, s1;
  80.  
  81.     input = input == MAGIC[0] ? 0 : input;
  82.     s0 = low_to_high(input) ^ input;
  83.     input = swap_bytes(s0);
  84.     s0 = (low_byte(s0) << 1) ^ input;
  85.     s1 = (s0 >> 1) ^ MAGIC[1];
  86.     input = is_odd(s0) ? shigeru(s1) : miyamoto(s1);
  87.  
  88.     return input;
  89. }
  90.  
  91. // Works as expected: get_random_number(17711) -> 63470
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement