4

I am creating a mini housie game in scratch and I have used the pick random block to pick between 1 and 27. And I have 27 backdrops with 1 to 27 numbers written on them. However I notice that after about 21-22 numbers the random picker is not able to pick any of the remaining numbers. Below is how my code looks like - enter image description here

How can I fix this code so as to make sure it picks everything from 1 to 27 randomly?

user979189
  • 1,230
  • 2
  • 15
  • 39
  • 2
    It probably is doing it randomly. Obviously, 21-22 runs isn't enough to test. Did you run 500 times and see if every number was hit? Which numbers aren't being used? – Garr Godfrey Aug 03 '19 at 01:38
  • @Garr: the script shown above will loop indefinitely each time the space key is pressed, until a random number that hasn't already been selected is picked. It should take exactly 27 trials to choose all 27 numbers. Granted, it's not an _efficient_ way to do that (shuffling the list would be much better), but it should work. – Peter Duniho Aug 03 '19 at 01:44
  • That's not how random numbers work. It isn't a generator that evenly distributes numbers. It's random. If you roll 6 dice, you won't likely get one of each number. – Garr Godfrey Aug 03 '19 at 01:50
  • but I see what you are saying. 27 times hitting the spacebar. You are saying the 23rd time it freezes? How long did you wait? – Garr Godfrey Aug 03 '19 at 01:52
  • my best guess is it really ran 27 times, but some of the spacebar presses resulted in it running twice quickly so you didn't see them. I believe scratch works by polling, so holding down space would make it run more than once – Garr Godfrey Aug 03 '19 at 01:54
  • 1
    @Garr: the script is running exactly once per spacebar press. That's not the issue. The problem is in the way Scratch implements the "contains" block. See my answer below. – Peter Duniho Aug 03 '19 at 02:45

1 Answers1

6

Your problem is due to how the "contains" block works. It is natural to assume that it would compare the value you give it to each value in the list, and would evaluate to "true" if there's a match and "false" if there's not. But unfortunately, that's not what it does. Instead, it treats the list as a single string formed by concatenating all of the elements in the list (separating each element with a space), and then checks to see if the thing you asked was contained by the list is in that string.

You can see this in action if you run this snippet:

enter image description here

You'll find that your sprite does in fact say "Hello", even though the list definitely does not contain "2 3" anywhere!

In your script, this has the effect of excluding some of the single-digit numbers, depending on what order the numbers are chosen. For example, the number 1 is highly unlikely to be picked, because almost half the numbers you could pick have the digit 1 in them. Likewise 2. The other digits have much lower chances of being excluded, but it's a non-zero chance, and at least some of them tend to be excluded for the same reason.

In other words, by the time you get to around 20 to 22 of the 27 numbers picked, the rest of the numbers that are left will be treated as though they were picked, even though they weren't.

You can get your script to work if you implement a proper "contains" block, like this:

enter image description here

Then you can use it in your main script like this:

enter image description here All that said, your approach to picking random numbers isn't ideal, because you have to do this looping and repeatedly picking and ignoring some numbers, more and more as the loop progresses. This can become entirely intractable if you start having to pick from a larger range of numbers.

It would be better to implement as a proper "shuffle". There's a standard algorithm for this, called the Fisher-Yates shuffle. Essentially, you initialize your list with all the numbers you want to choose from, start at the first element, pick a random other element to swap with that element (the element you're on could be picked), swap the values, and then move on to the next element. With each iteration, you're picking a new element only from those remaining in the list.

I leave the implementation of the Fisher-Yates shuffle in your Scratch program to you and other readers. It's an excellent programming exercise. :)

Peter Duniho
  • 68,759
  • 7
  • 102
  • 136