In Inform 7, how do I implement a random number generator?
Welcome to the forums. For information about using the built-in random number generator see: WI §8.18 Randomness
The link goes to Zed’s online version of the docs, but you can also find it in the built-in docs. (Writing with Inform, Chapter 8, section 18)
The key expressions are:
a random number between X and Y, which you can use wherever a number goes, and gives a number from X to Y (inclusive)
Let x be a random number between 1 and 6;
If a random chance of X in C succeeds: …which is true X times in C (e.g.
a random chance of 1 in 3is true a third of the time), and
seed the random-number generator with 1.which you can use to set the seed.
When you’re testing it’s annoying if the random outcomes are, well, random, so in the IDE you can also set an option in the project setting tab to make the random number generator predictable. The RANDOM command does the same thing in the game.
random [name of kind of value] between [X] and [Y] works for enumerated kinds of value, too. Also, the order of X and Y don’t matter. Also, the absolute value of X minus Y must be less than the maximum positive integer for the target, i.e., 32767 (2^15 - 1) for the Z-machine or 2^31 - 1 on Glulx. (You can specify a larger range, but the results will be bad.)
a color is a kind of value. The colors are red, orange, yellow, green, blue, indigo, violet. when play begins: say a random color between orange and indigo; say a random color between blue and orange; say a random number between 3 and -3;
Seeding the random number generator with a given value will give you consistent results for a given target (Z-machine or Glulx) with a given interpreter… but these consistent sequences won’t necessarily be the same as each other across different environments. Including @Dannii 's XorShift will provide consistent results for the same starting seed independent of environment, at a modest price of extra computation time that would very likely be wholly imperceptible. (You’d be unlikely to care about this unless you’d created test suites you wanted to be usable in different environments.)
One other, other, thing I forgot is that you can use it to select random elements from a list, which is most useful when dynamically constructing a list, like:
Let P be a random person; Let B be a random ball enclosed by the ball pit; Let the owner be a random person enclosing the top hat;
Since it’s related, when you have a list, it’s often useful to shuffle it, with:
sort L in random order;
The things with which you can do
random [kind] between v1 and v2 are arithmetic values and enumerated values. Arithmetic values aren’t just numbers, it includes times and any units you have specified. Enumerated kinds of value aren’t just things defined with
X is a kind of value. Some Xes are..., but also external files, figure names, sound names, and scenes.
So these are valid:
s1, s2, s3, s4 are scenes. cash is a kind of value. $9.99 specifies a cash. weight is a kind of value. 9 lbs 15 oz specifies a weight. when play begins: say "[a random cash from $1.00 to $99.99]."; say "[a random weight from 100 lbs 0 oz to 200 lbs 15 oz]."; say "[a random time between 10:00 am and 12:00 pm]."; say "[a random scene between s2 and s4].";
But there are several other things you can iterate over with
repeat with x running through the Ks…, truth states, use options, responses, verbs, table names, action names, objects, or descriptions of values of those kinds. Given that Inform has an ordering of those things, you’d think
between would work, but it doesn’t. You can also
repeat with t running through the times, but not other arithmetic values.
Meanwhile, you can ask for
a random (description of values) using any of the things you can repeat through, but not other kinds of value that are countable for a given story like rulebooks, rules, equation names.
Does this make sense? Or should I just give up on Inform 7 and use C++ instead?
let fate_roll be a random number between 1 and 100; let destiny_roll be a random number between 1 and 100; say "Fate rolls a [fate_roll].". say "Destiny rolls a [destiny_roll].". if fate_roll >= destiny_roll: say "Fate overwhelms you. You fail the Perception Check."; else: say "You overcome Fate. You pass the Perception Check.";
It’s giving me this error:
Problem. The text ‘let fate_roll be a random number between 1 and 100’ [! is followed by a semicolon ‘;’, which only makes sense to me inside a rule or phrase (where there’s a heading, then a colon, then a list of instructions divided by semicolons). Perhaps you want a full stop ‘.’ instead?
Problem. The text ‘let destiny_roll be a random number between 1 and 100’ [! is followed by a semicolon ‘;’, which only makes sense to me inside a rule or phrase (where there’s a heading, then a colon, then a list of instructions divided by semicolons). Perhaps you want a full stop ‘.’ instead?
The trick is, you need to say when this code should run. It’s like how in C++ you can’t have code like this outside a function or method.
Instead of waiting: let…
As @Draconis says, you need to tell Inform when to make the check. This might help make that a little clearer.
Instead of jumping: say "You jump into the air ... "; Unless a fate check is passed: say "and land very badly."; End the story saying "You fell, broke your neck and were consumed by your pet cat."; otherwise: say "and land perfectly. Phew."; To decide if a fate check is passed: let fate_roll be a random number between 1 and 100; let destiny_roll be a random number between 1 and 100; if fate_roll >= destiny_roll: decide no; otherwise: decide yes;