home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1 (1993) / nebula.bin / SourceCode / Random / Random.m < prev    next >
Encoding:
Text File  |  1993-01-19  |  5.0 KB  |  277 lines

  1. //
  2. // Random
  3. //
  4. // <<See the file Random.h for more information>>.
  5. //
  6. // Version 1.1, 1992 Feb 27
  7. //
  8. // Written by Gregor Purdy
  9. // gregor@umich.edu
  10. //
  11. // See the README file included for information
  12. // and distribution and usage rights. 
  13. //
  14.  
  15.  
  16. #import <sys/time.h>
  17. #import <math.h>
  18. #import "Random.h"
  19.  
  20.  
  21. #define RAND_DEBUG
  22.  
  23.  
  24. @implementation Random
  25.  
  26.  
  27. + (int)version
  28. {
  29.     return 2;                // Was 0 last release, but should have been 1.
  30. }
  31.  
  32.  
  33. - init
  34. {
  35.     [super init];            // Make a new instance using superclass' method
  36.     [self newSeeds];            // Get a new seed for ourselves
  37.  
  38.     iset = 0;                // No saved gaussian yet.
  39.     gset = 0.0;
  40.     
  41.     gscale = 1.0;
  42.     gorigin = 0.0;
  43.  
  44.     return self;
  45. }
  46.  
  47.  
  48. - initSeeds:(int)s1 :(int)s2 :(int)s3
  49. {
  50.     [super init];
  51.     [self setSeeds:s1 :s2 :s3];
  52.  
  53.     return self;
  54. }
  55.  
  56.  
  57. - newSeeds
  58. {
  59.     struct timeval theTime;        // gettimeofday return structure
  60.     
  61.     gettimeofday(&theTime,0);        // Get the time of day in seconds and microseconds
  62.     h1 = theTime.tv_usec;        // Set seed 1 by microseconds past second
  63.     gettimeofday(&theTime,0);        // Get the time of day in seconds and microseconds
  64.     h2 = theTime.tv_usec;        // Set seed 2 by microseconds past second
  65.     gettimeofday(&theTime,0);        // Get the time of day in seconds and microseconds
  66.     h3 = theTime.tv_usec;        // Set seed 3 by microseconds past second
  67.  
  68.     return self;    
  69. }
  70.  
  71.  
  72. - setSeeds:(int) s1 :(int) s2 :(int) s3
  73. {
  74.     h1 = s1;                // Set the seeds to the values given
  75.     h2 = s2;
  76.     h3 = s3;
  77.     
  78.     return self;
  79. }
  80.  
  81.  
  82. - getSeeds:(int *)s1 :(int *)s2 :(int *)s3
  83. {
  84.     if((s1 == NULL) || (s2 == NULL) || (s3 == NULL))
  85.     return nil;
  86.  
  87.     *s1 = h1;
  88.     *s2 = h2;
  89.     *s3 = h3;
  90.  
  91.     return self;
  92. }
  93.  
  94.  
  95. //
  96. // See the Source article for the explanations of these constants
  97. //
  98. #define M1    32771
  99. #define M2    32779
  100. #define M3    32783
  101. #define F1    179
  102. #define F2    183
  103. #define F3    182
  104.  
  105. #define MAXNUM    32767
  106. #define RANGE    32768
  107.  
  108. - (int) rand
  109. {
  110.     h1 = (F1 * h1) % M1;            // Update the sections
  111.     h2 = (F2 * h2) % M2;
  112.     h3 = (F2 * h3) % M3;
  113.     
  114.     if ((h1 > MAXNUM) || (h2 > MAXNUM) || (h3 > MAXNUM))    // If a section is out of range,
  115.         return [self rand];            //   return next result
  116.     else                    // Otherwise,
  117.         return (h1 + h2 + h3) % RANGE;        //   Return this result
  118. }
  119.  
  120.  
  121. - (int) randMax:(int)max
  122. {
  123.     if(max <= 0)
  124.         return 0;
  125.     else
  126.     return (int)((float)[self rand] / (float)RANGE * (float)(max + 1));
  127. }
  128.  
  129.  
  130. - (int)randMin:(int)min max:(int)max
  131. {
  132.     return min + [self randMax:(max - min)];
  133. }
  134.  
  135.  
  136. - (double)percent
  137. {
  138.     return ((double)[self rand] / (double)RANGE);
  139. }
  140.  
  141.  
  142. - (BOOL)bool
  143. {
  144.     return ([self randMax:1]);
  145. }
  146.  
  147.  
  148. - (int)rollDie:(int) numSides
  149. {
  150.     return [self randMax:(numSides - 1)] + 1;
  151. }
  152.  
  153.  
  154. - (int)roll:(int) numRolls die:(int) numSides
  155. {
  156.     int temp = 0;
  157.     int loop;
  158.     
  159.     for (loop = 1 ; loop <= numRolls ; loop++ )
  160.     temp += [self rollDie:numSides];
  161.     
  162.     return temp;
  163. }
  164.  
  165.  
  166. - (int) rollBest:(int)numWanted of:(int)numRolls die:(int)numSides
  167. {
  168.     int temp[numRolls];                // Array of rolls
  169.     int loop1;                    // First loop control variable
  170.     int loop2;                    // Second loop control variable
  171.     int highest;                // Index of highest found roll
  172.     int accumulator = 0;            // Accumulates total best roll
  173.     
  174.     for (loop1 = 1 ; loop1 <= numRolls ; loop1++)    // Fill an array with rolls
  175.     temp[loop1] = [self rollDie:numSides];
  176.     
  177.     for (loop1 = 1 ; loop1 <= numWanted; loop1++) {
  178.     highest = 1;                // Start off as if first is highest
  179.     for (loop2 = 2 ; loop2 <= numRolls ; loop2++)    // Scan array for higher rolls
  180.         if (temp[loop2] > temp[highest])    // If temp[loop2] is higher, then
  181.         highest = loop2;        //     remember that fact
  182.     accumulator += temp[highest];        // Add highest roll to accumulator
  183.     temp[highest] = 0;            // Clear highest roll so we don't find it again
  184.     }
  185.     
  186.     return accumulator;                // Return what we found
  187. }
  188.  
  189.  
  190. - (double)randFunc:(ddfunc)func
  191. {
  192.     return (*func)([self percent]);
  193. }
  194.  
  195.  
  196. - (double)gScale
  197. {
  198.     return gscale;
  199. }
  200.  
  201.  
  202. - setGScale:(double)aScale
  203. {
  204.     gscale = aScale;
  205.     
  206.     return self;
  207. }
  208.  
  209.  
  210. - (double)gOrigin
  211. {
  212.     return gorigin;
  213. }
  214.  
  215.  
  216. - setGOrigin:(double)anOrigin
  217. {
  218.     gorigin = anOrigin;
  219.     
  220.     return self;
  221. }
  222.  
  223.  
  224. - (double)gaussian
  225. {
  226.     double        fac, r, v1, v2, temp;
  227.     
  228.     if(iset == 0) {                // If none stored, calculate a pair.
  229.         r = 0.0;
  230.     
  231.         while((r >= 1.0) || (r == 0.0)) {    // Find a pair which are inside unit circle.
  232.         v1 = 2.0 * [self percent] - 1.0;
  233.         v2 = 2.0 * [self percent] - 1.0;
  234.         r = (v1 * v1) + (v2 * v2);
  235.     }
  236.     
  237.     fac = sqrt(-2.0 * log(r) / r);        // Do Box-Muller transformation.
  238.     gset = v1 * fac;
  239.     iset = 1;
  240.     
  241.     temp = v2 * fac;            // Return one of the pair.
  242.     }
  243.     else {                    // Otherwise return stored one.
  244.         iset = 0;
  245.     temp = gset;
  246.     }
  247.     
  248.     return ((temp * gscale) + gorigin);        // Modify the variable.
  249. }
  250.  
  251.  
  252. - read:(NXTypedStream *)stream
  253. {
  254.     [super read:stream];
  255.     
  256.     NXReadTypes(stream, "iiiiddd", &h1, &h2, &h3, &iset, &gset, &gscale, &gorigin);
  257.     
  258.     return self;
  259. }
  260.  
  261.  
  262. - write:(NXTypedStream *)stream
  263. {
  264.     [super write:stream];
  265.     
  266.     NXWriteTypes(stream, "iiiiddd", &h1, &h2, &h3, &iset, &gset, &gscale, &gorigin);
  267.  
  268.     return self;
  269. }
  270.  
  271.  
  272. @end
  273.  
  274.  
  275. //
  276. // End of file.
  277. //