From 0dbe6a0506fff756a7a4050445a36e898a398abb Mon Sep 17 00:00:00 2001 From: aspizu Date: Sat, 5 Oct 2024 03:39:24 +0530 Subject: [PATCH 1/7] Implement method randintExcept for RandomGenerator. --- src/engine/internal/irandomgenerator.h | 1 + src/engine/internal/randomgenerator.cpp | 13 +++++++++++ src/engine/internal/randomgenerator.h | 1 + test/randomgenerator/randomgenerator_test.cpp | 22 +++++++++++++++++++ 4 files changed, 37 insertions(+) diff --git a/src/engine/internal/irandomgenerator.h b/src/engine/internal/irandomgenerator.h index c8d4a177..2228c933 100644 --- a/src/engine/internal/irandomgenerator.h +++ b/src/engine/internal/irandomgenerator.h @@ -12,6 +12,7 @@ class IRandomGenerator virtual long randint(long start, long end) const = 0; virtual double randintDouble(double start, double end) const = 0; + virtual long randintExcept(long start, long end, long except) const = 0; }; } // namespace libscratchcpp diff --git a/src/engine/internal/randomgenerator.cpp b/src/engine/internal/randomgenerator.cpp index 06e169e7..84cca982 100644 --- a/src/engine/internal/randomgenerator.cpp +++ b/src/engine/internal/randomgenerator.cpp @@ -41,3 +41,16 @@ double RandomGenerator::randintDouble(double start, double end) const std::uniform_real_distribution distribution(start, end); return distribution(*m_generator); } + +long RandomGenerator::randintExcept(long start, long end, long except) const +{ + if (start > end) { + std::swap(start, end); + } + std::uniform_int_distribution distribution(start, end); + long value = distribution(*m_generator); + if (value == except) { + return randintExcept(start, end, except); + } + return value; +} diff --git a/src/engine/internal/randomgenerator.h b/src/engine/internal/randomgenerator.h index 6cb72586..1358de37 100644 --- a/src/engine/internal/randomgenerator.h +++ b/src/engine/internal/randomgenerator.h @@ -20,6 +20,7 @@ class RandomGenerator : public IRandomGenerator long randint(long start, long end) const override; double randintDouble(double start, double end) const override; + long randintExcept(long start, long end, long except) const; private: static std::shared_ptr m_instance; diff --git a/test/randomgenerator/randomgenerator_test.cpp b/test/randomgenerator/randomgenerator_test.cpp index 45f220af..fe327c81 100644 --- a/test/randomgenerator/randomgenerator_test.cpp +++ b/test/randomgenerator/randomgenerator_test.cpp @@ -43,3 +43,25 @@ TEST(RandomGeneratorTest, RandIntDouble) ASSERT_LE(num, 5.081); } } + +TEST(RandomGeneratorTest, RandInt) +{ + auto rng = RandomGenerator::instance(); + ASSERT_TRUE(rng); + + long num; + + for (int i = 0; i < 25; i++) { + num = rng->randintExcept(-2, 3, 0); + ASSERT_GE(num, -2); + ASSERT_LE(num, 3); + ASSERT_NE(num, 0); + } + + for (int i = 0; i < 25; i++) { + num = rng->randintExcept(5, -3, 2); + ASSERT_GE(num, -3); + ASSERT_LE(num, 5); + ASSERT_NE(num, 2); + } +} From 9f358599b2af2b8fab680b69dc34d8dd91d2cf98 Mon Sep 17 00:00:00 2001 From: aspizu Date: Sat, 5 Oct 2024 03:47:05 +0530 Subject: [PATCH 2/7] Always select a different random backdrop. (Closes #521) --- src/blocks/looksblocks.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/blocks/looksblocks.cpp b/src/blocks/looksblocks.cpp index 5d2cf55a..da77cc3c 100644 --- a/src/blocks/looksblocks.cpp +++ b/src/blocks/looksblocks.cpp @@ -964,8 +964,9 @@ void LooksBlocks::randomBackdropImpl(VirtualMachine *vm) if (Stage *stage = vm->engine()->stage()) { std::size_t count = stage->costumes().size(); - if (count > 0) - stage->setCostumeIndex(rng->randint(0, count - 1)); + if (count > 0) { + stage->setCostumeIndex(rng->randintExcept(0, count - 1, stage->costumeIndex())); + } } } From 495f1309e9241c321539a70a7ed2ffcdbe805767 Mon Sep 17 00:00:00 2001 From: aspizu Date: Sat, 5 Oct 2024 03:56:44 +0530 Subject: [PATCH 3/7] Fix tests for randomBackdrop. --- test/blocks/looks_blocks_test.cpp | 2 +- test/mocks/randomgeneratormock.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/test/blocks/looks_blocks_test.cpp b/test/blocks/looks_blocks_test.cpp index 92c21532..ba2318bc 100644 --- a/test/blocks/looks_blocks_test.cpp +++ b/test/blocks/looks_blocks_test.cpp @@ -2507,7 +2507,7 @@ TEST_F(LooksBlocksTest, RandomBackdrop) stage.addCostume(std::make_shared("backdrop4", "b4", "svg")); - EXPECT_CALL(rng, randint(0, 3)).WillOnce(Return(2)); + EXPECT_CALL(rng, randintExcept(0, 3, 1)).WillOnce(Return(2)); EXPECT_CALL(m_engineMock, startBackdropScripts(stage.costumeAt(2)->broadcast(), &thread, false)); vm->reset(); vm->run(); diff --git a/test/mocks/randomgeneratormock.h b/test/mocks/randomgeneratormock.h index 42d6e999..6e07f881 100644 --- a/test/mocks/randomgeneratormock.h +++ b/test/mocks/randomgeneratormock.h @@ -10,4 +10,5 @@ class RandomGeneratorMock : public IRandomGenerator public: MOCK_METHOD(long, randint, (long, long), (const, override)); MOCK_METHOD(double, randintDouble, (double, double), (const, override)); + MOCK_METHOD(long, randintExcept, (long, long, long), (const, override)); }; From 367363402000ce36a39d8057b698209dd7d16408 Mon Sep 17 00:00:00 2001 From: aspizu Date: Sat, 5 Oct 2024 04:02:43 +0530 Subject: [PATCH 4/7] Only switch to a random backdrop if there are more than 1 backdrops. --- src/blocks/looksblocks.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/blocks/looksblocks.cpp b/src/blocks/looksblocks.cpp index da77cc3c..f142f34c 100644 --- a/src/blocks/looksblocks.cpp +++ b/src/blocks/looksblocks.cpp @@ -964,7 +964,7 @@ void LooksBlocks::randomBackdropImpl(VirtualMachine *vm) if (Stage *stage = vm->engine()->stage()) { std::size_t count = stage->costumes().size(); - if (count > 0) { + if (count > 1) { stage->setCostumeIndex(rng->randintExcept(0, count - 1, stage->costumeIndex())); } } From 49a1cc9db44d7af09088f48b6b65a0fcaf8f7c65 Mon Sep 17 00:00:00 2001 From: aspizu Date: Sat, 5 Oct 2024 04:03:09 +0530 Subject: [PATCH 5/7] Fix test name for RandIntExcept. --- test/randomgenerator/randomgenerator_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/randomgenerator/randomgenerator_test.cpp b/test/randomgenerator/randomgenerator_test.cpp index fe327c81..1a7fedba 100644 --- a/test/randomgenerator/randomgenerator_test.cpp +++ b/test/randomgenerator/randomgenerator_test.cpp @@ -44,7 +44,7 @@ TEST(RandomGeneratorTest, RandIntDouble) } } -TEST(RandomGeneratorTest, RandInt) +TEST(RandomGeneratorTest, RandIntExcept) { auto rng = RandomGenerator::instance(); ASSERT_TRUE(rng); From 6ffc3a74933e9423432862ce3c49780b88165fcc Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Sat, 12 Oct 2024 19:46:16 +0200 Subject: [PATCH 6/7] Update random backdrop tests --- test/blocks/looks_blocks_test.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/test/blocks/looks_blocks_test.cpp b/test/blocks/looks_blocks_test.cpp index ba2318bc..041c32b8 100644 --- a/test/blocks/looks_blocks_test.cpp +++ b/test/blocks/looks_blocks_test.cpp @@ -1992,7 +1992,7 @@ TEST_F(LooksBlocksTest, SwitchBackdropToImpl) LooksBlocks::rng = &rng; EXPECT_CALL(m_engineMock, startBackdropScripts(stage.costumeAt(3)->broadcast(), &thread, false)); - EXPECT_CALL(rng, randint(0, 5)).WillOnce(Return(3)); + EXPECT_CALL(rng, randintExcept(0, 5, 0)).WillOnce(Return(3)); stage.setCostumeIndex(0); vm->setBytecode(bytecode15); vm->run(); @@ -2001,7 +2001,7 @@ TEST_F(LooksBlocksTest, SwitchBackdropToImpl) ASSERT_EQ(stage.costumeIndex(), 3); EXPECT_CALL(m_engineMock, startBackdropScripts(stage.costumeAt(5)->broadcast(), &thread, false)); - EXPECT_CALL(rng, randint(0, 5)).WillOnce(Return(5)); + EXPECT_CALL(rng, randintExcept(0, 5, 3)).WillOnce(Return(5)); vm->reset(); vm->run(); @@ -2011,7 +2011,7 @@ TEST_F(LooksBlocksTest, SwitchBackdropToImpl) stage.addCostume(std::make_shared("random backdrop", "b7", "svg")); EXPECT_CALL(m_engineMock, startBackdropScripts(stage.costumeAt(6)->broadcast(), &thread, false)); - EXPECT_CALL(rng, randint).Times(0); + EXPECT_CALL(rng, randintExcept).Times(0); vm->reset(); vm->run(); @@ -2337,7 +2337,7 @@ TEST_F(LooksBlocksTest, SwitchBackdropToAndWaitImpl) LooksBlocks::rng = &rng; EXPECT_CALL(m_engineMock, startBackdropScripts(stage.costumeAt(3)->broadcast(), &thread, true)); - EXPECT_CALL(rng, randint(0, 5)).WillOnce(Return(3)); + EXPECT_CALL(rng, randintExcept(0, 5, 0)).WillOnce(Return(3)); stage.setCostumeIndex(0); vm->resolvePromise(); vm->setBytecode(bytecode15); @@ -2349,7 +2349,7 @@ TEST_F(LooksBlocksTest, SwitchBackdropToAndWaitImpl) ASSERT_EQ(stage.costumeIndex(), 3); EXPECT_CALL(m_engineMock, startBackdropScripts(stage.costumeAt(5)->broadcast(), &thread, true)); - EXPECT_CALL(rng, randint(0, 5)).WillOnce(Return(5)); + EXPECT_CALL(rng, randintExcept(0, 5, 3)).WillOnce(Return(5)); vm->reset(); vm->run(); vm->resolvePromise(); @@ -2361,7 +2361,7 @@ TEST_F(LooksBlocksTest, SwitchBackdropToAndWaitImpl) stage.addCostume(std::make_shared("random backdrop", "b7", "svg")); EXPECT_CALL(m_engineMock, startBackdropScripts(stage.costumeAt(6)->broadcast(), &thread, true)); - EXPECT_CALL(rng, randint).Times(0); + EXPECT_CALL(rng, randintExcept).Times(0); vm->reset(); vm->run(); vm->resolvePromise(); @@ -2488,7 +2488,7 @@ TEST_F(LooksBlocksTest, RandomBackdrop) RandomGeneratorMock rng; LooksBlocks::rng = &rng; - EXPECT_CALL(rng, randint).Times(0); + EXPECT_CALL(rng, randintExcept).Times(0); vm->run(); ASSERT_EQ(vm->registerCount(), 0); @@ -2496,8 +2496,9 @@ TEST_F(LooksBlocksTest, RandomBackdrop) stage.addCostume(std::make_shared("backdrop1", "b1", "svg")); stage.addCostume(std::make_shared("backdrop2", "b2", "svg")); stage.addCostume(std::make_shared("backdrop3", "b3", "svg")); + stage.setCostumeIndex(0); - EXPECT_CALL(rng, randint(0, 2)).WillOnce(Return(1)); + EXPECT_CALL(rng, randintExcept(0, 2, 0)).WillOnce(Return(1)); EXPECT_CALL(m_engineMock, startBackdropScripts(stage.costumeAt(1)->broadcast(), &thread, false)); vm->reset(); vm->run(); From 763e82119444e8b1d182a3c91402ae8234b92102 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Sat, 12 Oct 2024 20:34:32 +0200 Subject: [PATCH 7/7] RandomGenerator: Optimize randintExcept() --- src/engine/internal/randomgenerator.cpp | 23 ++++++++++--- test/randomgenerator/randomgenerator_test.cpp | 32 +++++++++++++++++++ 2 files changed, 50 insertions(+), 5 deletions(-) diff --git a/src/engine/internal/randomgenerator.cpp b/src/engine/internal/randomgenerator.cpp index 84cca982..e9e7c572 100644 --- a/src/engine/internal/randomgenerator.cpp +++ b/src/engine/internal/randomgenerator.cpp @@ -47,10 +47,23 @@ long RandomGenerator::randintExcept(long start, long end, long except) const if (start > end) { std::swap(start, end); } - std::uniform_int_distribution distribution(start, end); - long value = distribution(*m_generator); - if (value == except) { - return randintExcept(start, end, except); + + if (except < start || except > end) { + return randint(start, end); + } else if (start == end) { + return start; + } else if (end - start == 1) { + if (except == start) + return end; + else + return start; + } + + if (randint(0, 1) == 0) { + std::uniform_int_distribution distribution(start, except - 1); + return distribution(*m_generator); + } else { + std::uniform_int_distribution distribution(except + 1, end); + return distribution(*m_generator); } - return value; } diff --git a/test/randomgenerator/randomgenerator_test.cpp b/test/randomgenerator/randomgenerator_test.cpp index 1a7fedba..06b9dda0 100644 --- a/test/randomgenerator/randomgenerator_test.cpp +++ b/test/randomgenerator/randomgenerator_test.cpp @@ -64,4 +64,36 @@ TEST(RandomGeneratorTest, RandIntExcept) ASSERT_LE(num, 5); ASSERT_NE(num, 2); } + + for (int i = 0; i < 25; i++) { + num = rng->randintExcept(5, 8, 2); + ASSERT_GE(num, 5); + ASSERT_LE(num, 8); + } + + for (int i = 0; i < 25; i++) { + num = rng->randintExcept(5, 8, 10); + ASSERT_GE(num, 5); + ASSERT_LE(num, 8); + } + + for (int i = 0; i < 25; i++) { + num = rng->randintExcept(2, 2, 2); + ASSERT_EQ(num, 2); + } + + for (int i = 0; i < 25; i++) { + num = rng->randintExcept(2, 2, 5); + ASSERT_EQ(num, 2); + } + + for (int i = 0; i < 25; i++) { + num = rng->randintExcept(1, 2, 1); + ASSERT_EQ(num, 2); + } + + for (int i = 0; i < 25; i++) { + num = rng->randintExcept(1, 2, 2); + ASSERT_EQ(num, 1); + } }