Skip to content

Commit 4c1db3f

Browse files
authored
Merge pull request #590 from aspizu/randintExcept
Switching to "random backdrop" should always select a different backdrop (Closes #521)
2 parents d94bdc7 + 763e821 commit 4c1db3f

File tree

7 files changed

+96
-11
lines changed

7 files changed

+96
-11
lines changed

src/blocks/looksblocks.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -964,8 +964,9 @@ void LooksBlocks::randomBackdropImpl(VirtualMachine *vm)
964964
if (Stage *stage = vm->engine()->stage()) {
965965
std::size_t count = stage->costumes().size();
966966

967-
if (count > 0)
968-
stage->setCostumeIndex(rng->randint(0, count - 1));
967+
if (count > 1) {
968+
stage->setCostumeIndex(rng->randintExcept(0, count - 1, stage->costumeIndex()));
969+
}
969970
}
970971
}
971972

src/engine/internal/irandomgenerator.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ class IRandomGenerator
1212

1313
virtual long randint(long start, long end) const = 0;
1414
virtual double randintDouble(double start, double end) const = 0;
15+
virtual long randintExcept(long start, long end, long except) const = 0;
1516
};
1617

1718
} // namespace libscratchcpp

src/engine/internal/randomgenerator.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,29 @@ double RandomGenerator::randintDouble(double start, double end) const
4141
std::uniform_real_distribution<double> distribution(start, end);
4242
return distribution(*m_generator);
4343
}
44+
45+
long RandomGenerator::randintExcept(long start, long end, long except) const
46+
{
47+
if (start > end) {
48+
std::swap(start, end);
49+
}
50+
51+
if (except < start || except > end) {
52+
return randint(start, end);
53+
} else if (start == end) {
54+
return start;
55+
} else if (end - start == 1) {
56+
if (except == start)
57+
return end;
58+
else
59+
return start;
60+
}
61+
62+
if (randint(0, 1) == 0) {
63+
std::uniform_int_distribution<long> distribution(start, except - 1);
64+
return distribution(*m_generator);
65+
} else {
66+
std::uniform_int_distribution<long> distribution(except + 1, end);
67+
return distribution(*m_generator);
68+
}
69+
}

src/engine/internal/randomgenerator.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ class RandomGenerator : public IRandomGenerator
2020

2121
long randint(long start, long end) const override;
2222
double randintDouble(double start, double end) const override;
23+
long randintExcept(long start, long end, long except) const;
2324

2425
private:
2526
static std::shared_ptr<RandomGenerator> m_instance;

test/blocks/looks_blocks_test.cpp

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1992,7 +1992,7 @@ TEST_F(LooksBlocksTest, SwitchBackdropToImpl)
19921992
LooksBlocks::rng = &rng;
19931993

19941994
EXPECT_CALL(m_engineMock, startBackdropScripts(stage.costumeAt(3)->broadcast(), &thread, false));
1995-
EXPECT_CALL(rng, randint(0, 5)).WillOnce(Return(3));
1995+
EXPECT_CALL(rng, randintExcept(0, 5, 0)).WillOnce(Return(3));
19961996
stage.setCostumeIndex(0);
19971997
vm->setBytecode(bytecode15);
19981998
vm->run();
@@ -2001,7 +2001,7 @@ TEST_F(LooksBlocksTest, SwitchBackdropToImpl)
20012001
ASSERT_EQ(stage.costumeIndex(), 3);
20022002

20032003
EXPECT_CALL(m_engineMock, startBackdropScripts(stage.costumeAt(5)->broadcast(), &thread, false));
2004-
EXPECT_CALL(rng, randint(0, 5)).WillOnce(Return(5));
2004+
EXPECT_CALL(rng, randintExcept(0, 5, 3)).WillOnce(Return(5));
20052005
vm->reset();
20062006
vm->run();
20072007

@@ -2011,7 +2011,7 @@ TEST_F(LooksBlocksTest, SwitchBackdropToImpl)
20112011
stage.addCostume(std::make_shared<Costume>("random backdrop", "b7", "svg"));
20122012

20132013
EXPECT_CALL(m_engineMock, startBackdropScripts(stage.costumeAt(6)->broadcast(), &thread, false));
2014-
EXPECT_CALL(rng, randint).Times(0);
2014+
EXPECT_CALL(rng, randintExcept).Times(0);
20152015
vm->reset();
20162016
vm->run();
20172017

@@ -2337,7 +2337,7 @@ TEST_F(LooksBlocksTest, SwitchBackdropToAndWaitImpl)
23372337
LooksBlocks::rng = &rng;
23382338

23392339
EXPECT_CALL(m_engineMock, startBackdropScripts(stage.costumeAt(3)->broadcast(), &thread, true));
2340-
EXPECT_CALL(rng, randint(0, 5)).WillOnce(Return(3));
2340+
EXPECT_CALL(rng, randintExcept(0, 5, 0)).WillOnce(Return(3));
23412341
stage.setCostumeIndex(0);
23422342
vm->resolvePromise();
23432343
vm->setBytecode(bytecode15);
@@ -2349,7 +2349,7 @@ TEST_F(LooksBlocksTest, SwitchBackdropToAndWaitImpl)
23492349
ASSERT_EQ(stage.costumeIndex(), 3);
23502350

