Got a question that the wiki doesn't answer? Ask on the forum (preferred), or join us on IRC.



From Wiki
Jump to: navigation, search

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:

1   msg('Hello World!');
2   msg('Hello World!');
3   msg('Hello World!');
4   msg('Hello World!');
5   msg('Hello World!');

Now say we want to do it 6 times.

1   msg('Hello World!');
2   msg('Hello World!');
3   msg('Hello World!');
4   msg('Hello World!');
5   msg('Hello World!');
6   msg('Hello World!');

Doing this continually would work, but if the number of times it is run can be dynamic, this approach won't work. The looping functions can be used to dynamically run code a given number of times. The for() function can be used to rewrite the same code as above in just a few lines:


1   for(@i = 0, @i < 5, @i++){
2        msg('Hello World!');
3   }

First of all, let's look at the inner parts. @i = 0 assigns 0 to the variable @i. This bit of code is run only once, and at the beginning of the loop. Since = returns a variable, and for() requires the first parameter to be a variable, this works out perfect. Next, is the less than. Essentially, in English, this says "while @i is less than 5, run the code". This condition is checked at the start of each iteration of the loop, (including the first) and if it is true, the code is run again. @i++ adds one to @i, and stores the value back in the variable. This is run each time at the end of the loop, and is not required to return a value. 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.

1   for(@i = 1, @i <= 10, @i++){
2        msg(@i);
3   }

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.

1   for(@i = 0, @i < $userInput@i++){
2        msg(@i);
3   }

Or, maybe we want to count down:

1   for(@i = $userInput@i >= 0, @i--){
2        msg(@i);
3   }

Often times you're looping through an array. Perhaps we want to print all the words in this array:

1   @array = array('one''two''three''four''five''six''seven''eight''nine''ten');
2   for(@i = 0, @i < array_size(@array), @i++){
3        msg(@array[@i]);
4   }


While that last example 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:

1   foreach(@val in @array){
2        msg(@val);
3   }

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.

1   @array = array(key1: 'val1', key2: 'val2', key3: 'val3');
2   foreach(@value in @array){
3        msg(@value); # Messages 'val1', 'val2', 'val3'
4   }

What if you are also interested in messaging out the key of the array? You can use array_keys() to get them, or use the special key parameter of foreach.

1   foreach(@key@value in @array){
2        msg(@key . ': ' . @value); # Messages 'key1: val1', 'key2: val2', 'key3: val3'
3   }

Another common task with arrays is to do one thing if the array is empty, or loop through it if it isn't. You could check the array size and have an if/else statement, but since this is a common enough task, special syntax exists.

1   foreach(@value in @array){
2      msg('This code runs for each element in the array, if the array isn\&apos;t empty');
3   } else {
4      msg('This code runs only if the array is empty');
5   }

foreach() also has other forms, though only the "foreach([@key:]@value in @array)" format is recommended. You may also use the no-keywords method:

1   // Without key
2   foreach(@array@value){
3      //
4   }
6   // With key
7   foreach(@array@key@value){
8      //
9   }

or the "as" keyword method:

1   // Without key
2   foreach(@array as @value){
3      //
4   }
6   // With key
7   foreach(@array as @key@value){
8      //
9   }

or the no-brace method (old style):

1   // Without key
2   foreach(@array@value,
3      code()
4   )
6   // With key
7   foreach(@array@key@value,
8      code()
9   )

Note: Modifications to the array being iterated are handled specially. Read the page on array iteration for full details.


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, and you aren't using an array. In that case, you can use a while loop, and you control all the conditions except for loop decision value.

1   @times = 10;
2   while(@times > 0){
3       @times = @times - rand(2);
4       msg(@times);
5   }

You can also make an "infinite" loop with a while(true) loop, and control stopping the loop with continue() and break().

01   while(true){
02       if(rand(5) == 0){
03           msg('rand returned 0, breaking!');
04           break();
05       }
06       if(rand(5) > 3){
07           continue();
08       }
09       msg('Looping!');
10   }

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(), continue() moves to the next index).


Note: dowhile() does not currently support brace syntax. This feature will be added later.

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.

break() and continue()

Breaking and continuing in a loop works will all 4 loop types, for, foreach, while, and dowhile. A break causes the loop to exit immediately, and a continue causes that particular iteration to finish, and the loop restarts. Both break and continue can be given a counter as well, and they will do that operation that many times. break() must have a hardcoded integer value, however, as a dynamic value prevents code flow analysis and optimizations. Continuing can be done a dynamic number of times, and essentially works like this:

01   @cont = 0;
02   for(@i = 0, @i < 10, @i++){
03      if(@cont > 0){
04         @cont--;
05         continue();
06      } else if(@i == 1){
07         @cont = 2;
08         continue();
09      }
10      msg(@i);
11   }
12   // This would message out 0, 4, 5, 6, 7, 8, 9
13   // But the same code can be written in less code, and less confusingly with:
15   for(@i = 0, @i < 10, @i++){
16      if(@i == 1){
17         continue(3);
18      }
19      msg(@i);
20   }

Breaks with more than 1 break out of multiple loops.

01   @output = array();
02   for(@i = 0, @i < 5, @i++){
03      for(@j = 0, @j < 5, @j++){
04         if(@i == 2 && @j == 3){
05            break(2);
06         }
07         @output[] = "@i @j";
08      }
09   }
10   msg(@output); // {0 0, 0 1, 0 2, 0 3, 0 4, 1 0, 1 1, 1 2, 1 3, 1 4, 2 0, 2 1, 2 2}

Breaks follow special rules, however. Breaks cannot bubble up past procedures, closures, or the root of the script. Since the break count must be hardcoded, the compiler will catch this at compile time, and cause an error.

Break may also be used with switch statements. In this case, breaks work the same as if switch were a loop, even though it is technically a conditional, and not a loop.

Navigation menu