From 52b01775c2c94f08786696cae7836ca56f683739 Mon Sep 17 00:00:00 2001 From: jbzdarkid Date: Tue, 19 Nov 2019 09:42:45 -0800 Subject: Fix RNG -- this will break seeds, though. --- Source/Random.cpp | 7 +++-- Source/Random.h | 2 +- Source/Randomizer2.cpp | 78 ++++++++++++++++++++++++++++++++++++++++++++-- Source/Randomizer2Core.cpp | 13 ++++++-- Test/RandomTests.cpp | 8 +++++ 5 files changed, 98 insertions(+), 10 deletions(-) diff --git a/Source/Random.cpp b/Source/Random.cpp index 61fd30f..d9fe678 100644 --- a/Source/Random.cpp +++ b/Source/Random.cpp @@ -1,7 +1,7 @@ #include #include "Random.h" -int Random::s_seed = static_cast(time(nullptr)); // Seed from the time in milliseconds +uint32_t Random::s_seed = static_cast(time(nullptr)); // Seed from the time in milliseconds void Random::SetSeed(int seed) { s_seed = seed; @@ -9,6 +9,7 @@ void Random::SetSeed(int seed) { // Returns a random integer in [min, max] int Random::RandInt(int min, int max) { - s_seed = (214013 * s_seed + 2531011) % 2147483648; - return (s_seed % (max - min + 1)) + min; + s_seed = (214013 * s_seed + 2531011); // Implicit unsigned integer overflow + int32_t maskedSeed = ((s_seed >> 16) & 0x7fff); // Only use bits 16-30 + return (maskedSeed % (max - min + 1)) + min; } diff --git a/Source/Random.h b/Source/Random.h index 46287a1..a2ad706 100644 --- a/Source/Random.h +++ b/Source/Random.h @@ -8,5 +8,5 @@ public: static int RandInt(int min, int max); private: - static int s_seed; + static uint32_t s_seed; }; diff --git a/Source/Randomizer2.cpp b/Source/Randomizer2.cpp index 83427d7..adf8eb6 100644 --- a/Source/Randomizer2.cpp +++ b/Source/Randomizer2.cpp @@ -84,6 +84,77 @@ void Randomizer2::RandomizeTutorial() { } _serializer.WritePuzzle(p, 0xA3B5); } + + { // Back right + Puzzle p; + p.NewGrid(6, 6); + + p.grid[0][12].start = true; + p.grid[12][12].start = true; + p.grid[6][0].end = Cell::Dir::UP; + + std::vector cuts; + bool toTheRight; + // Start by generating a cut line, to ensure one of the two startpoints is inaccessible + int x, y; + switch (Random::RandInt(1, 4)) + { + case 1: + x = 1; + y = 1; + toTheRight = true; + cuts.emplace_back(Pos{0, 1}); + break; + case 2: + x = 1; + y = 1; + toTheRight = true; + cuts.emplace_back(Pos{1, 0}); + break; + case 3: + x = 11; + y = 1; + toTheRight = false; + cuts.emplace_back(Pos{12, 1}); + break; + case 4: + x = 11; + y = 1; + toTheRight = false; + cuts.emplace_back(Pos{11, 0}); + break; + } + while (y < p.height) { // The final cut will push y below the bottom of the puzzle, which means we're done. + switch (Random::RandInt(1, 4)) { + case 1: // Go right + if (x < p.width-2) { + cuts.emplace_back(Pos{x+1, y}); + x += 2; + } + break; + case 2: // Go left + if (x > 1) { + cuts.emplace_back(Pos{x-1, y}); + x -= 2; + } + break; + case 3: + case 4: // Go down (biased) + cuts.emplace_back(Pos{x, y+1}); + y += 2; + break; + } + } + + for (Pos pos : cuts) { + p.grid[pos.x][pos.y].gap = Cell::Gap::BREAK; + } + + for (Pos pos : Randomizer2Core::CutEdges(p, 30 - cuts.size(), true)) { + p.grid[pos.x][pos.y].gap = Cell::Gap::BREAK; + } + _serializer.WritePuzzle(p, 0xA3B2); + } } void Randomizer2::RandomizeKeep() { @@ -109,7 +180,7 @@ void Randomizer2::RandomizeKeep() { std::vector cutEdges = Randomizer2Core::CutEdges(p, 5, false); Puzzle copy = p; std::vector gates = {0x00344, 0x00488, 0x00489, 0x00495, 0x00496}; - for (int i=0; i pebbleMarkers = {0x034a9, 0x034b1, 0x034be, 0x034c4}; - std::vector cutEdges = Randomizer2Core::CutEdges(p, 7, false); for (Pos pos : cutEdges) { p.grid[pos.x][pos.y].gap = Cell::Gap::BREAK; } + + std::vector pebbleMarkers = {0x034a9, 0x034b1, 0x034be, 0x034c4}; + // _serializer.WritePuzzle(p, 0x19E7); } diff --git a/Source/Randomizer2Core.cpp b/Source/Randomizer2Core.cpp index 0310ae2..c34fec6 100644 --- a/Source/Randomizer2Core.cpp +++ b/Source/Randomizer2Core.cpp @@ -77,15 +77,22 @@ std::vector Randomizer2Core::CutEdgesInternal(const Puzzle& p, std::vector< return cutEdges; } +#ifndef NDEBUG +#include +#endif + void Randomizer2Core::DebugColorGrid(const std::vector>& colorGrid) { +#ifndef NDEBUG for (int y=0; y>& colorGrid, int color, int x, int y) { @@ -102,7 +109,7 @@ void Randomizer2Core::FloodFill(const Puzzle& p, std::vector>& void Randomizer2Core::FloodFillOutside(const Puzzle& p, std::vector>& colorGrid, int x, int y) { if (!p.SafeCell(x, y)) return; if (colorGrid[x][y] != 0) return; // Already processed. - if (x%2 != y%2 && p.grid[x][y].gap != Cell::Gap::FULL) return; // Only flood-fill through full gaps + if (x%2 != y%2 && p.grid[x][y].gap == Cell::Gap::NONE) return; // Only flood-fill through gaps colorGrid[x][y] = 1; // Outside color FloodFillOutside(p, colorGrid, x, y+1); diff --git a/Test/RandomTests.cpp b/Test/RandomTests.cpp index a4fd410..20a86e5 100644 --- a/Test/RandomTests.cpp +++ b/Test/RandomTests.cpp @@ -32,4 +32,12 @@ TEST(RandomTests, SeedChangesInitialValue) { int random3 = Random::RandInt(0, 1 << 30); ASSERT_NE(random3, random1); ASSERT_NE(random3, random2); +} + +TEST(RandomTests, EvenOdd) { + std::vector outputs; + for (int i=0; i<100; i++) { + outputs.emplace_back(Random::RandInt(0, 1)); + } + int k = 0; } \ No newline at end of file -- cgit 1.4.1