23512351
EXPECT_CALL(m_engineMock, startBackdropScripts(stage.costumeAt(5)->broadcast(), &thread, true));
2352-
EXPECT_CALL(rng, randint(0, 5)).WillOnce(Return(5));
2352+
EXPECT_CALL(rng, randintExcept(0, 5, 3)).WillOnce(Return(5));
23532353
vm->reset();
23542354
vm->run();
23552355
vm->resolvePromise();
@@ -2361,7 +2361,7 @@ TEST_F(LooksBlocksTest, SwitchBackdropToAndWaitImpl)
23612361
stage.addCostume(std::make_shared<Costume>("random backdrop", "b7", "svg"));
23622362

23632363
EXPECT_CALL(m_engineMock, startBackdropScripts(stage.costumeAt(6)->broadcast(), &thread, true));
2364-
EXPECT_CALL(rng, randint).Times(0);
2364+
EXPECT_CALL(rng, randintExcept).Times(0);
23652365
vm->reset();
23662366
vm->run();
23672367
vm->resolvePromise();
@@ -2488,16 +2488,17 @@ TEST_F(LooksBlocksTest, RandomBackdrop)
24882488
RandomGeneratorMock rng;
24892489
LooksBlocks::rng = &rng;
24902490

2491-
EXPECT_CALL(rng, randint).Times(0);
2491+
EXPECT_CALL(rng, randintExcept).Times(0);
24922492
vm->run();
24932493

24942494
ASSERT_EQ(vm->registerCount(), 0);
24952495

24962496
stage.addCostume(std::make_shared<Costume>("backdrop1", "b1", "svg"));
24972497
stage.addCostume(std::make_shared<Costume>("backdrop2", "b2", "svg"));
24982498
stage.addCostume(std::make_shared<Costume>("backdrop3", "b3", "svg"));
2499+
stage.setCostumeIndex(0);
24992500

2500-
EXPECT_CALL(rng, randint(0, 2)).WillOnce(Return(1));
2501+
EXPECT_CALL(rng, randintExcept(0, 2, 0)).WillOnce(Return(1));
25012502
EXPECT_CALL(m_engineMock, startBackdropScripts(stage.costumeAt(1)->broadcast(), &thread, false));
25022503
vm->reset();
25032504
vm->run();
@@ -2507,7 +2508,7 @@ TEST_F(LooksBlocksTest, RandomBackdrop)
25072508

25082509
stage.addCostume(std::make_shared<Costume>("backdrop4", "b4", "svg"));
25092510

2510-
EXPECT_CALL(rng, randint(0, 3)).WillOnce(Return(2));
2511+
EXPECT_CALL(rng, randintExcept(0, 3, 1)).WillOnce(Return(2));
25112512
EXPECT_CALL(m_engineMock, startBackdropScripts(stage.costumeAt(2)->broadcast(), &thread, false));
25122513
vm->reset();
25132514
vm->run();

test/mocks/randomgeneratormock.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ class RandomGeneratorMock : public IRandomGenerator
1010
public:
1111
MOCK_METHOD(long, randint, (long, long), (const, override));
1212
MOCK_METHOD(double, randintDouble, (double, double), (const, override));
13+
MOCK_METHOD(long, randintExcept, (long, long, long), (const, override));
1314
};

test/randomgenerator/randomgenerator_test.cpp

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,57 @@ TEST(RandomGeneratorTest, RandIntDouble)
4343
ASSERT_LE(num, 5.081);
4444
}
4545
}
46+
47+
TEST(RandomGeneratorTest, RandIntExcept)
48+
{
49+
auto rng = RandomGenerator::instance();
50+
ASSERT_TRUE(rng);
51+
52+
long num;
53+
54+
for (int i = 0; i < 25; i++) {
55+
num = rng->randintExcept(-2, 3, 0);
56+
ASSERT_GE(num, -2);
57+
ASSERT_LE(num, 3);
58+
ASSERT_NE(num, 0);
59+
}
60+
61+
for (int i = 0; i < 25; i++) {
62+
num = rng->randintExcept(5, -3, 2);
63+
ASSERT_GE(num, -3);
64+
ASSERT_LE(num, 5);
65+
ASSERT_NE(num, 2);
66+
}
67+
68+
for (int i = 0; i < 25; i++) {
69+
num = rng->randintExcept(5, 8, 2);
70+
ASSERT_GE(num, 5);
71+
ASSERT_LE(num, 8);
72+
}
73+
74+
for (int i = 0; i < 25; i++) {
75+
num = rng->randintExcept(5, 8, 10);
76+
ASSERT_GE(num, 5);
77+
ASSERT_LE(num, 8);
78+
}
79+
80+
for (int i = 0; i < 25; i++) {
81+
num = rng->randintExcept(2, 2, 2);
82+
ASSERT_EQ(num, 2);
83+
}
84+
85+
for (int i = 0; i < 25; i++) {
86+
num = rng->randintExcept(2, 2, 5);
87+
ASSERT_EQ(num, 2);
88+
}
89+
90+
for (int i = 0; i < 25; i++) {
91+
num = rng->randintExcept(1, 2, 1);
92+
ASSERT_EQ(num, 2);
93+
}
94+
95+
for (int i = 0; i < 25; i++) {
96+
num = rng->randintExcept(1, 2, 2);
97+
ASSERT_EQ(num, 1);
98+
}
99+
}

0 commit comments

Comments
 (0)