From 5a7f17a240cfa9fa10c8fbc427fda91873a5bac8 Mon Sep 17 00:00:00 2001 From: "Andrew \"Akari\" Alexeyew" Date: Fri, 27 Jul 2012 20:11:45 +0300 Subject: [PATCH] Added a custom random generator --- src/CMakeLists.txt | 1 + src/global.c | 11 +++--- src/global.h | 6 ++- src/item.c | 4 +- src/main.c | 3 ++ src/player.c | 2 +- src/random.c | 81 ++++++++++++++++++++++++++++++++++++++ src/random.h | 43 ++++++++++++++++++++ src/stage.c | 12 ++++-- src/stages/stage0.c | 4 +- src/stages/stage1_events.c | 4 +- src/stages/stage4.c | 4 +- 12 files changed, 154 insertions(+), 21 deletions(-) create mode 100644 src/random.c create mode 100644 src/random.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1ef97908..9a8080f6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -17,6 +17,7 @@ ADD_FLEX_BISON_DEPENDENCY(cfgscanner cfgparser) set(SRCs main.c + random.c stage.c replay.c global.c diff --git a/src/global.c b/src/global.c index ddb6ed7e..a3c3dbac 100644 --- a/src/global.c +++ b/src/global.c @@ -19,8 +19,11 @@ Global global; void init_global() { memset(&global, 0, sizeof(global)); - srand(time(0)); - + + tsrand_seed_p(&global.rand_game, time(0)); + tsrand_seed_p(&global.rand_visual, time(0)); + tsrand_switch(&global.rand_visual); + memset(&resources, 0, sizeof(Resources)); load_resources(); printf("- fonts:\n"); @@ -76,10 +79,6 @@ void fade_out(float f) { glColor4f(1,1,1,1); } -inline double frand() { - return rand()/(double)RAND_MAX; -} - extern SDL_Surface *display; void toggle_fullscreen() diff --git a/src/global.h b/src/global.h index ccea81f5..b773dcae 100644 --- a/src/global.h +++ b/src/global.h @@ -30,6 +30,7 @@ #include "vbo.h" #include "resource/resource.h" #include "replay.h" +#include "random.h" #define FILE_PREFIX PREFIX "/share/taisei/" #define CONFIG_FILE "config" @@ -112,6 +113,9 @@ typedef struct { Replay replay; int replaymode; + + RandomState rand_game; + RandomState rand_visual; } Global; extern Global global; @@ -128,8 +132,6 @@ void toggle_fullscreen(); void global_processevent(SDL_Event*); void take_screenshot(); -double frand(); - // this is used by both player and replay code enum { EV_PRESS, diff --git a/src/item.c b/src/item.c index 9b0c8e11..df202010 100644 --- a/src/item.c +++ b/src/item.c @@ -127,7 +127,7 @@ int collision_item(Item *i) { } inline void spawn_item(complex pos, Type type) { - create_item(pos, 5*cexp(I*rand()/frand()*M_PI*2), type); + create_item(pos, 5*cexp(I*tsrand()/frand()*M_PI*2), type); } void spawn_items(complex pos, int point, int power, int bomb, int life) { @@ -143,4 +143,4 @@ void spawn_items(complex pos, int point, int power, int bomb, int life) { for(i = 0; i < life; i++) spawn_item(pos, Life); -} \ No newline at end of file +} diff --git a/src/main.c b/src/main.c index 1e085b36..70730222 100644 --- a/src/main.c +++ b/src/main.c @@ -47,6 +47,9 @@ void taisei_shutdown() { #endif int main(int argc, char** argv) { + if(tsrand_test()) + return 0; + MKDIR(get_config_path()); MKDIR(get_screenshots_path()); MKDIR(get_replays_path()); diff --git a/src/player.c b/src/player.c index 46074afd..2da1f311 100644 --- a/src/player.c +++ b/src/player.c @@ -220,7 +220,7 @@ void player_death(Player *plr) { if(plr->deathtime == -1 && global.frames - abs(plr->recovery) > 0) { int i; for(i = 0; i < 20; i++) - create_particle2c("flare", plr->pos, NULL, Shrink, timeout_linear, 40, (3+frand()*7)*cexp(I*rand())); + create_particle2c("flare", plr->pos, NULL, Shrink, timeout_linear, 40, (3+frand()*7)*cexp(I*tsrand())); create_particle2c("blast", plr->pos, rgb(1,0.5,0.3), GrowFade, timeout, 35, 2.4); plr->deathtime = global.frames + DEATHBOMB_TIME; } diff --git a/src/random.c b/src/random.c new file mode 100644 index 00000000..cda7ef08 --- /dev/null +++ b/src/random.c @@ -0,0 +1,81 @@ +/* + * This software is licensed under the terms of the MIT-License + * See COPYING for further information. + * --- + * Copyright (C) 2011, Lukas Weber + * Copyright (C) 2012, Alexeyew Andrew + */ + +#include "random.h" +#include +#include + +/* + * Multiply-with-carry algorythm + */ + +static RandomState *tsrand_current; + +void tsrand_switch(RandomState *rnd) { + tsrand_current = rnd; +} + +void tsrand_seed_p(RandomState *rnd, uint32_t seed) { + // might be not the best way to seed this + rnd->w = (seed >> 16u) + TSRAND_W_SEED_COEFF * (seed & 0xFFFFu); + rnd->z = (seed >> 16u) + TSRAND_Z_SEED_COEFF * (seed & 0xFFFFu); +} + +int tsrand_p(RandomState *rnd) { + rnd->w = (rnd->w >> 16u) + TSRAND_W_COEFF * (rnd->w & 0xFFFFu); + rnd->z = (rnd->z >> 16u) + TSRAND_Z_COEFF * (rnd->z & 0xFFFFu); + return (uint32_t)((rnd->z << 16u) + rnd->w) % TSRAND_MAX; +} + +inline void tsrand_seed(uint32_t seed) { + tsrand_seed_p(tsrand_current, seed); +} + +inline int tsrand(void) { + return tsrand_p(tsrand_current); +} + +double frand(void) { + return tsrand()/(double)TSRAND_MAX; +} + +int tsrand_test(void) { +#if defined(TSRAND_FLOATTEST) + RandomState rnd; + tsrand_switch(&rnd); + tsrand_seed(time(0)); + + FILE *fp; + int i; + + fp = fopen("/tmp/rand_test", "w"); + for(i = 0; i < 10000; ++i) + fprintf(fp, "%f\n", frand()); + + return 1; +#elif defined(TSRAND_SEEDTEST) + RandomState rnd; + tsrand_switch(&rnd); + + int seed = 1337, i, j; + printf("SEED: %d\n", seed); + + for(i = 0; i < 5; ++i) { + printf("RUN #%i\n", i); + tsrand_seed(seed); + + for(j = 0; j < 5; ++j) { + printf("-> %i\n", tsrand()); + } + } + + return 1; +#else + return 0; +#endif +} diff --git a/src/random.h b/src/random.h new file mode 100644 index 00000000..f539042a --- /dev/null +++ b/src/random.h @@ -0,0 +1,43 @@ +/* + * This software is licensed under the terms of the MIT-License + * See COPYING for further information. + * --- + * Copyright (C) 2011, Lukas Weber + * Copyright (C) 2012, Alexeyew Andrew + */ + +#ifndef TSRAND_H +#define TSRAND_H + +#include + +typedef struct RandomState { + uint32_t w; + uint32_t z; +} RandomState; + +int tsrand_test(void); +void tsrand_switch(RandomState *rnd); +void tsrand_seed_p(RandomState *rnd, uint32_t seed); +int tsrand_p(RandomState *rnd); + +inline void tsrand_seed(uint32_t seed); +inline int tsrand(void); + +double frand(); + +#define TSRAND_MAX INT32_MAX + +#define srand USE_tsrand_seed_INSTEAD_OF_srand +#define rand USE_tsrand_INSTEAD_OF_rand + +/* + * These have to be distinct 16-bit constants k, for which both k*2^16-1 and k*2^15-1 are prime numbers + */ + +#define TSRAND_W_COEFF 30963 +#define TSRAND_W_SEED_COEFF 19164 +#define TSRAND_Z_COEFF 29379 +#define TSRAND_Z_SEED_COEFF 31083 + +#endif diff --git a/src/stage.c b/src/stage.c index 4387317e..8d506dcd 100644 --- a/src/stage.c +++ b/src/stage.c @@ -418,7 +418,7 @@ void stage_loop(StageInfo* info, StageRule start, StageRule end, StageRule draw, } int seed = time(0); - srand(seed); + tsrand_seed_p(&global.rand_game, seed); if(global.replaymode == REPLAY_RECORD) { replay_destroy(&global.replay); @@ -428,7 +428,7 @@ void stage_loop(StageInfo* info, StageRule start, StageRule end, StageRule draw, } else { printf("REPLAY_PLAY mode: %d events\n", global.replay.ecount); - srand(global.replay.seed); + tsrand_seed_p(&global.rand_game, global.replay.seed); printf("Random seed: %d\n", global.replay.seed); global.diff = global.replay.diff; @@ -442,6 +442,7 @@ void stage_loop(StageInfo* info, StageRule start, StageRule end, StageRule draw, global.plr.power = global.replay.plr_power; } + tsrand_switch(&global.rand_game); stage_start(); start(); @@ -452,8 +453,10 @@ void stage_loop(StageInfo* info, StageRule start, StageRule end, StageRule draw, stage_logic(endtime); calc_fps(&global.fps); - - stage_draw(info, draw, shaderrules, endtime); + + tsrand_switch(&global.rand_visual); + stage_draw(info, draw, shaderrules, endtime); + tsrand_switch(&global.rand_game); SDL_GL_SwapBuffers(); frame_rate(&global.lasttime); @@ -483,6 +486,7 @@ void stage_loop(StageInfo* info, StageRule start, StageRule end, StageRule draw, end(); stage_end(); + tsrand_switch(&global.rand_visual); } void draw_stage_title(StageInfo *info) { diff --git a/src/stages/stage0.c b/src/stages/stage0.c index 49c139c4..55ddfea7 100644 --- a/src/stages/stage0.c +++ b/src/stages/stage0.c @@ -161,9 +161,9 @@ void cirno_perfect_freeze(Boss *c, int time) { float g = frand(); float b = frand(); - create_projectile2c("ball", c->pos, rgb(r, g, b), cirno_pfreeze_frogs, 4*cexp(I*rand()), add_ref(global.boss)); + create_projectile2c("ball", c->pos, rgb(r, g, b), cirno_pfreeze_frogs, 4*cexp(I*tsrand()), add_ref(global.boss)); if(global.diff > D_Normal) - create_projectile2c("ball", c->pos, rgb(r, g, b), cirno_pfreeze_frogs, 4*cexp(I*rand()), add_ref(global.boss)); + create_projectile2c("ball", c->pos, rgb(r, g, b), cirno_pfreeze_frogs, 4*cexp(I*tsrand()), add_ref(global.boss)); } GO_AT(c, 160, 190, 2 + 1I); diff --git a/src/stages/stage1_events.c b/src/stages/stage1_events.c index 63700552..1b03a304 100644 --- a/src/stages/stage1_events.c +++ b/src/stages/stage1_events.c @@ -321,7 +321,7 @@ void hina_bad_pick(Boss *h, int time) { } AT(200) { - int win = rand()%5; + int win = tsrand()%5; for(i = 0; i < 5; i++) { if(i == win) continue; @@ -448,4 +448,4 @@ void stage1_events() { AT(5100) { global.boss = create_hina(); } -} \ No newline at end of file +} diff --git a/src/stages/stage4.c b/src/stages/stage4.c index 1f9b3267..90994627 100644 --- a/src/stages/stage4.c +++ b/src/stages/stage4.c @@ -88,7 +88,7 @@ void stage4_draw() { stagedata.light_strength *= 0.98; - if(frand() < 0.01) // TODO: this will desync replays, so we need our own rand(); + if(frand() < 0.01) stagedata.light_strength = 5+5*frand(); } @@ -140,4 +140,4 @@ void stage4_end() { void stage4_loop() { // ShaderRule shaderrules[] = { stage3_fog, NULL }; stage_loop(stage_get(5), stage4_start, stage4_end, stage4_draw, stage4_events, NULL, 5700); -} \ No newline at end of file +}