ftp.nice.ch/pub/next/games/board/Risk.0.97.s.tar.gz#/RiskSource0.97/Risk/Random.m

This is Random.m in view mode; [Download] [Up]

//
// Random
//
// <<See the file Random.h for more information>>.
//
// Version 1.1, 1992 Feb 27
//
// Written by Gregor Purdy
// gregor@umich.edu
//
// See the README file included for information
// and distribution and usage rights. 
//


#import <sys/time.h>
#import <math.h>
#import "Random.h"


#define RAND_DEBUG


@implementation Random


+ (int)version
{
    return 2;				// Was 0 last release, but should have been 1.
}


- init
{
    [super init];			// Make a new instance using superclass' method
    [self newSeeds];			// Get a new seed for ourselves

    iset = 0;				// No saved gaussian yet.
    gset = 0.0;
    
    gscale = 1.0;
    gorigin = 0.0;

    return self;
}


- initSeeds:(int)s1 :(int)s2 :(int)s3
{
    [super init];
    [self setSeeds:s1 :s2 :s3];

    return self;
}


- newSeeds
{
    struct timeval theTime;		// gettimeofday return structure
	
    gettimeofday(&theTime,0);		// Get the time of day in seconds and microseconds
    h1 = theTime.tv_usec;		// Set seed 1 by microseconds past second
    gettimeofday(&theTime,0);		// Get the time of day in seconds and microseconds
    h2 = theTime.tv_usec;		// Set seed 2 by microseconds past second
    gettimeofday(&theTime,0);		// Get the time of day in seconds and microseconds
    h3 = theTime.tv_usec;		// Set seed 3 by microseconds past second

    return self;	
}


- setSeeds:(int) s1 :(int) s2 :(int) s3
{
    h1 = s1;				// Set the seeds to the values given
    h2 = s2;
    h3 = s3;
    
    return self;
}


- getSeeds:(int *)s1 :(int *)s2 :(int *)s3
{
    if((s1 == NULL) || (s2 == NULL) || (s3 == NULL))
	return nil;

    *s1 = h1;
    *s2 = h2;
    *s3 = h3;

    return self;
}


//
// See the Source article for the explanations of these constants
//
#define M1	32771
#define M2	32779
#define M3	32783
#define F1	179
#define F2	183
#define F3	182

#define MAXNUM	32767
#define RANGE	32768

- (int) rand
{
    h1 = (F1 * h1) % M1;			// Update the sections
    h2 = (F2 * h2) % M2;
    h3 = (F2 * h3) % M3;
    
    if ((h1 > MAXNUM) || (h2 > MAXNUM) || (h3 > MAXNUM))	// If a section is out of range,
        return [self rand];			//   return next result
    else					// Otherwise,
        return (h1 + h2 + h3) % RANGE;		//   Return this result
}


- (int) randMax:(int)max
{
    if(max <= 0)
        return 0;
    else
	return (int)((float)[self rand] / (float)RANGE * (float)(max + 1));
}


- (int)randMin:(int)min max:(int)max
{
    return min + [self randMax:(max - min)];
}


- (double)percent
{
    return ((double)[self rand] / (double)RANGE);
}


- (BOOL)bool
{
    return ([self randMax:1]);
}


- (int)rollDie:(int) numSides
{
    return [self randMax:(numSides - 1)] + 1;
}


- (int)roll:(int) numRolls die:(int) numSides
{
    int temp = 0;
    int loop;
	
    for (loop = 1 ; loop <= numRolls ; loop++ )
	temp += [self rollDie:numSides];
	
    return temp;
}


- (int) rollBest:(int)numWanted of:(int)numRolls die:(int)numSides
{
    int temp[numRolls];				// Array of rolls
    int loop1;					// First loop control variable
    int loop2;					// Second loop control variable
    int highest;				// Index of highest found roll
    int accumulator = 0;			// Accumulates total best roll
	
    for (loop1 = 1 ; loop1 <= numRolls ; loop1++)	// Fill an array with rolls
	temp[loop1] = [self rollDie:numSides];
	
    for (loop1 = 1 ; loop1 <= numWanted; loop1++) {
	highest = 1;				// Start off as if first is highest
	for (loop2 = 2 ; loop2 <= numRolls ; loop2++)	// Scan array for higher rolls
	    if (temp[loop2] > temp[highest])	// If temp[loop2] is higher, then
		highest = loop2;		//     remember that fact
	accumulator += temp[highest];		// Add highest roll to accumulator
	temp[highest] = 0;			// Clear highest roll so we don't find it again
    }
	
    return accumulator;				// Return what we found
}


- (double)randFunc:(ddfunc)func
{
    return (*func)([self percent]);
}


- (double)gScale
{
    return gscale;
}


- setGScale:(double)aScale
{
    gscale = aScale;
    
    return self;
}


- (double)gOrigin
{
    return gorigin;
}


- setGOrigin:(double)anOrigin
{
    gorigin = anOrigin;
    
    return self;
}


- (double)gaussian
{
    double		fac, r, v1, v2, temp;
    
    if(iset == 0) {				// If none stored, calculate a pair.
    	r = 0.0;
	
        while((r >= 1.0) || (r == 0.0)) {	// Find a pair which are inside unit circle.
	    v1 = 2.0 * [self percent] - 1.0;
	    v2 = 2.0 * [self percent] - 1.0;
	    r = (v1 * v1) + (v2 * v2);
	}
	
	fac = sqrt(-2.0 * log(r) / r);		// Do Box-Muller transformation.
	gset = v1 * fac;
	iset = 1;
	
	temp = v2 * fac;			// Return one of the pair.
    }
    else {					// Otherwise return stored one.
        iset = 0;
	temp = gset;
    }
    
    return ((temp * gscale) + gorigin);		// Modify the variable.
}


- read:(NXTypedStream *)stream
{
    [super read:stream];
    
    NXReadTypes(stream, "iiiiddd", &h1, &h2, &h3, &iset, &gset, &gscale, &gorigin);
    
    return self;
}


- write:(NXTypedStream *)stream
{
    [super write:stream];
    
    NXWriteTypes(stream, "iiiiddd", &h1, &h2, &h3, &iset, &gset, &gscale, &gorigin);

    return self;
}


@end


//
// End of file.
//

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.