-rw-r--r-- | noncore/games/sfcave/random.cpp | 179 | ||||
-rw-r--r-- | noncore/games/sfcave/random.h | 19 | ||||
-rw-r--r-- | noncore/games/sfcave/sfcave.cpp | 79 | ||||
-rw-r--r-- | noncore/games/sfcave/sfcave.h | 12 | ||||
-rw-r--r-- | noncore/games/sfcave/sfcave.pro | 4 |
5 files changed, 274 insertions, 19 deletions
diff --git a/noncore/games/sfcave/random.cpp b/noncore/games/sfcave/random.cpp new file mode 100644 index 0000000..c4c10bb --- a/dev/null +++ b/noncore/games/sfcave/random.cpp @@ -0,0 +1,179 @@ +/* ------------------------------------------------------------------------- + * This is an ANSI C library for multi-stream random number generation. + * The use of this library is recommended as a replacement for the ANSI C + * rand() and srand() functions, particularly in simulation applications + * where the statistical 'goodness' of the random number generator is + * important. The library supplies 256 streams of random numbers; use + * SelectStream(s) to switch between streams indexed s = 0,1,...,255. + * + * The streams must be initialized. The recommended way to do this is by + * using the function PlantSeeds(x) with the value of x used to initialize + * the default stream and all other streams initialized automatically with + * values dependent on the value of x. The following convention is used + * to initialize the default stream: + * if x > 0 then x is the state + * if x < 0 then the state is obtained from the system clock + * if x = 0 then the state is to be supplied interactively. + * + * The generator used in this library is a so-called 'Lehmer random number + * generator' which returns a pseudo-random number uniformly distributed + * 0.0 and 1.0. The period is (m - 1) where m = 2,147,483,647 and the + * smallest and largest possible values are (1 / m) and 1 - (1 / m) + * respectively. For more details see: + * + * "Random Number Generators: Good Ones Are Hard To Find" + * Steve Park and Keith Miller + * Communications of the ACM, October 1988 + * + * Name : rngs.c (Random Number Generation - Multiple Streams) + * Authors : Steve Park & Dave Geyer + * Language : ANSI C + * Latest Revision : 09-22-98 + * ------------------------------------------------------------------------- + */ + +#include <stdio.h> +#include <time.h> +#include "random.h" + +#define MODULUS 2147483647 /* DON'T CHANGE THIS VALUE */ +#define MULTIPLIER 48271 /* DON'T CHANGE THIS VALUE */ +#define CHECK 399268537 /* DON'T CHANGE THIS VALUE */ +#define STREAMS 256 /* # of streams, DON'T CHANGE THIS VALUE */ +#define A256 22925 /* jump multiplier, DON'T CHANGE THIS VALUE */ +#define DEFAULT 123456789 /* initial seed, use 0 < DEFAULT < MODULUS */ + +static long seed[STREAMS] = {DEFAULT}; /* current state of each stream */ +static int stream = 0; /* stream index, 0 is the default */ +static int initialized = 0; /* test for stream initialization */ + + + double Random(void) +/* ---------------------------------------------------------------- + * Random returns a pseudo-random real number uniformly distributed + * between 0.0 and 1.0. + * ---------------------------------------------------------------- + */ +{ + const long Q = MODULUS / MULTIPLIER; + const long R = MODULUS % MULTIPLIER; + long t; + + t = MULTIPLIER * (seed[stream] % Q) - R * (seed[stream] / Q); + if (t > 0) + seed[stream] = t; + else + seed[stream] = t + MODULUS; + return ((double) seed[stream] / MODULUS); +} + + + void PlantSeeds(long x) +/* --------------------------------------------------------------------- + * Use this function to set the state of all the random number generator + * streams by "planting" a sequence of states (seeds), one per stream, + * with all states dictated by the state of the default stream. + * The sequence of planted states is separated one from the next by + * 8,367,782 calls to Random(). + * --------------------------------------------------------------------- + */ +{ + const long Q = MODULUS / A256; + const long R = MODULUS % A256; + int j; + int s; + + initialized = 1; + s = stream; /* remember the current stream */ + SelectStream(0); /* change to stream 0 */ + PutSeed(x); /* set seed[0] */ + stream = s; /* reset the current stream */ + for (j = 1; j < STREAMS; j++) { + x = A256 * (seed[j - 1] % Q) - R * (seed[j - 1] / Q); + if (x > 0) + seed[j] = x; + else + seed[j] = x + MODULUS; + } +} + + + void PutSeed(long x) +/* --------------------------------------------------------------- + * Use this function to set the state of the current random number + * generator stream according to the following conventions: + * if x > 0 then x is the state (unless too large) + * if x < 0 then the state is obtained from the system clock + * if x = 0 then the state is to be supplied interactively + * --------------------------------------------------------------- + */ +{ + char ok = 0; + + if (x > 0) + x = x % MODULUS; /* correct if x is too large */ + if (x < 0) + x = ((unsigned long) time((time_t *) NULL)) % MODULUS; + if (x == 0) + while (!ok) { + printf("\nEnter a positive integer seed (9 digits or less) >> "); + scanf("%ld", &x); + ok = (0 < x) && (x < MODULUS); + if (!ok) + printf("\nInput out of range ... try again\n"); + } + seed[stream] = x; +} + + + void GetSeed(long *x) +/* --------------------------------------------------------------- + * Use this function to get the state of the current random number + * generator stream. + * --------------------------------------------------------------- + */ +{ + *x = seed[stream]; +} + + + void SelectStream(int index) +/* ------------------------------------------------------------------ + * Use this function to set the current random number generator + * stream -- that stream from which the next random number will come. + * ------------------------------------------------------------------ + */ +{ + stream = ((unsigned int) index) % STREAMS; + if ((initialized == 0) && (stream != 0)) /* protect against */ + PlantSeeds(DEFAULT); /* un-initialized streams */ +} + + + void TestRandom(void) +/* ------------------------------------------------------------------ + * Use this (optional) function to test for a correct implementation. + * ------------------------------------------------------------------ + */ +{ + long i; + long x; + double u; + char ok = 0; + + SelectStream(0); /* select the default stream */ + PutSeed(1); /* and set the state to 1 */ + for(i = 0; i < 10000; i++) + u = Random(); + GetSeed(&x); /* get the new state value */ + ok = (x == CHECK); /* and check for correctness */ + + SelectStream(1); /* select stream 1 */ + PlantSeeds(1); /* set the state of all streams */ + GetSeed(&x); /* get the state of stream 1 */ + ok = ok && (x == A256); /* x should be the jump multiplier */ + if (ok) + printf("\n The implementation of rngs.c is correct.\n\n"); + else + printf("\n\a ERROR -- the implementation of rngs.c is not correct.\n\n"); +} diff --git a/noncore/games/sfcave/random.h b/noncore/games/sfcave/random.h new file mode 100644 index 0000000..4bc7c06 --- a/dev/null +++ b/noncore/games/sfcave/random.h @@ -0,0 +1,19 @@ +/* ----------------------------------------------------------------------- + * Name : rngs.h (header file for the library file rngs.c) + * Author : Steve Park & Dave Geyer + * Language : ANSI C + * Latest Revision : 09-22-98 + * ----------------------------------------------------------------------- + */ + +#if !defined( _RNGS_ ) +#define _RNGS_ + +double Random(void); +void PlantSeeds(long x); +void GetSeed(long *x); +void PutSeed(long x); +void SelectStream(int index); +void TestRandom(void); + +#endif diff --git a/noncore/games/sfcave/sfcave.cpp b/noncore/games/sfcave/sfcave.cpp index 788606f..b5bc736 100644 --- a/noncore/games/sfcave/sfcave.cpp +++ b/noncore/games/sfcave/sfcave.cpp @@ -2,4 +2,5 @@ #include <stdlib.h> #include <math.h> +#include <time.h> #ifdef QWS @@ -27,4 +28,5 @@ #define STATE_NEWGAME 4 #define STATE_MENU 5 +#define STATE_REPLAY 6 // Menus @@ -128,4 +130,5 @@ SFCave :: SFCave( int spd, QWidget *w, char *name ) { + replayIt = 0; #ifdef QWS showMaximized(); @@ -165,6 +168,8 @@ SFCave :: SFCave( int spd, QWidget *w, char *name ) offscreen->fill( Qt::black ); - setUp(); +// setUp(); crashLineLength = -1; + state = STATE_MENU; + prevState = STATE_MENU; gameTimer = new QTimer( this, "game timer" ); @@ -183,14 +188,23 @@ void SFCave :: start() } +void SFCave :: setSeed( int seed ) +{ + if ( seed == -1 ) + currentSeed = ((unsigned long) time((time_t *) NULL)); + else + currentSeed = seed; + PutSeed( currentSeed ); +} + int SFCave :: nextInt( int range ) { - return rand() % range; + int val = (int)(Random( ) * range); + + return val; + } void SFCave :: setUp() { - state = STATE_MENU; - prevState = STATE_MENU; - score = 0; offset = 0; @@ -222,4 +236,5 @@ void SFCave :: setUp() crashLineLength = 0; + lastGateBottomY = 0; user.setRect( 50, sWidth/2, 4, 4 ); @@ -255,4 +270,5 @@ void SFCave :: setUp() for ( int i = 0 ; i < BLOCKSIZE ; ++i ) blocks[i].setY( -1 ); + } @@ -265,8 +281,20 @@ void SFCave :: run() break; case STATE_NEWGAME: + setSeed( -1 ); setUp(); draw(); state = STATE_RUNNING; + replay = false; + replayList.clear(); break; + case STATE_REPLAY: + setSeed( currentSeed ); + setUp(); + draw(); + state = STATE_RUNNING; + replay = true; + if ( replayIt ) + delete replayIt; + replayIt = new QListIterator<int>( replayList ); case STATE_BOSS: drawBoss(); @@ -285,4 +313,14 @@ void SFCave :: run() // Apply Game rules nrFrames ++; + + if ( replay ) + { + while( replayIt->current() && *(replayIt->current()) == nrFrames ) + { + press = !press; + ++(*replayIt); + } + } + if ( CURRENT_GAME_TYPE == SFCAVE_GAME ) handleGameSFCave(); @@ -524,10 +562,11 @@ void SFCave :: addGate() // See if height between last gate and this one is too big - if ( b1Height - 200 > lastGateBottomY ) + if ( b1Height - 100 > lastGateBottomY ) b1Height -= 25; - else if ( b1Height + 200 < lastGateBottomY ) + else if ( b1Height + 100 < lastGateBottomY ) b1Height += 25; lastGateBottomY = b1Height; + int x2 = sWidth; int y2 = y1 + b1Height + gapHeight; @@ -774,5 +813,9 @@ void SFCave :: keyPressEvent( QKeyEvent *e ) case Qt::Key_F9: case Qt::Key_Space: - press = true; + if ( !press ) + { + press = true; + replayList.append( new int( nrFrames ) ); + } break; case Qt::Key_M: @@ -805,20 +848,24 @@ void SFCave :: keyReleaseEvent( QKeyEvent *e ) case Qt::Key_F9: case Qt::Key_Space: - press = false; + case Qt::Key_Up: + if ( press ) + { + press = false; + + replayList.append( new int( nrFrames ) ); + } break; - case Qt::Key_Up: - press = false; - case Qt::Key_R: - case Qt::Key_Down: if ( state == STATE_CRASHED ) { - state = STATE_NEWGAME; + state = STATE_REPLAY; } - else - movel = true; break; + case Qt::Key_Down: + if ( state == STATE_CRASHED ) + state = STATE_NEWGAME; + break; default: e->ignore(); diff --git a/noncore/games/sfcave/sfcave.h b/noncore/games/sfcave/sfcave.h index 69a0e13..0d9a626 100644 --- a/noncore/games/sfcave/sfcave.h +++ b/noncore/games/sfcave/sfcave.h @@ -5,6 +5,7 @@ #include <qrect.h> #include <qtimer.h> +#include <qlist.h> - +#include "random.h" #define MAPSIZE 52 @@ -12,4 +13,6 @@ #define TRAILSIZE 30 + + class SFCave : public QMainWindow { @@ -21,4 +24,10 @@ public: int segSize; + int currentSeed; + + QList<int> replayList; + QListIterator<int> *replayIt; + bool replay; + int blockWidth; int blockHeight; @@ -80,4 +89,5 @@ public: ~SFCave(); void start(); + void setSeed( int seed ); int nextInt( int range ); void setUp(); diff --git a/noncore/games/sfcave/sfcave.pro b/noncore/games/sfcave/sfcave.pro index f4b9e5d..5f49330 100644 --- a/noncore/games/sfcave/sfcave.pro +++ b/noncore/games/sfcave/sfcave.pro @@ -2,6 +2,6 @@ TEMPLATE = app CONFIG += qt warn_on release DESTDIR = $(OPIEDIR)/bin -SOURCES = sfcave.cpp helpwindow.cpp -HEADERS = sfcave.h helpwindow.h +SOURCES = sfcave.cpp helpwindow.cpp random.cpp +HEADERS = sfcave.h helpwindow.h random.h TARGET = sfcave INCLUDEPATH += $(OPIEDIR)/include |