Lists ’n Loops

Lists

So far in Setanta we’ve only been using text and numbers in our programs. These have allowed us to do some powerful stuff, but they are also very limiting.

What if we want to deal with more than one piece of text, or more than one number. That’s where lists come in. Lists, unsurprisingly, allow us to store values in a list.

Making lists

Lists are created with square brackets ([, ]) around the outside and commas (,) to separate the elements of the list, for example: [100, 200, 300] is a list with 3 elements. 100 is the first element, 200 is the second, and 300 is the last element. [] is an empty list.

Try adding 4 as a fourth element to the list [1, 2, 3] here:

Click here to see the answer.

In that example we saw a list of numbers, but you can make a list out of whatever you like! Text, numbers, booleans, other lists, you name it. You can even mix and match in the same list.

[1, 2, 3] >-- Numbers
["Hello", "Goodbye"] >-- Text
[["List", "inside"], ["a", "list"]] >-- Lists of lists
[10, fíor, "Dia duit"] >-- Mix up the types

Joining lists

Lists can be joined together with the “+” operator, just like text and numbers.

Using + with two lists creates a new list made up of the 2 original lists joined together.

We can use this to add elements to the end or front of existing lists.

Explanation:

  • On the first line, we create a new list [1, 2, 3], and put it in the new variable “x”.
  • On the second line we update the variable x with the value x + [4]. The value stored in x is [1, 2, 3], so this evaluates to [1, 2, 3] + [4] which equals [1, 2, 3, 4]. We then update the variable x to this value.
  • On the third line we print x, which is now [1, 2, 3, 4].

Access

Now that we know how to make lists, and how to put values into the lists, how do we get values back out?

The elements of a list are numbered. The first element of the list is element 0, the second is element 1, then 2, then 3, etc. This number is called the index of the element.

List numbering

We use square brackets ([]) again to access an element at a specific index. We wrap the index in square brackets and place it after the list. e.g. if we have a list called our_list, we can access the first element by writing our_list[0], the second element by writing our_list[1], and so on. Here’s an example you can play with:

Try changing the 0 on line 5 to a different number and see what happens.

Out of bounds

Our list [10, 20, 30, 40] in the last example is only 4 elements long, so what happens if we try and get access to the 5th element (index 4)? Try it out:

You should get an error saying “Tá 4 thar teorainn an liosta” which translates as “4 is outside the limits of the list”.

Out of bounds error

If a list has some length L, then the only valid indices are 0, 1, 2 … up to L - 1.

Length

We often want to know how many elements are in a list. To do this we can use the word “fad” meaning “length”. If our list is called our_list, we write fad@our_list to get the length. Try it out!:

(We will see what the “@” symbol does in the future)

This can be very useful if we want to get the last element of the list. Remember that this will be at index fad@our_list - 1. Try it out here:

Text vs lists

Text can be thought of as a list of characters. You can use the same methods as lists to access the letters in text, and to get the length of a piece of text.

E.g.

Loop-de-loop

Now that we have our lists, what can we do with them. The main tool that we will use with lists are called “loops”.

Loops give us a way of taking some piece of code and repeating it over and over. We’ll take a look at types of loops, and then see how we can use them with lists.

Le idir

Our first type of loop we’re going to look at is called the “le idir” loop. “le idir” translates as “with between”. This loop is called “with between” because it allows us to loop with some variable, between two values.

The syntax for a “le idir” loop is:

le <variable> idir (<start>, <finish>) {
    <code to repeat>
}

How a “le idir” loop works is:

  1. The Setanta interpreter creates a new variable, with the name we gave (“<variable>”). This is called the loop variable.
  2. Then it assigns this variable the “<start>” value.
  3. It runs the code between the curly braces ({ }).
  4. It then increases the value in the loop variable.
  5. It checks if the loop variable is equal to the “<finish>” value. If it is, it exits the “le idir” loop and continues on after.
  6. If the loop variable wasn’t equal to the finish value, then it returns to step 3.

This might be a little confusing to read, but it’s easy to see with an example. Let’s run the following code:

Example

Running this code you should see that it writes “0”, then “1”, then “2”, “3”, and “4”. It then writes “Finished”.

Explanation

To execute the “le idir” loop, Setanta creates a new variable called “i”. We could choose any name for this variable, but in our example we chose “i”.

Setanta first assigns the start value (in our case 0) to i, and then runs the code in the curly braces. This code is scríobh(i). So the first thing that gets written is “0”.

