articy:draft

articy:draft

Not enough ratings
Make Your Own Pseudo-Random Number Generator in articy:draft
By Elyziuz
articy:draft does not come with a built-in random number generator, but you can build one yourself if you absolutely need it for your project.

This guide is in English, but on the developers' advice, I've checked all the language tags to make my guide visible to everyone regardless of their native language.
   
Award
Favorite
Favorited
Unfavorite
Introduction
Pseudo-random number generators are commonly referred to as RNGs. Many videogames use them. Some users of articy:draft may wish to see how well their game mechanics integrate RNG. Even though articy:draft does not come with a built-in pseudo-random generator, nothing prevents us from scripting one. This guide will show you how.

The algorithm that we will implement is the linear congruential generator, a quick and dirty method that gets the job done. It generates pseudo-random numbers fast, but it's far from being scientifically reliable. There are much better algorithms out there, but they all require integer arrays, which articy:draft does not implement. Given the limitations of the software, the linear congruential generator is our best shot at scripting RNGs in articy:draft.
The Algorithm vs. the Limitations of articy
Before we get into the actual walkthrough, let's spend some time learning about the linear congruential algorithm and the challenges of implementing it in articy. We won't delve into the mathematics of the algorithm, so if you want to know more about it, you can get look it up in the Wikipedia[en.wikipedia.org].

If we were to implement the algorithm in C, it would look something like this:

const unsigned long long m = 2147483648; // the modulus const unsigned long long a = 214013; // the multiplier const unsigned long long c = 2531011; // the increment // The seed number is any number between 0 to (m - 1). // This value should manually be changed each time the program is run // to generate a different sequence of pseudo-random numbers. unsigned long long seed = 5323; unsigned int genRandom() { seed = (a * seed + c) % m; // Use only bits 30..16 of seed for the random number. unsigned long long randomNum = (seed >> 15) & 32767; return (unsigned int) randomNum; } int main() { // Generate a pseudo-random number from 1 to 100. unsigned int d100 = genRandom() % 100 + 1; }

The above code assumes that unsigned long long is a 64-bit unsigned integer. It's big enough to handle the math involved without overflow. In articy, however, integers are only 32 bits long and can go into the negative as well as the positive range. If we were to implement the algorithm as is, we're likely to wind up with negative numbers due to integer overflow. In addition, there are no bit-wise operators in articy. That's kind of inconvenient as having them would have made it easier for us to select which bits of the seed variable to use in generating our pseudo-random number.

That said, these limitations are nothing more than inconveniences. We can still work around them.
Scripting the RNG in articy
The first step is to create some global variables that our RNG will use. In this walkthrough, we're going to call our variable set "RNGVars."


All the variables in the set are integers. They are as follows:

Seed
This is the initial number for seeding the algorithm. The seed value is any number between 0 to 2147483647. This should manually be changed each time a journey is begun to generate a different sequence.
Random
This is the pseudo-random number that our algorithm will generate.
DiceRoll
This variable isn't integral to the algorithm itself. It is just provided for converting Random to a desired range, such as 1 to 100. Feel free to leave it out or transfer it to some other variable set.

Next, go to the flow view and create a new flow fragment called "Generate Random Number." You can add a description to it if you like.


As you can see from the above picture, this flow fragment will be a container for the parts of the flow that implement the RNG. Submerge into this flow fragment to start building its inner content. By the time we're done, the flow at the submerged level should look like the following:


The first block in this submerged level is an instruction, which should look like the following image.


Create the instruction and connect the parent node's inbound pin to the inbound pin of this instruction. Write the following code in it:

// Linear congruential generator RNGVars.Seed = 214013 * RNGVars.Seed + 2531011

Next, create a new condition and connect the instruction's outbound pin to the condition's inbound pin. Write the following code in it:

// Seed = Seed % 2147483648 // Seed will be in the range [0, 2147483647] RNGVars.Seed < 0

As can be seen in the following picture, the green output pin of this condition has a script embedded in it.


Double-click the green output pin and write the following code in the window that appears:

RNGVars.Seed += 1; RNGVars.Seed += 2147483647;


Click OK when you're done.

This entire condition is actually our workaround for implementing Seed = Seed % 2147483648. Because of integer overflow, there's a chance that Seed will contain a negative value. Since Seed is a 32-bit integer, we know that its range of values is within -2147483648 to 2147483647. If the value of Seed is greater than or equal to zero, then the operation (Seed % 2147483648) will return the original value of Seed. If the value of Seed is less than zero, then adding 2147483648 to it would result in the same value if we had done the modulo operation using unsigned 64-bit integers. Recall, however, that the maximum value of a signed 32-bit integer is 2147483647. Therefore, to add 2147483648 to Seed, we first add 2147483647 to it, then we add 1. Those are some of the hoops we have to jump through to implement our RNG in articy.

If that last paragraph confused you, don't worry about it. As long as you follow these instructions to the letter, you should be fine.

Next, we create another instruction and connect both outbound pins of the previous condition to the inbound pin of our new instruction. Write the following script in this instruction:

// Use only bits 30 to 16 to generate a random number from 0 to 32767. RNGVars.Random = RNGVars.Seed / 32768


Create a second condition and connect the outbound pin of the last instruction to the inbound pin of this new condition. Enter the following code in it:

RNGVars.Random > 32767


The above picture shows how this last condition looks. Notice that its green outbound pin is lit up, indicating that it has code embedded in it. Double-click the green outbound pin and write the following script in the window that appears:

RNGVars.Random -= 32768


Click OK when you're done.

Finally, connect both outbound pins of this condition to the outbound pin of the parent node.

You may be wondering, what was that all about? The last instruction and condition are for implementing the following code in articy if only articy had bitwise operations:

RNGVars.Random = (RNGVars.Seed >> 15) & 32767

Alas, there are no bitwise operations in articy, so we had to jump through a few more hoops to work around this limitation.

At this point, give yourself a pat in the back. You now have your very own RNG in articy. Hooray.
Pseudo-Dice Rolls
The RNG that we just created will generate a pseudo-random number from 0 to 32767. The game you're designing will probably require a different range of random numbers, such as 1 to 100 for d100 or 1 to 6 for d6. You can convert the pseudo-random number to a different range of numbers with the following operation:

RNGVars.DiceRoll = RNGVars.Random % RANGE + LOWER_LIMIT

RANGE should be a number representing your desired range of random numbers, and LOWER_LIMIT is the lowest value of that range. The following picture shows how you can implement a d100 die roll:


This concludes my guide on creating a pseudo-random number generator in articy. Have fun with your RNG.
3 Comments
Benjiboy 10 Oct, 2017 @ 11:37pm 
Excellent stuff Elyziuz. Just what I needed for a gamebook project :)
Articy | Peter Sabath  [developer] 15 Sep, 2016 @ 5:22am 
Many thanks for sharing this great guide.
JeFawk 5 Sep, 2016 @ 2:35pm 
This is really clever, thanks for sharing!