SRL Archive - OSR Outdated Tutorials

[Tut] Loops


NCDS

2010-01-19 02:50:30

This tutorial will guide you through using loops in Scar(pascal). I will provide examples as well as descriptions for the following types of loops: for..to..do, while..do, repeat..until.

You should already know about variables, begin..end nests, as well as basic Scar(pascal) syntax.

for..to..do

In my opinion, the for..do..to loop is the most useful of the three I will be covering in this tutorial. The following is an example of a basic for..to..do loop.

program for_to_do;

procedure for_to_do_practice;
var
i: Integer;
begin
for i := 0 to 4 do
Writeln(IntToStr(i));
end;

begin
for_to_do_practice;
end.
This procedure would output:

0
1
2
3
4
All a for..to..do loop does is takes the value set to the variable between the "for..to" which, in this case is "i := 0", and repeats the loop, increasing the value of "i" by one each time, until "i" is equal to the value set between the "to..do" which, in this case is "4". So, as you can see, the preceding example looped through 5 times.
(NOTE: You must set a variable between "for..to" for the loop to count with. It doesn't need to equal "0", but you must change the value between "to..do" accordingly.)

Now, if I wanted to execute more that one line during my for..to..do loop, I would have to add a begin..end nest(which you should already know about, if not please resort to a more basic tutorial for now).
Example:

program for_to_do;

procedure for_to_do_practice;
var
i: Integer;
begin
for i := 0 to 4 do
begin
if i <= 2 then // if "i" is less than or equal to 2 then
Writeln(IntToStr(i)) // do this
else //otherwise
Writeln('i is greater than 2.'); // do this.
end;
end;

begin
for_to_do_practice;
end.
In this case the procedure would output:

0
1
2
i is greater than 2.
i is greater than 2.

While on this topic I will also talk briefly about for..downto..do loops. They are basically the same thing as a for..to..do loop, just counting down, instead of up.
Example:

program for_to_do;

procedure for_to_do_practice;
var
i: Integer;
begin
for i := 4 downto 0 do
Writeln(IntToStr(i));
end;

begin
for_to_do_practice;
end.
This procedure would output:

4
3
2
1
0
Simple, yet effective.
If you work with arrays at all you will find these loops to be extremely useful.


while..do
The syntax for a while..do loop is:

while Statement = True do
WhateverYouWantTheLoopToDo;
So, with a while..do loop, as long as the statement between while..do remains true, the loop will continue to repeat.

Example:

program while_do_loops;

procedure while_do_practice;
var
i: Integer;
begin
i := 0; //set the value of "i" equal to "0"
while i <= 4 do //while "i" is less than or equal to 4 do the following..
begin
Writeln(IntToStr(i));
Inc(i); //Increases the value of "i" by 1
end;
Writeln('The loop is over because i = '+IntToStr(i)+';');
end;

begin
while_do_practice;
end.
The preceding procedure would output:

0
1
2
3
4
The loop is over because i = 5;
As you can see, a while..do loop checks the statement before it executes the actual loop. Therefor, if the statement returns false, it will skip over the loop to the next part of the procedure.

Example:

program while_do_loops;

procedure while_do_practice;
var
i: Integer;
begin
i := 5; //set the value of "i" equal to "5"
while i <= 4 do //while "i" is less than or equal to 4 do the following..
begin
Writeln(IntToStr(i));
Inc(i); //Increases the value of "i" by 1
end;
Writeln('The loop is over because i = '+IntToStr(i)+';');
end;

begin
while_do_practice;
end.
In this case, because "i" is greater than 4, the compiler will skip over the loop it self, and so the output would be:

The loop is over because i = 5;


repeat..until

The repeat..until loop is pretty self-explanatory. The syntax goes as follows:

repeat
Loop;
until(Statement = True);

As you can see, unlike the while..do loop, the repeat..until loop checks the statement after the loop, therefor, the loop is guaranteed to run through at least once.

Example:

program repeat_until_loops;

procedure repeat_until_practice;
var
i: Integer;
begin
i := 0;
repeat
Writeln(IntToStr(i));
Inc(i);
until(i >= 5);
Writeln('The loop is over because i = '+IntToStr(i)+';');
end;

begin
repeat_until_practice;
end.
This procedure would output:

0
1
2
3
4
The loop is over because i = 5;
Now, keep in mind that the loop will execute at least once because it checks the statement at the end.

Example:

program repeat_until_loops;

procedure repeat_until_practice;
var
i: Integer;
begin
i := 5;
repeat
Writeln(IntToStr(i));
Inc(i);
until(i >= 5);
Writeln('The loop is over because i = '+IntToStr(i)+';');
end;

begin
repeat_until_practice;
end.
Would output:

5
The loop is over because i = 6;
As you can see, even though "i" was already equal to 5, the compiler still executed the loop once because it didn't check the statement until after the loop.


BEWARE OF INFINITE LOOPS!
An "Infinite Loop" is a loop that has a possibility of never ending.

Example:

procedure Infinite_Loop_Practice;
begin
repeat
Writeln('This loop may never end!');
until(ThisFunction);
end;
The above repeat..until loop would continue to repeat until "ThisFunction" returned true. Therefor, if something went wrong and "ThisFunction" never returned true, the loop would just continue to repeat until it was stopped manually. This can become incredibly dangerous especially if you're planning to script for RuneScape, as an Infinite loop may lead to a ban :/. So be careful!

BREAKING LOOPS
You may be wondering how you can prevent an Infinite loop.Your looking for a what is known as a "failsafe". for..to..do loop's are good for avoiding infinite loops because they have a sort of "built in" failsafe. Since, as you should know by this point, they have a set amount of times they can loop through before ending.
However, if you would prefer not to use a for..to..do loop there are a couple ways to implement your own failsafes into your loops.

Counting FailSafe

One method you could use would be counting. By "counting" I meen to increase the value of a variable to keep track of loop number. (Count each loop). This method basically just sets a limit to the containing loop.
Your going to need to know before hand a maximum amount of times you want the program to loop through before it is "too many" and you want it to stop. (or have it set to a variable and have a value passed to it during run time.) The reason I recommend a for..to..do loop is because it just saves the script writer (you) from having to increment the "counting variable" your self.
Also, make sure you understand this simple procedure:

procedure Inc(x: Integer);
All it does is increase "x" by 1.

Example of a Counting failsafe:

procedure Counting_failsafe_practice;
var
Counter: Integer; //It doesn't have to be named "counter" I just chose that for readability.
begin
Counter := 0; // Be sure to set the starting value of your "counting variable" BEFORE the loop, so it doesn't reset every time your loop goes through.
while(not (ThisFunction)) do //while ThisFunction = false do..
begin
Inc(Counter); // Increase the value of "Counter" by 1.
if Counter >= 4 then // if the value of "Counter" is greater than or equal to 4 then...
Break; //By calling this the program will now quit this loop.
end;
end;
As you can see, the above procedure will continue looping through until either ThisFunction returns true, or the value of "Counter" is 5 or greater. Which we then exit the loop by calling "Break;".

Timing FailSafe

Another type of custom failsafe you could add to your loop would be a "Timer". You can find a lot of other functions to go along with this type of failsafe in Timing.Scar. Once you get the hang of using timers you will be able to experiment with using them different ways, but for now I will just show you a basic way to do it.
First, I suggest looking over/familiarizing yourself with these two functions from Timing.Scar:

{*******************************************************************************
procedure MarkTime(var TimeMarker: Integer);
By: Stupid3ooo
Description: Sets TimeMarker to current system time
*******************************************************************************}

procedure MarkTime(var TimeMarker: Integer);
begin
TimeMarker := GetSystemTime;
end;

{*******************************************************************************
function TimeFromMark(TimeMarker: Integer): Integer;
By: Stupid3ooo
Description: returns Milliseconds since MarkTime was set
*******************************************************************************}

function TimeFromMark(TimeMarker: Integer): Integer;
begin
Result := GetSystemTime - TimeMarker;
end;
Example of a "Timing" failsafe:

procedure Timing_Failsafe_Practice;
var
Timer: Integer; // Declare our variable to track time with.
begin
MarkTime(Timer); // Sets a marker for the current time and stores it in "Timer".
repeat
Wait(100);
until((ThisFunction) or (TimeFromMark(Timer) >= 5000));
end;
Hopefully, from reading the above code you can figure out that the loop will keep going until either "ThisFunction" returns true, or our "Timer" has been going for greater than or equal to 5 seconds. Remember that the timing is measured in milliseconds so 1000 = 1 second etc.

Labels
Labels are used to skip from one part of code to another during runtime.
One thing you NEED to know is: Labels can NOT be used to break out of a loop! You will get an error.
There are three steps to using Labels that will be shown in the example below.

Example of using Labels:

procedure LabelDemo;
label Marker; //Step 1: Declare our "Marker" (to mark our "jump to" point in code)
begin
DoThis;
if ThisIsTrue then
goto Marker; //Step 2: the "goto" command tells the compiler to skip to where it finds the "Marker".
ThisFunction;
Marker: //Step 3: Set "Marker" (this is where the script will skip to. Notice the ':' When setting a "marker" for a label you will need to follow it with a colon ( : ) instead of a semicolon ( ; )
end;
In this case if the function "ThisIsTrue" returns true, it will skip over "ThisFunction" and continue to run after "Marker".

USEFUL FUNCTIONS WITH LOOPS

Continue;
'Continue;' can be a very useful little function when working with loops. By calling 'Continue;' the script will then skip to the end of the current loop. Many people seem to think it skips to the beginning, but that is false.

For example:

var
i: Integer;
begin
i := 0;
repeat
Inc(i);
Writeln(IntToStr(i));
if i = 1 then
Continue;
Writeln('i must not be 1');
until(i = 1);
end.
Would output:

Compiled succesfully in 593 ms.
1
Successfully executed.

Another example would be:

for i := 0 to High(Objects) do
begin
if FindObject(Objects[i], ...) then //Just for an example
Continue
else begin
WalkHere;
DoThis;
end;
Wait(3000);
Writeln('not found');
end;
In the above example if 'Continue;' is called, it will skip:

else begin
WalkHere;
DoThis;
end;
Wait(3000);
Writeln('not found');

And that concludes my tutorial on loops. For now, anyways.
If anyone feels I left anything out or would like me to add something please don't hesitate to say so.

Thanks for reading, hope you learned something :)

