[!java|scala]Arrays[/!][!python]Lists[/!] e nós

O objetivo deste exercício é reproduzir o padrão da primeira linha nas outras linhas com um deslocamento de uma célula (veja a guia Objetivo para detalhes). A maior diferença entre este exercício e os outros sobre padrões é que tem que ler o padrão (na primeira linha) antes de reproduzí-lo. Não pode fazer de outro jeito por que o mesmo código será executado em três mundos diferentes, cada um com um próprio padrão.

Uma solução é ler a próxima célula e copiá-la à posição antes de voltar para ler a segunda célula. Mas já que é proibido usar os métodos de teletransporte de buggle para uma posição específica (setPos() e similares), esta abordagem seria muito difícil de implementar.

O mais simples é armazenar a sequência de cores que constituem o padrão inteiro numa [!java|scala]array[/!][!python]list[/!]. Mas antes de fazer isto, devemos aprender um pouco sobre o que [!java|scala]arrays[/!][!python]lists[/!] são.

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

[!java|scala]Uma array[/!][!python]Uma list[/!] é uma sequência ordenada de variáveis que ficam juntas. é similar a uma estante onde em cada prateleira se coloca um valor separado. Cada variável da sequência é identificada pela posição dela e pode armazenar um valor específico. [!java|scala]todas as células da array devem armazenar valores do mesmo tipo por que arrays são homogêneas em [!thelang]. É possível burlar esta restrição a usar tipos de dados [!java]Object[/!][!scala]Any[/!] que contenham [!java]praticamente[/!] qualquer outro tipo de dados. [!java]Tipos primitivos como aqueles que vimos anteriormente (int, boolean, double, char, etc) não podem ser armazenados numa variável Object, mas suas contrapartidas objetificadas (Integer, Boolean, Double, Char, Boolean, etc) podem.[/!] Entretanto, é boa prática fazer o tipo de uma array o mais específico possível, p.ex., se planea armazenar alguns inteiros na sua array, faça dela uma array de inteiros, não de [!java]Object[/!][!scala]Any[/!].[/!] [!python]Lists podematé mesmo misturar valores de diferentes tipos, como valores inteiros em algumas células e cores em outras células.[/!]

T é o nome da [!java|scala]array[/!][!python]list[/!], [!java|python]T[0][/!][!scala]T(0)[/!] é o nome da primeira célula, [!java|python]T[1][/!][!scala]T(1)[/!] é o nome da segunda célula, [!java|python]T[2][/!][!scala]T(2)[/!] da terceira e etc. E sim, a primeira célula é numerada [!java|python]T[0][/!][!scala]T(0)[/!] e a última de uma [!java|scala]array[/!][!python]list[/!] de tamanho N é [!java|python]T[N-1][/!][!scala]T(N-1)[/!]. Pode parecer estranho contar a partir de 0 e não de 1 como normalmente, mas por motivos históricos isto agora é inevitável.

Uso básico

Podemos usar uma variável inteira i para acessar com [!java|python]T[i][/!][!scala]T(i)[/!] as células: quando o valor de i é 0, [!java|python]T[i][/!][!scala]T(i)[/!] acessa [!java|python]T[0][/!][!scala]T(0)[/!]; quando o valor de i é 10, [!java|python]T[i][/!][!scala]T(i)[/!] acessa [!java|python]T[10][/!][!scala]T(10)[/!]. Sizemos que i é o índice em T. [!java|python]T[i][/!][!scala]T(i)[/!] pode ser usada simplesmente como qualquer variável. Podemos configurar um novo valor:

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

Podemos recuperar e usar valor dele:

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

Podemos testar este valor:

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

É muito fácil percorrer toda a [!scala|java]array[/!][!python]list[/!], por exemplo para iniciar as células.

[!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]A notação T.length recupera o comprimento (length) da array T,[/!] [!python]A função len() recupera o comprimento da lista T,[/!] a permitir que se construa um loop clássico facilmente. [!python]Na verdade, a função len() é muito mais genérica e pode ser usada para recuperar o comprimento de muitos objetos. Aplicada numa cadeia, por exemplo, ela retorna a quantidade de caracteres na cadeia.[/!] [!scala]Não se esqueça de começar em 0 e terminar em T.length-1 ao invés de ir de 1 até T.length.[/!]

Se quer simplesmente iterar nos valores de T sem controlar o índice, pode simplesmente escrever:

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

[!java]Esta construção é chamada um loop extendido em Java. A variável i assume todos os valores do conjunto localizado a direita do dois-pontos (:), um depois do outro.[/!] [!python|scala]Isto é na verdade muito similar à construção anterior. Simplesmente, [!python]range(n)[/!][!scala]i to j[/!] retorna um conjunto de inteiros sobre os quais o loop for itera. Na verdade, [!thelang] oferece formas muito mais elegantes de percorrer [!python]lists[/!][!scala]arrays[/!] e outras coleções de dados, mas isto fica para um conjunto específico de exercícios (que ainda será escrito no PLM).[/!]

