summaryrefslogtreecommitdiff
Side-by-side diff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--noncore/games/sfcave/random.cpp179
-rw-r--r--noncore/games/sfcave/random.h19
-rw-r--r--noncore/games/sfcave/sfcave.cpp79
-rw-r--r--noncore/games/sfcave/sfcave.h12
-rw-r--r--noncore/games/sfcave/sfcave.pro4
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