senrath

2010-01-19 03:02:50

Nice tut. Glad to see you covering the differences between while..do and repeat..until.

NCDS

2010-01-19 10:11:32

Thanks Senrath. It's the first tut I ever wrote really. I wasn't sure if I was explaining things simple enough or not.

Frement

2010-01-19 10:39:57

Cool tut, even thought i knew almost all it except the last part about repeat..until(); :)

Timer

2010-01-19 17:24:43

why are you confusing them?
begin
...._practice;
end.
please

NCDS

2010-01-19 17:42:27

From: Timer
why are you confusing them?
begin
...._practice;
end.
please


What…?

senrath

2010-01-19 18:15:42

From: NCDS
What…?


Oh, I see. You messed up on the main loop. You have end; instead of end.

Wanted

2010-01-19 18:18:41

What about labels and functions/proc that call themselves?

NCDS

2010-01-19 18:34:26

From: senrath
Oh, I see. You messed up on the main loop. You have end; instead of end.

>.< Fixed. Thanks for pointing that out.

From: IceFire908
What about labels and functions/proc that call themselves?

The thought never even crossed my mind to add those. I can though :)

Blumblebee

2010-01-19 18:39:15

you should also address the issue of infinite loops and how to break loops via timers, etc. (t := getSystemTime stuff).