Next Setanta increases the value of i, so now i contains the value 1. It then checks, is i equal to the finish value (in our case 5)? It isn’t, so it returns to step 3 and runs the code inside the brackets. Again this is scríobh(i). Now however i is 1, so “1” is written on the console.

This continues for 2, 3 and 4.

Finally after Setanta runs the code for 4 it increases the value of i to 5. Now however it checks if i is equal to the finish value, and this time it is. This tells Setanta that we are finished, so it exits the loop and continues on to the next statement.

The next statement is scríobh("Finished"), so it writes “Finished” on the console. This is the last statement so the program finishes.

Printing out a list

Now we will see how to use “le-idir” loops with lists. We will use a loop to print out every element of a list.

Let’s start with a short list:

my_list := [1, 2, 3, 4, 5]

There are five elements in that list, we want to use each one, because of that we need to use every index. We should write my_list[0], my_list[1], my_list[2], my_list[3] and my_list[4]. To do that, we should use a loop to go from 0 to 4. We saw in the previous example that we can use this list to go from 0 to 4:

le i idir (0, 5) {
}

Let’s use that again to write every element of the list, try it out:

But now, what happens when we add a new number to the list? There is now a new number 6 in the list, try the code again:

It doesn’t write out “6” on the console! Why? It doesn’t write it because the loop stops when it gets to index 4, and 6 is at index 5. If we want to we can change the finish value from 5 to 6, but is there a smarter way?

Notice that in the first example that 5 is equal to the length of the list, this is not a coincidence! We want the loop to go from 0 to the last index, and we saw before that the last index would be fad@my_list - 1. A “le-idir” loop stops before the finish value", because of that if we use fad@my_list as the finish value, the loop will stop at fad@my_list - 1. This is exactly what we want to do!

Now this is our code:

When you run this now it writes every element of the list! Try out shorter lists and longer lists!

List sum

Let’s explore how we could add up all the elements of a list of numbers. We should start with our code from before to loop over all the element of the list

>-- Start with some list
my_list := [11, 12, 13, 14, 15]

>-- Use le idir loop to loop over the elements
le i idir (0, fad@my_list) {
}

Now we can make a new variable to store the sum of the elements. This variable starts out with the value 0.

>-- Start with some list
my_list := [11, 12, 13, 14, 15]

>-- A variable to store the sum of the elements.
sum := 0

>-- Use le idir loop to loop over the elements
le i idir (0, fad@my_list) {
}

Then for each element of the list we can add it’s value to the sum with sum = sum + my_list[i]

>-- Start with some list
my_list := [11, 12, 13, 14, 15]

>-- A variable to store the sum of the elements.
sum := 0

>-- Use le idir loop to loop over the elements
le i idir (0, fad@my_list) {
    sum = sum + my_list[i]
}

Now we just add our final line scríobh(sum) to write the sum of the list on the console. Try out the final code!

Bonus shorthand

We used sum = sum + my_list[i] to add my_list[i] to the sum variable. Setanta has a shorthand for this common problem, the += operator. We can just write sum += my_list[i] to add my_list[i] to the sum.

There is also *=, -= and /= for multiplication, subtraction and division respectively.

Step Up

A le idir loop can also accept a third number, positioned after the start and finish values. This value increases the size of the step. Usually the loop variable is increased by 1 on every iteration, however by including a third number you can specify a custom size to increase by:

For example:

This loop starts at 0 and increases by 2 instead of 1 each time.

Bonus Tip

If the finish value is smaller than the start value, the loop will decrease by 1 each time, instead of increasing.

Circle Art

Let’s combine what we’ve seen before with our new knowledge and make some art. Let’s make a program where the user can input a number of circles that they would like, and the program will randomly draw that many circles all over the stage, with random positions and sizes.

Let’s draw some circles

There are a few new actions and values we’ll have to look at before we start.

Random

First let’s see how do we generate a random number? Lucky for us Setanta has 2 actions that can do that for us, rand and slánuimh_rand. These are maths actions so we access them with rand@mata and slánuimh_rand@mata. (Once again, we’ll see what the @ does in the future).

  • rand returns a random number between 0 and 1, not necessarily a whole number e.g. 0.5, 0.333 etc.
  • slánuimh_rand takes two arguments and returns a random whole number between those 2. e.g. slánuimh_rand(3, 5) will return one of 3, 4 or 5 with equal probability..

The names of these actions are rand and slánuimh_rand because “rand” is short for “randamach” meaning “random” and “slánuimh” is short for “slánuimhir” which means whole number.

Try out this code a few times:

You should get different numbers from 0 to 100 each time.

