summaryrefslogtreecommitdiff
authorandyq <andyq>2002-12-09 20:30:46 (UTC)
committer andyq <andyq>2002-12-09 20:30:46 (UTC)
commitb9a448e0687558c1cb79f801161966e15d589132 (patch) (side-by-side diff)
tree4f485b85b8bc03546008dd2003c75bf60f7acd9b
parentaccc4e231dc34744e75d32af77eeb98f46006c27 (diff)
downloadopie-b9a448e0687558c1cb79f801161966e15d589132.zip
opie-b9a448e0687558c1cb79f801161966e15d589132.tar.gz
opie-b9a448e0687558c1cb79f801161966e15d589132.tar.bz2
Added replay function and included own random method for replay functionality
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
@@ -1,9 +1,10 @@
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
+#include <time.h>
#ifdef QWS
#include <qpe/qpeapplication.h>
#include <qpe/config.h>
#else
#include <qapplication.h>
@@ -23,12 +24,13 @@
#define STATE_BOSS 0
#define STATE_RUNNING 1
#define STATE_CRASHING 2
#define STATE_CRASHED 3
#define STATE_NEWGAME 4
#define STATE_MENU 5
+#define STATE_REPLAY 6
// Menus
#define MENU_MAIN_MENU 0
#define MENU_OPTIONS_MENU 1
// Main Menu Options
@@ -124,12 +126,13 @@ int main( int argc, char *argv[] )
}
SFCave :: SFCave( int spd, QWidget *w, char *name )
: QMainWindow( w, name )
{
+ replayIt = 0;
#ifdef QWS
showMaximized();
#else
resize( 240, 284 );
#endif
@@ -161,14 +164,16 @@ SFCave :: SFCave( int spd, QWidget *w, char *name )
speed = spd; // Change to 2 for PC
press = false;
offscreen = new QPixmap( sWidth, sHeight );
offscreen->fill( Qt::black );
- setUp();
+// setUp();
crashLineLength = -1;
+ state = STATE_MENU;
+ prevState = STATE_MENU;
gameTimer = new QTimer( this, "game timer" );
connect( gameTimer, SIGNAL( timeout() ),
this, SLOT( run() ) );
}
@@ -179,22 +184,31 @@ SFCave :: ~SFCave()
void SFCave :: start()
{
gameTimer->start( 10 );
}
+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;
nrFrames = 0;
dir = 1;
thrust = 0;
@@ -218,12 +232,13 @@ void SFCave :: setUp()
noThrust = DownThrustVals[FLY_GAME_TYPE][currentGameDifficulty];
maxUpThrust = MaxUpThrustVals[FLY_GAME_TYPE][currentGameDifficulty];
maxDownThrust = MaxDownThrustVals[FLY_GAME_TYPE][currentGameDifficulty];
}
crashLineLength = 0;
+ lastGateBottomY = 0;
user.setRect( 50, sWidth/2, 4, 4 );
blockWidth = 20;
blockHeight = 70;
gapHeight = initialGateGaps[currentGameDifficulty];
@@ -251,26 +266,39 @@ void SFCave :: setUp()
for ( int i = 0 ; i < MAPSIZE ; ++i )
mapBottom[i] = sHeight - 10;
}
for ( int i = 0 ; i < BLOCKSIZE ; ++i )
blocks[i].setY( -1 );
+
}
void SFCave :: run()
{
switch ( state )
{
case STATE_MENU:
displayMenu();
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();
break;
case STATE_CRASHING:
case STATE_CRASHED:
@@ -281,12 +309,22 @@ void SFCave :: run()
{
if ( nrFrames % 2 == 0 )
handleKeys();
// Apply Game rules
nrFrames ++;
+
+ if ( replay )
+ {
+ while( replayIt->current() && *(replayIt->current()) == nrFrames )
+ {
+ press = !press;
+ ++(*replayIt);
+ }
+ }
+
if ( CURRENT_GAME_TYPE == SFCAVE_GAME )
handleGameSFCave();
else if ( CURRENT_GAME_TYPE == GATES_GAME )
handleGameGates();
else if ( CURRENT_GAME_TYPE == FLY_GAME )
handleGameFly();
@@ -520,18 +558,19 @@ void SFCave :: addGate()
{
int x1 = sWidth;
int y1 = mapTop[50];
int b1Height = nextInt(mapBottom[50] - mapTop[50] - gapHeight);
// 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;
int b2Height = mapBottom[50] - y2;
blocks[i].setRect( x1, y1, blockWidth, b1Height );
@@ -770,13 +809,17 @@ void SFCave :: keyPressEvent( QKeyEvent *e )
{
switch( e->key() )
{
case Qt::Key_Up:
case Qt::Key_F9:
case Qt::Key_Space:
- press = true;
+ if ( !press )
+ {
+ press = true;
+ replayList.append( new int( nrFrames ) );
+ }
break;
case Qt::Key_M:
case Qt::Key_Return:
case Qt::Key_Enter:
if ( state == STATE_CRASHED )
state = STATE_MENU;
@@ -801,28 +844,32 @@ void SFCave :: keyReleaseEvent( QKeyEvent *e )
else
{
switch( e->key() )
{
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();
break;
}
}
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
@@ -1,28 +1,37 @@
#include <qmainwindow.h>
#include <qpainter.h>
#include <qpixmap.h>
#include <qpoint.h>
#include <qrect.h>
#include <qtimer.h>
+#include <qlist.h>
-
+#include "random.h"
#define MAPSIZE 52
#define BLOCKSIZE 6
#define TRAILSIZE 30
+
+
class SFCave : public QMainWindow
{
Q_OBJECT
public:
int sWidth;
int sHeight;
int segSize;
+ int currentSeed;
+
+ QList<int> replayList;
+ QListIterator<int> *replayIt;
+ bool replay;
+
int blockWidth;
int blockHeight;
int gapHeight;
int state;
int prevState;
int speed;
@@ -76,12 +85,13 @@ public:
double thrust;
bool running;
SFCave( int speed = 3, QWidget *p = 0, char *name = 0 );
~SFCave();
void start();
+ void setSeed( int seed );
int nextInt( int range );
void setUp();
void handleGameSFCave();
void handleGameGates();
void handleGameFly();
bool checkFlyGameCollision();
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
@@ -1,9 +1,9 @@
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
DEPENDPATH += $(OPIEDIR)/include
LIBS += -lqpe