NCDS

2010-01-19 19:15:06

From: Blumblebee
you should also address the issue of infinite loops and how to break loops via timers, etc. (t := getSystemTime stuff).


I did mean to add that. I wrote this at like 2 or 3a.m. last night?

I'll add updates later on tonight.

NCDS

2010-01-20 00:57:41

Updated.

Added a big section on breaking loops.

Will add a section on labels soon. (either a little later tonight or tomorrow.)

I'm still debating whether or not to add a part on a recursive method as the way it's used (sorting techniques) seems a bit advanced for a beginners tut. I may still do it though.

Take a look through, see if I missed anything this time. I should probably stop waiting till so late at night to do these..


Edit: Added labels.

BraK

2010-06-18 07:17:11

Exit; might be a good peice to add in there also.

i luffs yeww

2010-06-18 07:36:13

^ I believe Exit exits the function, not the loop.


if(not(LoggedIn))then
Exit;

No loop there. :)

BraK

2010-06-18 08:33:16

From: i luffs yeww
^ I believe Exit exits the function, not the loop.


if(not(LoggedIn))then
Exit;

No loop there. :)


True, but i use in it my function loops.


Function Fslime(var x,y:integer):boolean;
var
t:integer;
begin
t:=0;
repeat
wait(200+random(100));
inc(t);
if findcolortolerance(x,y,14089436,217,155,241,194,5) then
begin
result:=true;
writeln('Found Slime');
Mmouse(x,y,5,5);
exit;
end else
writeln('failed to find slime ' + inttostr(t) + ' Times.');
until (t>10)
end;

It's not really covered in most other tut's either.

bugger0001

2011-01-11 09:33:51

Care to add a little paragraph about Continue; as there have been a few threads about it lately in the Help section and it applies to all loops.
A simple example wouldn't harm either
repeat
Inc(i);
if i = 3 then Continue;
Writeln(i);
until i >= 5;

In addition to that I think you should add recursion here too. It's not that hard to understand at all if there is a simple example. I guess an alpha-beta algorithm would be a bit too much for this section, but a very basic overview of recursion would be nice :p

Yush Dragon

2011-01-11 12:18:04

Damn nice, i learned a new thing ^^ i noticed Labels could be very handy :o
btw u might add: continue; break; exit; to the tutorial since they are used in a loop most of the time.

rep+

NCDS

2011-01-11 21:10:20

From: Yush Dragon
Damn nice, i learned a new thing ^^ i noticed Labels could be very handy :o
btw u might add: continue; break; exit; to the tutorial since they are used in a loop most of the time.

rep+


'Exit;' exits the function, I believe 'Break;' is covered, and I will add a little description for 'Continue' in just a minute as requested by Bugger as well.

Edit: Added the 'Continue' bit.

jiadongpeng

2011-06-26 23:23:17

Thank you for sharing the post.

HT BaaFly

2011-12-16 14:49:24

thanks a lot. I think labels are going to be a crucial part in my upcoming script :D