The Stage

If we want to place circles randomly on the stage, we’ll need to know how big it is.

We can access the width and height by accessing the values fad_x@stáitse and fad_y@stáitse.

Try running this code:

If you resize your window you might get different results.

The Art

Ok let’s write our program: First we want to ask the user how many circles they want. Remember we can use ceist to ask for user input, and go_uimh to convert text to numbers.

n_circles := go_uimh(ceist("How many circles? "))

Now we would like to create that many circles, so we would like to repeat some code n_circles times. We can use a le idir loop for this

n_circles := go_uimh(ceist("How many circles? "))

le i idir (0, n_circles) {
    >-- We'll put our circle logic here
}

(We’ve named our loop variable i, but we won’t be using it in the loop)

To draw a circle randomly, we want to pick a random X coordinate, a random Y coordinate, and a random radius. We can uses fad_x and fad_y to get the bounds of the stage, and slánuimh_rand to generate a random number in that range by using slánuimh_rand@mata(0, fad_x@stáitse) and slánuimh_rand@mata(0, fad_y@stáitse)

n_circles := go_uimh(ceist("How many circles? "))

le i idir (0, n_circles) {
    randx := slánuimh_rand@mata(0, fad_x@stáitse)
    randy := slánuimh_rand@mata(0, fad_y@stáitse)
}

We’ll just use 50 to 100 as a range for our radius, as we don’t want them too big or too small.

n_circles := go_uimh(ceist("How many circles? "))

le i idir (0, n_circles) {
    randx := slánuimh_rand@mata(0, fad_x@stáitse)
    randy := slánuimh_rand@mata(0, fad_y@stáitse)
    randr := slánuimh_rand@mata(50, 100)
}

Now that we’ve picked random coordinates and size, all that’s left is to draw the circles using ciorcal@stáitse.

n_circles := go_uimh(ceist("How many circles? "))

le i idir (0, n_circles) {
    randx := slánuimh_rand@mata(0, fad_x@stáitse)
    randy := slánuimh_rand@mata(0, fad_y@stáitse)
    randr := slánuimh_rand@mata(50, 100)
    ciorcal@stáitse(randx, randy, randr)
}

Try running the code! You’ll have to type in how many circles you want, then switch tabs to the stage to see the results.

Switch up the colours

It’s a bit boring having all the circles be the same colour. Let’s switch it up using lists!

Let’s make a list of colours we’d like to see and put it at the top of the program.

colours := ["dearg", "buí", "gorm", "glas"]

n_circles := go_uimh(ceist("How many circles? "))

le i idir (0, n_circles) {
    randx := slánuimh_rand@mata(0, fad_x@stáitse)
    randy := slánuimh_rand@mata(0, fad_y@stáitse)
    randr := slánuimh_rand@mata(50, 100)
    ciorcal@stáitse(randx, randy, randr)
}

I chose “dearg”, “buí”, “gorm” and “glas”. Now when before we draw a circle, we can switch to a random colour from our list.

To pick a random colour we want to pick a random element from the list. We can do this by picking a random index using slánuimh_rand, we want any index between the first (0) and the last (fad@colours - 1). This gives us index := slánuimh_rand@mata(0, fad@colours - 1).

colours := ["dearg", "buí", "gorm", "glas"]

n_circles := go_uimh(ceist("How many circles? "))

le i idir (0, n_circles) {
    randx := slánuimh_rand@mata(0, fad_x@stáitse)
    randy := slánuimh_rand@mata(0, fad_y@stáitse)
    randr := slánuimh_rand@mata(50, 100)

    rand_index := slánuimh_rand@mata(0, fad@colours - 1)

    ciorcal@stáitse(randx, randy, randr)
}

We can use the index now to pick our random colour “colours[rand_index]” and use dath@stáitse to switch to that colour:

colours := ["dearg", "buí", "gorm", "glas"]

n_circles := go_uimh(ceist("How many circles? "))

le i idir (0, n_circles) {
    randx := slánuimh_rand@mata(0, fad_x@stáitse)
    randy := slánuimh_rand@mata(0, fad_y@stáitse)
    randr := slánuimh_rand@mata(50, 100)

    rand_index := slánuimh_rand@mata(0, fad@colours - 1)

    dath@stáitse(colours[rand_index])

    ciorcal@stáitse(randx, randy, randr)
}

Now try running the code!

Demo

Circle art

Challenge

Switch to using ciorcal_lán@stáitse instead of ciorcal, what happens?

(Hint: “lán” means “full” in English).