Listas



Uma lista é uma variável com uma forma especial: Em vez de guardar um número, ou a designação de um agente, ou qualquer outro elemento isolado, uma lista tem a forma de uma tabela em que cada item se comporta como uma variável convencional (ou até como outra lista, isto é, listas dentro de listas). Exemplos:

set lista1 (list 0 1 2 3)
Constrói uma lista de quatro elementos com o valor 0 como primeiro elemento, 1 como segundo, 2 como terceiro e 3 como quarto, e atribuí-a à variável lista1. Ou seja, lista1 passa a ser uma lista de quatro elementos.
set lista2 (list red "NOME" 4.5 turtles lista1 1056)
Desta maneira, lista2 passa a ser uma lista de seis elementos de vários tipos diferentes: Três números (red designa o valor numérico correspondente à cor vermelha), uma string, um conjunto de agentes (turtles) e uma outra lista, a lista1 construída anteriormente.
set lista3 (list)
É possível construír listas vazias.

Como se pode ver, usa-se a construção (list elemento ...) para explicitar os elementos que compõem uma lista. Os parêntesis são necessários. Os elementos de uma lista podem variar ao longo da existência dessa lista, e o próprio tipo e número de elementos também pode variar. Ou seja, além de se construír uma lista da maneira indicada, é possível acrescentar, remover ou modificar elementos individuais em qualquer altura.

Uma lista é estritamente ordenada: Isto é, cada elemento de uma lista possuí um número de ordem, designado índice. Este índice pode ser usado para referenciar um determinado elemento de uma lista. O primeiro elemento tem sempre índice 0, e elementos sucessivos recebem índices sucessivos na escala dos inteiros positivos. Ou seja, para a lista1 construída acima, os elementos têm o mesmo valor numérico que os seus índices respectivos. No entanto, estes índices podem mudar: Se for retirado um elemento do princípio ou meio da lista, os elementos seguintes vêm o seu índice ser reduzido por uma unidade. Isto é, nunca podem existir índices desocupados numa lista.

De seguida descrevem-se as primitivas mais úteis para o manuseamento de listas.

SintaxeDescrição
but-first listaDevolve uma lista semelhante a lista, mas com o primeiro elemento removido.
but-last listaDevolve uma lista semelhante a lista, mas sem o último elemento.
empty? listaDevolve true se lista não contiver elementos, devolve false no caso contrário.
foreachVer à frente.
fput item listaDevolve uma lista igual a lista, com item acrescentado ao início.
item indice listaDevolve o elemento pertencente a lista com índice indice.
length listaReporta o número de elementos contidos em lista.
lput item listaDevolve uma lista igual a lista, com item acrescentado no fim.
position item listaPercorre lista e reporta o índice do primeiro elemento igual a item. Se não existir, devolve false.
random-one-of listaDevolve um elemento escolhido aleatoriamente de entre os que estão contidos em lista.
remove-item indice listaDevolve uma nova lista igual a lista com o elemento na posição indice removido.
replace-item indice lista elementoDevolve uma nova lista igual a lista mas com o item na posição indice substituído por elemento.
shuffle listaConstrói uma nova lista com os elementos de lista, mas numa ordem aleatória.

Note-se que nenhuma das primitivas acima modifica a lista original passada como argumento à primitiva; apenas constróem uma nova lista a partir da fornecida. Assim, se quisermos acrescentar o valor 9 ao fim da lista3, por exemplo, deve-se fazer:
set lista3 lput 9 lista3

Como exemplo de utilização de listas, segue-se uma explicação de parte do código do modelo usado no Capítulo 5. Neste modelo, a função desempenhada pelo botão de interface Repor Ambiente (que é responsável por reposicionar as migalhas de comida nas mesmas posições que tinham antes de serem alteradas pelas formigas) usa três variáveis globais (definidas na primitiva globals) do tipo lista: lista-x, lista-y, lista-tipo

Primeiro, no procedimento Preparar, que inicializa o modelo, estas três variáveis são inicializadas como listas vazias:

