[!java|scala]Arrays[/!][!python]Lists[/!] and Knotting

The goal of this exercise is to reproduce the pattern of the first row in the other rows with a shift of one cell (see the Objective tab for details). The biggest difference between this exercise and the others we had on patterns is that you have to read the pattern (on first row) before reproducing it. You cannot do otherwise because the same code will be executed on three different worlds, each of them having a specific pattern.

One solution is to read the next cell, and go copy it in position before coming back to read the second cell. But since it is forbidden to use the methods to teleport the buggle to a specific position (setPos() and similar), this approach will be a pain to implement.

The simplest is to store the sequence of colors that constitute the whole pattern in an [!java|scala]array[/!][!python]list[/!]. But before we can do so, we should learn a bit what [!java|scala]arrays[/!][!python]lists[/!] are.

[!java|scala]Arrays[/!][!python]List[/!]

[!java|scala]An array[/!][!python]A list[/!] is an ordered sequence of variables that go together. It is somehow similar to a shelve where each level can store a separate value. Each variable of the sequence is identified by its position, and can store a specific value. [!java|scala]All cells of the array must store values of the same type because arrays are homogeneous in [!thelang]. It is possible to trick this restriction by using the datatype [!java]Object[/!][!scala]Any[/!] that can contain [!java]almost[/!] any other datatype. [!java]Primitive types such as the ones we saw so far (int, boolean, double, char, etc) cannot be stored in an Object variable, but their objectified counter-part (Integer, Boolean, Double, Char, Boolean, etc) can.[/!] It is however a good practice to make the type of an array as specific as possible, i.e., if you plan to store some integers in your array, make it an array of integers, not of [!java]Object[/!][!scala]Any[/!].[/!] [!python]Lists can even mix values of differing types, such as integer values in some cells and colors in other cells.[/!]

T is the [!java|scala]array[/!][!python]list[/!]'s name, [!java|python]T[0][/!][!scala]T(0)[/!] is the name of the first cell, [!java|python]T[1][/!][!scala]T(1)[/!] the name of the second cell, [!java|python]T[2][/!][!scala]T(2)[/!] the third one, etc. And yes, the first cell is numbered [!java|python]T[0][/!][!scala]T(0)[/!] while the last one of [!java|scala]an array[/!][!python]a list[/!] of size N is [!java|python]T[N-1][/!][!scala]T(N-1)[/!]. It may seem funny to count starting from 0 and not from 1 as usual, but some historical reasons make it unavoidable here.

Basic usage

We can use an integer variable i to access with [!java|python]T[i][/!][!scala]T(i)[/!] to the cells: when the value of i is 0, then [!java|python]T[i][/!][!scala]T(i)[/!] accesses [!java|python]T[0][/!][!scala]T(0)[/!]; when the value of i is 10, then [!java|python]T[i][/!][!scala]T(i)[/!] accesses [!java|python]T[10][/!][!scala]T(10)[/!]. i is said to be the index in T. [!java|python]T[i][/!][!scala]T(i)[/!] can be used just like any variable. We can set a new value:

[!java|python]T[i][/!][!scala]T(i)[/!] = 78[!java];[/!]

We can retrieve and use its value:

x = [!java|python]T[i][/!][!scala]T(i)[/!][!java];[/!]

We can test this value:

if ([!java|python]T[i][/!][!scala]T(i)[/!] > 0) [!scala|java]{[/!][!python]:[/!]
    [!java|scala]//[/!][!python]#[/!] instructions...
[!java|scala]}[/!]

It is very easy to traverse the whole [!scala|java]array[/!][!python]list[/!], for example to initialize each cells.

