Looping is an important programming concept, because it allows you to do something more than once, without having to rewrite the code over and over. As a simple example, perhaps we want to echo "Hello World!" 5 times to the player. The most straightforward way to do it would be this:
msg('Hello World!') msg('Hello World!') msg('Hello World!') msg('Hello World!') msg('Hello World!')
Hmm, what if we now want to do it 6 times?
msg('Hello World!') msg('Hello World!') msg('Hello World!') msg('Hello World!') msg('Hello World!') msg('Hello World!')
Hmm, well, that would work, but what if we want to allow the player to specify the number of times it is run? As you can see, this quickly becomes impossible to do without some kind of loop. Enter the
for() function. The same code written above can be condensed to just a few lines:
for(assign(@i, 0), lt(@i, 5), inc(@i), msg('Hello World!') )
Uh, ok. That added a bunch of extra stuff. Let's explain it one bit at a time. First of all, let's look at the inner parts.
assign(@i, 0) assigns 0 to the variable @i. Then, it returns the variable. for() requires the first parameter to be a variable, so this works out perfect. Next, is the less than. Essentially, in English, this says "while @i is less than 5, run the code".
inc(@i) adds one to @i, and stores the value back in the variable. So, in plain English, this entire statement says, "Starting at 0, run this code if @i is less than 5, and after each run of the code, add 1 to @i". In the code of the loop, you can also use @i, which is often useful. Say we want to write out the numbers from 1-10.
for(assign(@i, 1), lte(@i, 10), inc(@i), msg(@i) )
This can be read in English as: "Starting from 1, run the code if @i is less than or equal to 10, and add 1 to @i each time."
Most often though, when you are running through a loop, you are not going through a set number of times. So, usually you will see a variable as the limiting factor.
for(assign(@i, 0), lt(@i, $userInput), inc(@i), msg(@i) )
Or, maybe we want to count down:
for(assign(@i, $userInput), gte(@i, 0), dec(@i), msg(@i) )
Often times you're looping through an array. Perhaps we want to print all the words in this array:
assign(@array, array(one, two, three, four, five, six, seven, eight, nine, ten)) for(assign(@i, 0), lt(@i, array_size(@array)), inc(@i), msg(@array[@i]) )
While this would work, since we often want to walk through an array just like this, we have a special function just for walking through arrays,
foreach(). This code be be rewritten like so:
foreach(@array, @val, msg(@val) )
Much simpler. In fact, looping through an array with
for() is only possible if you aren't using an associative array. If you have an associative array, you MUST use
foreach() to walk through it.
assign(@array, array(key1: val1, key2: val2, key3: val3)) foreach(@array, @value, msg(@value) # Messages 'val1', 'val2', 'val3' )
What if you are also interested in messaging out the key of the array? You can use
array_keys(@array) to get them.
foreach(array_keys(@array), @key, msg(@key) # Messages 'key1', 'key2', 'key3' )
You can then use the @key to get the value at that location, if you want both.
foreach(array_keys(@array), @key, assign(@val, @array[@key]) msg(concat(@key, ' -> ', @value)) # Messages 'key1 -> val1', 'key2 -> val2', 'key3 -> val3' )
Sometimes you don't know how many times you want to do something, or the "counter" variable is otherwise too difficult to write using the for() syntax. In that case, you can use a while loop, and you control all the conditions except for loop decision value.
assign(@times, 10) while(@times > 0, assign(@times, @times - rand(2)) msg(@times) )
while(true, if(rand(5) == 0, msg('rand returned 0, breaking!') break() ) if(rand(5) > 3, continue() ) msg('Looping!') )
The above example will take an indefinite period of time, but once the first rand() generates a 0, it will break(). Otherwise, it will output "Looping!" each run of the loop, unless the second rand() generates a number greater than 3, in which case it will continue(), which restarts the loop. (And in for() and foreach() moves to the next index).
Once you understand while(), dowhile is trivial to understand. while() checks the condition THEN runs the code, whereas dowhile() runs the code THEN checks the condition. In both cases, if the condition is true, it runs again. So, while(false, <code>) will never run the code, whereas dowhile(<code>, false) will run the code only once.