First time here? Check out the FAQ!

Why do I keep getting the same value from nextRandomIndexOf: ?

0 votes

In this code below I keep getting the same value for nextRandomIndexOf:

When I first compile and run the Sound the first time I press the !Randomise button in the VCS a get a random value but every subsequent time I press the button I get the same value again.


If I change the second occurrance of !Randomise to !Gate, it kind of works but not reliably. That is if I change the second to last line to:

(!Randomise true: (register @< 0) <+ (!Gate nextRandomElementOf: values) false: nil),

it does change when I press !Randomise... fairly often but not 100%.

And if I align !Randomise with !Gate it stops working again:

((!Randomise alignWith: !Gate) true: (register @< 0) <+ (!Gate nextRandomElementOf: values) false: nil),

What should I put infront of nextRandomElementOf: to make it give a new random value every time I click on the !Randomise button?


Here's the whole code for cutting and pasting:

| register registerSize registerValue shiftExpression  values  |

"The size of the shift register"
registerSize := 8.

"The set of possible register values"
values := #(3 {5/4} {4/3} {3/2} {9/5} 2 {18/8} {12/5}).

register := EventVariable new size: registerSize.
registerValue := EventVariable new initialValue: 0.

"construct the expression that shifts the register by one place"
shiftExpression := registerValue <+ (register @< 0).

shiftExpression := (0 to: (registerSize - 2)) inject: shiftExpression into: [:expr :i|
    (expr, ((register @< i) <+ (register @< (i + 1))))].

shiftExpression := shiftExpression, ((register @< (registerSize -1)) <+ registerValue).


(!Gate switchedOn evaluate: shiftExpression),
(!Randomise true: (register @< 0) <+ (!Randomise nextRandomElementOf: values) false: nil),
(register @< 0).


asked Nov 26, 2018 in Capytalk & Smalltalk by alan-jackson (Master) (8,710 points)
Instead of using !Randomise as both the conditional and the trigger for nextRandomElementOf:, you could try selecting the random element first, store in an EventVariable and then select either 0 or the EventVariable in the conditional. For example,

(!Gate switchedOn evaluate: shiftExpression),
(randVal <+ (!Randomise nextRandomElementOf: values)),
(!Randomise true: (register @< 0) <+ randVal false: nil),
(register @< 0).
That works, thanks!

I can't understand why though. Why can't I use !Randomise as both the conditional and the trigger without using an intermediate variable?

The code above is a simplified version for the question. In my real code I'm randomising the whole register array, which means I'm now constructing an intermediate EventVariable array to hold the random values and then copying the values from that array into the register array when !Randomise is true. It is working but it is getting a bit big too.
If you think of the expression as:
   "a" true: "some function of a here" false: "b"
you can see that "some function of a here" will be evaluated only when "a" is true.

Since the receiver of the nextRandomElementOf: message (!Randomise, in this case) needs to become false and then true again before a new random element is selected, this means that a new element will be chosen only once.
Oooooh. Thank you! That really really helps my mental model of what's going on.

Does that mean that something like this would work?:

(!a switchedOn) turnOnAfter: 0 s for: 0.002 s
        ((!a switchedOn) turnOnAfter: 0 s for: 0.001 s) nextRandomElementOf: b
Yes, that should work.
I think you've answered my question, thank you. I can't promote your comment to an answer, so I can't mark this question as answered.

Please log in or register to answer this question.