]> git.draconx.ca Git - rrace.git/blobdiff - src/game.c
Improve RNG compatibility with old compilers.
[rrace.git] / src / game.c
index 47adc9ffe37cb01a90d88647d25246fb2be53332..801625103ab9ef09ae747a8a9b3c6447f36645a7 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Slide puzzle core game logic
- * Copyright © 2022 Nick Bowler
+ * Copyright © 2022-2024 Nick Bowler
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 #include <config.h>
 #include <limits.h>
 #include <string.h>
+#include <unistd.h>
 #include <time.h>
-#include <gethrxtime.h>
 #include "game.h"
 
-#define B64(x) ((x) & 0xffffffffffffffff)
+#define B64(x) ((x) & 0xffffffffffffffffull)
 
 /* Rotate val left by n bits.  The behaviour is undefined if n is zero. */
 static unsigned long long rot_left64(unsigned long long val, int n)
@@ -56,9 +56,9 @@ static unsigned long long splitmix64(unsigned long long *state)
 {
        unsigned long long z;
 
-       z = B64(*state += 0x9e3779b97f4a7c15);
-       z = B64((z ^ (z >> 30)) * 0xbf58476d1ce4e5b9);
-       z = B64((z ^ (z >> 27)) * 0x94d049bb133111eb);
+       z = B64(*state += 0x9e3779b97f4a7c15ull);
+       z = B64((z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ull);
+       z = B64((z ^ (z >> 27)) * 0x94d049bb133111ebull);
 
        return z ^ (z >> 31);
 }
@@ -119,6 +119,12 @@ void game_reseed(unsigned long long seed)
        rng_state[3] = splitmix64(&seed);
 }
 
+#define assign_tile(planes, tile, bit) do { \
+       0[planes] |= (((tile)>>0) & 1ul) << (bit); \
+       1[planes] |= (((tile)>>1) & 1ul) << (bit); \
+       2[planes] |= (((tile)>>2) & 1ul) << (bit); \
+} while (0)
+
 void game_reset(struct board *board)
 {
        unsigned char tiles[25];
@@ -127,8 +133,19 @@ void game_reset(struct board *board)
        if (!rng_is_seeded()) {
                unsigned long long seed;
 
-               seed = time(NULL);
-               seed += gethrxtime();
+               /*
+                * Try to get a reasonable initial seed.
+                *
+                * Reasonable in this context means:
+                *
+                * - roughly even distribution of 1/0 bits, and
+                * - unlikely to generate the same seed twice in succession.
+                */
+               game_begin(board);
+
+               seed  = time(NULL);
+               seed += board->time_start;
+               seed += (unsigned long long)getpid() << 16;
                seed += seed << 32;
 
                game_reseed(seed);
@@ -141,31 +158,26 @@ void game_reset(struct board *board)
        shuffle(tiles, 24);
        memset(board->goal, 0, sizeof board->goal);
 
-       for (i = 0; i < 9; i++) {
-               uint_fast32_t position = board_position(i/3+1, i%3+1) >> 6;
-
-               if (tiles[i] & 1) board->goal[0] |= position;
-               if (tiles[i] & 2) board->goal[1] |= position;
-               if (tiles[i] & 4) board->goal[2] |= position;
+       /*
+        * Goal bitmap has 2-tile "gaps" between rows; it doesn't matter what
+        * these are set to and since we have a random permutation it doesn't
+        * matter which of the 24 nonempty tiles we pick for the actual goal.
+        */
+       for (i = 0; i < 13; i++) {
+               assign_tile(board->goal, tiles[i], i);
        }
 
        tiles[24] = TILE_EMPTY;
        shuffle(tiles, 25);
-
        memset(board->game, 0, sizeof board->game);
+
        for (i = 0; i < 25; i++) {
-               unsigned x = i/5, y = i%5;
-               uint_fast32_t position;
-
-               position = board_position(x, y);
-               if (tiles[i] != TILE_EMPTY) {
-                       if (tiles[i] & 1) board->game[0] |= position;
-                       if (tiles[i] & 2) board->game[1] |= position;
-                       if (tiles[i] & 4) board->game[2] |= position;
-               } else {
-                       board->game[3] = ~position;
-                       board->x = x;
-                       board->y = y;
+               assign_tile(board->game, tiles[i], i);
+
+               if (tiles[i] == TILE_EMPTY) {
+                       board->game[3] = (1ul<<i);
+                       board->x = i%5;
+                       board->y = i/5;
                }
        }
 
@@ -240,16 +252,6 @@ uint_fast32_t game_check_goal(struct board *board)
        return mask & GOAL_MASK;
 }
 
-void game_begin(struct board *board)
-{
-       board->time_start = gethrxtime();
-}
-
-int_fast32_t game_elapsed(struct board *board)
-{
-       return (gethrxtime() - board->time_start) / 1000000;
-}
-
 int_fast32_t game_finish(struct board *board)
 {
        int_fast32_t t = game_elapsed(board);