Declarar uma [!python]list[/!][!java|scala]array[/!]

[!python]

Se sabe antecipadamente o conteúdo da sua lista, pode atribuir os valores todos juntos. Ponha eles simplesmente entre colchetes e separados por vírgulas como segue:

L = [1, 3, 5, 7, 9] 
# L agora é uma array de 5 valores, todos eles inteiros

Por outro lado, provavelmente vai criar uma lista vazia e depois anexar-la os valores separadamente:

L2 = [] 
# neste momento, L2 é uma lista vazia
L2.append(1)
L2.append(3)
L2.append(5)
L2.append(7)
L2.append(9) 
# E agora o seu conteúdo é igual ao de L, vista antes
[/!] [!java|scala]

Para declarar uma variável chamada T que pode guardar uma array de inteiros, deve escrever:

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

[!java]int significa que os elementos da array são do tipo inteiro; [] significa que estamos a falar de uma array e T é o nome da variável. Por motivos históricos, também pode ser escrito como int T[] (com o [] depois do nome da variável), mas como assim é menos legível, é melhor evitar esta forma.[/!] [!scala]A notação [Int] especializa o tipo Array (que é genérico), a especificar que cada célula desta array é um inteiro. Um array de booleanos deve ser escrito simplesmente como Array[Boolean].[/!]

Alocar uma array

Declarar uma variável T que armazena uma array apenas reserva o nome T para uso futuro, mas não reserva a área de memória para armazenar as células. A array ainda não está inicializada: ela não tem qualquer valor. O que significa [!java]T[4][/!][!scala]T(4)[/!] se ainda não dissemos que a array tem 5 células?

Primeiramente, temos que dar um valor a T:

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

new (novo) significa que queremos criar algo e [!java]int[10][/!][!scala]Array[Int](10)[/!] significa que é uma array de 10 valores inteiros. Como resultado, uma array de 10 células para valores inteiros é criada na memória e a variável T faz referência a esta array.

O tamanho de uma array é fixo e não pode ser mudado depois da criação da array. O tamanho de uma array T pode ser recuperado ao se consultar a variável T.length.

Ao alocar pode especificar o tamanho com uma variável: [!java]int[] T = new int[i];[/!][!scala]var T = new Array[Int](i);[/!] Neste caso, o tamanho da array será ajustado para o valor de i quando new for chamado. O tamanho da array ainda não pode ser modificado: mesmo se a variável i mudar depois disto, o tamanho permanece o do valor dado no momento da alocação. [!java]Além disto, é proibido escrever algo como int T[10]; no momento de declarar a variável. Deve usar a instrução new para alocar o array, como em int[] T = new int[10]; [/!]

Declaração e inicialização

Se sabe previamente o conteúdo da sua array, pode declarar, alocar e inicializar-la toda de uma vez:

[!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)[/!]

Para saber o tamanho da array para alocar, o compilador conta os valores dados. Este código é equivalente a:

[!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[/!]

também é equivalente a:

[!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[/!] e parâmetros de métodos

Não há nenhum problema em passar uma [!python]list[/!][!java|scala]array[/!] para um método como parâmetro. Este método pode então usar este parâmetro como se fosse definido localmente:

[!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
}[/!]

No lado de quem invoca também é bastante simples:

[!java]int[] tab = new int[10];[/!][!scala]var tab = new Array[Int] (10)[/!][!python]tab = [1, 3, 5, 7, 9][/!]
[!java|scala]// inicialização de valores omitida
[/!]if (has42First(tab))[!java|scala] {[/!][!python]:[/!]
   [!java|scala]//[/!][!python]#[/!] faz algo
[!java|scala]}[/!]
[!java]

Se quer alocar e inicializar o array de uma vez só, é um pouco mais complicado pois o compilador terá que saber o tipo do parâmetro queestá a criar. Para isto, use a seguinte construção (feia):

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

Métodos também podem retornar [!java|scala]arrays[/!][!python]lists[/!] como resultado sem nenhuma complicação. Aqui está um método que retorna uma [!java|scala]array[/!][!python]list[/!] do tamanho pedido, preenchido com 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[/!]

Objetivo deste exercício

Finalmente! Depois desta longa explicação, podemos voltar ao exercício.

A sua missão é bastante simples, na verdade. O seu código deve guardar o padrão de cores observado na primeira linha numa [!java|scala]array[/!][!python]list[/!]. [!python]O mais fácil é criar uma lista vazia e depois usar append()para adicionar as cores uma por uma à medida que for a ler elas (com getGroundColor()).[/!] [!java|scala]Para isto, deve declarar e alocar uma array de Cor. Mas atencção, existem vários mundos, de diferentes tamanhos; use getWorldHeight() para recuperar o tamanho do mundo atual. Uma que a array esteja alocada, preencha ela a ler a cor do chão em cada um dos pontos (com getGroundColor()).[/!]

Uma vez que conseguiu ler e gravar o padrão na primeira linha, tem que reaplicar o padrão nas outras linhas, por exemplo a executar getWorldHeight() vezes um método escrito especificamente para isto.