[!java]for (int i = 0; i<T.length; i++) {[/!][!python]for i in range(len(T)):[/!][!scala]for (i <- 0 to T.length-1) {[/!]
   [!java|python]T[i][/!][!scala]T(i)[/!] = 3[!java];[/!]
[!java|scala]}[/!]

[!java|scala]The notation T.length retrieves the length of the array T,[/!] [!python]The function len() retrieves the length of the list T,[/!] allowing to build a classical for loop easily. [!python]Actually, the len() function is much more generic and can be used to retrieve the length of many objects. Applied to strings for example, it returns the amount of chars in this string.[/!] [!scala]Don't forget to start at 0 and stop at T.length-1 instead of 1 to T.length however.[/!]

If you just want to iterate over the values of T without keeping track of their index, you can simply write:

[!java]for (int i: T) {[/!][!scala]for (i <- T) {[/!][!python]for i in T:[/!]
  action()[!java];[/!]
[!java|scala]}[/!]

[!java]This construct is called an extended loop in Java. The variable i takes all values of the set located to the right of the colon (:), one after the other.[/!] [!python|scala]This is actually very similar to the previous construct. Simply, [!python]range(n)[/!][!scala]i to j[/!] returns a set of integers over which the for construct iterates. Actually, [!thelang] offers much more elegant ways to traverse [!python]lists[/!][!scala]arrays[/!] and other data collections, but this should be the topic of a specific set of exercises (that are still to be written in PLM).[/!]

Declaring [!python]a list[/!][!java|scala]an array[/!]

[!python]

If you know beforehand the content of your list, you can affect these values all together. Just put them between square braces and separated by commas as follows:

L = [1, 3, 5, 7, 9] 
# L is now an array of 5 values, all of them being integers

Otherwise, you probably want to create an empty list and then append each values separately to the list:

L2 = [] 
# L2 is now an empty list
L2.append(1)
L2.append(3)
L2.append(5)
L2.append(7)
L2.append(9) 
# Its content is now the same as L previously
[/!] [!java|scala]

To declare a variable named T that can store arrays of integers, one should write:

[!java]int[] T;[/!][!scala]var T:Array[Int][/!]

[!java]int means that the elements of the array are of type integer; [] means that we are speaking of an array and T is the name of the variable. For historical reasons, this can also be written as int T[] (with the [] after the variable name), but this is less readable and should probably be avoided.[/!] [!scala]The [Int] notation specializes the Array type (that is generic), specifying that each cell of this array is an integer. An array of booleans would simply by written Array[Boolean].[/!]

Allocating an array

Declaring a variable T that stores an array only reserve the name T for later use, but not the memory area to store the cells. The array is not initialized yet: it does not have any value. What would [!java]T[4][/!][!scala]T(4)[/!] mean if we didn't say that the array is 5 cells long?

First and foremost, we have to give a value to T:

[!java]T = new int[10];[/!][!scala]var T = new Array[Int](10)[/!]

new means that we want to create something, and [!java]int[10][/!][!scala]Array[Int](10)[/!] means that it is an array of 10 integer values. In return, an array of 10 integer cells is created in memory, and the T variable references this array.

The size of an array is fixed and cannot be changed after the creation of the array. The size of a T array can be retrieve by consulting the variable T.length.

While allocating, you can specify the size with a variable: [!java]int[] T = new int[i];[/!][!scala]var T = new Array[Int](i);[/!] In this case, the array's size will be set to the value of i when new gets called. The size of the array still cannot be modified : even if the variable i changes afterward, the size remains to the value given when it was allocated. [!java]Also, it is forbidden to write something like int T[10]; when declaring the variable. You are required to use the new instruction to allocate it, as in int[] T = new int[10]; [/!]

Declaration and initialization

If you know beforehand the content of your array, you can declare, allocate and initialize it in one shoot:

[!java]int[] T = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };[/!][!scala]var T = Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)[/!]

To know the size of the array to allocate, the compiler counts the provided values. This code is equivalent to:

[!java]int[] T = new int[10];
T[0] = 1;
T[1] = 2;
...
T[9] = 10;[/!][!scala]var T = new Array[Int](10);
T(0) = 1
T(1) = 2
...
T(9) = 10[/!]

It is also equivalent to:

[!java]int[] T = new int[10];
for (int i=0; i<T.length; i++) {
  T[i] = i+1;
}[/!][!scala]var T = new Array[Int](10);
for (i <- 0 to T.length-1) {
  T(i) = i+1
}[/!]
[/!]

[!python]Lists[/!][!scala|java]Arrays[/!] and method parameters

It is perfectly OK to pass [!python]a list[/!][!java|scala]an array[/!] to a method as a parameter. This method can then use this parameter as if it were defined locally:

[!java]boolean has42First(int[] array) {
    return array[0] == 42;
}[/!][!python]def has42First(list):
  return list[0] == 42[/!][!scala]def has42First(array:Array[Int]):Boolean = {
  return array(0) == 42
}[/!]

On the caller side, that also very simple:

[!java]int[] tab = new int[10];[/!][!scala]var tab = new Array[Int] (10)[/!][!python]tab = [1, 3, 5, 7, 9][/!]
[!java|scala]// Values initialization omitted
[/!]if (has42First(tab))[!java|scala] {[/!][!python]:[/!]
   [!java|scala]//[/!][!python]#[/!] do something
[!java|scala]}[/!]
[!java]

If you want to allocate and initialize the array in one shoot, that's a bit more complicated as the compiler has to know the type of the parameter you are creating. For that, use the following (ugly) construct:

if (has42First(   new int[] {1, 3, 5, 7, 9}   ) {
   // do something
}
[/!]

Methods can also return [!java|scala]arrays[/!][!python]lists[/!] as result without any complication. Here is a method that returns [!java|scala]an array[/!][!python]a list[/!] of the requested size, filled with 42s.

[!java]int[] fill42(int size) {
    int[] res = new int[size];
    for (int i=0; i<size; i++) 
        res[i] = 42;
    return res;
}[/!][!scala]def fill42(size:Int):Array[Int] = {
    var res = new Array[int] (size)
    for (i <- 0 to size -1) {
        res(i) = 42;
    }
    return res;
}[/!][!python]def fill42(size):
    res = []
    for i in range(size):
        res.append(42)
    return res[/!]

Goal of this exercise

At least! After this long explanation, we can come back to the exercise.

Your mission is rather simple actually. Your code should save the color pattern observed on the first row into [!java|scala]an array[/!][!python]a list[/!]. [!python]The easiest is to create an empty list, and then append() the colors one after the others as you read them (with getGroundColor()).[/!] [!java|scala]For that, you should declare and allocate an array of Color. Beware, there is several worlds, of differing size; use getWorldHeight() to retrieve the size of the current world. Once the array allocated, fill it by reading the ground color in each locations (with getGroundColor()).[/!]

Once you managed to read and save the pattern on the first row, you have to reapply the pattern on every rows, for example by executing getWorldHeight() times a method written specifically for this.