set lista-x (list)
set lista-y (list)
set lista-tipo (list)

Depois, quando se criam novas migalhas com o botão Depositar Comida, o procedimento Depositar-Comida, que lhe está associado, usa as seguintes instruções para guardar em lista-x a coordenada X da nova migalha, em lista-y a coordenada Y, e em lista-tipo um valor inteiro que descrimina o tipo de migalha: Valores positivos indicam que se trata de uma migalha de forma regular, e valores negativos indicam uma forma aleatória. Os valores absolutos são a cor da migalha.

set lista-x lput mx lista-x
set lista-y lput my lista-y
ifelse forma-da-migalha = "regular"
[ Depositar-Migalha-Regular mx + 0.75 my + 0.75
set lista-tipo lput 1 lista-tipo ]
[ Depositar-Migalha-Aleatoria mx + 0.75 my + 0.75
set lista-tipo lput -1 lista-tipo ]
...
set lista-tipo replace-item (length lista-tipo - 1) lista-tipo (last lista-tipo * cor)

As duas primeiras instruções são evidentes: Trata-se apenas de acrescentar ao fim de cada uma das listas a coordenada respectiva. De seguida, a instrução ifelse, conforme o tipo de migalha seleccionado na lista de interface forma-da-migalha, acrescenta o valor +1 ou -1 ao fim da lista-tipo. Finalmente, a última instrução substituí o último elemento de lista-tipo (indicado por length lista-tipo - 1, não esquecer que o primeiro elemento tem índice 0, não 1), por esse próprio elemento multiplicado pelo valor numérico da cor da migalha (last lista-tipo é equivalente a item (length lista-tipo - 1) lista-tipo). Obtém-se assim um valor da forma +cor ou -cor, conforme a forma da migalha é regular ou aleatória, respectivamente.

Por fim, o procedimento repor, associado ao botão Repor Ambiente, usa a informação armazenada nas listas para reposicionar automaticamente todas as migalhas criadas desde que o modelo foi inicializado com o botão Preparar. Mas antes de explicar este procedimento, uma explicação sobre a primitiva foreach.

A primitiva foreach é usada para percorrer uma ou mais listas (que têm que ter todas o mesmo número de elementos) e executar um bloco de instruções com cada elemento ou grupo de elementos (elementos com o mesmo índice nas várias listas) como argumentos. Por exemplo:
(foreach lista1 lista2 lista3 [ Calcular ?1 ?2 ?3 ])
Se cada uma das listas tiver 5 elementos, então o procedimento Calcular é executado 5 vezes, recebendo como argumentos de cada vez, por ordem, o elemento actual de lista1, o elemento actual de lista2, e o elemento actual de lista3. Ou seja a variável com o nome especial ?1 significa o elemento actual (começando no primeiro e percorrendo sucessivamente a lista até ao fim) da primeira lista, e assim sucessivamente.
Se as listas estiverem vazias, nada é executado.
Quando se usa apenas uma lista, pode-se usar ? como sinónimo de ?1:
(foreach lista-agentes [ ask turtle ? [ set color red ] ])
Os parêntesis curvos são necessários.

O bloco de código relevante no procedimento repor é então:

( foreach lista-tipo lista-x lista-y
[ ifelse ?1 > 0
[ Depositar-Migalha-Regular ?2 + 0.75 ?3 + 0.75
set mcor ?1 ]
[ Depositar-Migalha-Aleatoria ?2 + 0.75 ?3 + 0.75
set mcor -1 * ?1 ]
ask patches with [ distancexy-nowrap ?2 ?3 <= tamanho-migalha ]
[ set cor mcor ] ] )

Ou seja, para cada migalha (isto é, para cada grupo de três elementos com o mesmo índice, um de cada lista), é avaliado se a sua forma é regular ou aleatória e o procedimento apropriado é chamado com as coordenadas X e Y da migalha. De seguida, a migalha é pintada com o valor absoluto do elemento de lista-tipo.