Une possibilité est de lire la prochaine case, puis d'aller la recopier en
position, avant de revenir lire la case suivante, etc. Mais comme vous
n'avez pas le droit d'utiliser les méthodes permettant de téléporter la
buggle à une case particulière (setPos()
et autres), cette
façon de faire va être très pénible à mettre en place.
Le plus simple est de stocker l'enchainement de couleurs constituant le motif dans [!java|scala]un tableau[/!][!python]une liste[/!]. Mais avant de pouvoir faire cela, nous devons en apprendre un peu plus sur les [!java|scala]tableau[/!][!python]listes[/!].
[!java|scala]Un tableau[/!][!python]Une liste[/!] est une séquence ordonnée
de variables qui marchent ensemble.
C'est un peu similaire à une commode dont les différents tiroirs peuvent
stocker des valeurs différentes.
Chaque variable de la séquence est identifiée par sa position et peut
stocker une valeur spécifique.
[!java|scala]Toutes les cellules d'un tableau doivent stocker des valeurs du
même type de données parce que les tableaux sont homogènes en [!thelang].
Il est cependant possible de contourner cette restriction en utilisant le
type de données [!java]Object[/!][!scala]Any[/!]
qui peut
contenir [!java]presque[/!] tous les autres type de données[!scala] («any»
veut dire «n'importe» en anglais)[/!].
[!java]Les types primitifs comme ceux que nous avons utilisé jusqu'à présent
(int, boolean, double, char, etc) ne peuvent pas être stockés dans une
variable Object, mais leurs variantes objectifiées (Integer, Boolean,
Double, Char, Boolean, etc) peuvent l'être.[/!]
Il est cependant raisonnable de rendre ses tableaux aussi spécifiques que
possible. Si vous avez l'intention de stocker des entiers, faites en un
tableau de [!java]integer[/!][!scala]Int[/!], pas de
[!java]Object[/!][!scala]Any[/!].[/!]
[!python]Les listes peuvent contenir des données de différents types, en
mélangeant par exemple quelques valeurs entières dans certaines cellules
avec des entiers dans d'autres cellules.[/!]
T est le nom [!python]de la liste[/!][!scala|java]du tableau[/!], [!java|python]T[0][/!][!scala]T(0)[/!] est le nom de la première case, [!java|python]T[1][/!][!scala]T(1)[/!] de la deuxième case, [!java|python]T[2][/!][!scala]T(2)[/!] de la troisième case, etc... Et oui, la première case est [!java|python]T[0][/!][!scala]T(0)[/!] et la dernière case [!python]d'une liste[/!][!scala|java]d'un tableau[/!] de taille N est [!java|python]T[N-1][/!][!scala]T(N-1)[/!]. Cela peut sembler étrange de commencer à compter à partir de 0 et non de 1, mais c'est ainsi (et cela s'explique par des raisons historiques obscures).
On peut utiliser une variable entière i pour accéder avec
[!java|python]T[i][/!][!scala]T(i)[/!] aux cases.
Quand i vaut 0 alors [!java|python]T[i][/!][!scala]T(i)[/!] dénote la
case [!java|python]T[0][/!][!scala]T(0)[/!];
lorsque i vaut 10, [!java|python]T[i][/!][!scala]T(i)[/!] dénote
[!java|python]T[10][/!][!scala]T(10)[/!].
On dit alors que i est un indice dans [!java|scala]le
tableau[/!][!python]la liste[/!] T.
[!java|python]T[i][/!][!scala]T(i)[/!]
peut être utilisé comme
n'importe quelle variable.
On peut lui affecter une nouvelle valeur:
[!java|python]T[i][/!][!scala]T(i)[/!] = 78[!java];[/!]
On peut réutiliser et tester cette valeur :
x = [!java|python]T[i][/!][!scala]T(i)[/!][!java];[/!]
On peut tester cette valeur :
if ([!java|python]T[i][/!][!scala]T(i)[/!] > 0) [!scala|java]{[/!][!python]:[/!] [!java|scala]//[/!][!python]#[/!] instructions... [!java|scala]}[/!]
Il est également très simple de parcourir [!java|scala]tout le tableau[/!][!python]toute la liste[/!], par exemple pour initialiser chaque cellule.
[!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]La notation T.length
permet d'accéder à la taille
(«length» en anglais) du tableau T,[/!]
[!python]La fonction len()
renvoie la longueur de la liste
T,[/!]
ce qui permet de construire facilement la boucle.
[!python]En fait, la fonction len()
est bien plus générique et
peut être utilisée pour calculer la taille de nombreux objets. Appliquée à
une chaîne de caractères par exemple, elle retourne le nombre de caractères
composant cette chaîne.[/!]
[!scala]N'oubliez pas de commencer à 0
pour terminer à
T.length-1
au lieu de 1 to T.length
![/!]
Si vous souhaitez simplement parcourir les valeurs de T sans avoir besoin de l'index de chaque valeur, vous pouvez écrire simplement :
[!java]for (int i: T) {[/!][!scala]for (i <- T) {[/!][!python]for i in T:[/!] action()[!java];[/!] [!java|scala]}[/!]
[!java]Cette construction s'appelle une boucle for
étendue en
Java.
La variable i prend successivement toutes les valeurs de l'ensemble
placé à droite des deux-points (:).[/!]
[!python|scala]Cette écriture est finalement très semblable à la
précédente.
Simplement, [!python]range(n)[/!][!scala]i to j[/!]
retourne un
ensemble d'entiers sur lequel la boucle for
itère.
En fait, [!thelang] offre d'autres moyens très élégants de traverser des
[!python]listes[/!][!scala]tableaux[/!]
et d'autres collections de données. Mais cela devrait être le sujet
d'exercices spécifiques (qui restent à écrire dans PLM).[/!]
Si vous connaissez à l'avance le contenu de votre liste, vous pouvez affecter ces valeurs directement. Placez-les simplement entre crochets et séparées par des virgules comme ceci :
L = [1, 3, 5, 7, 9]
# L est maintenant une liste de 5 valeurs, toutes des entiers
Dans le cas contraire, le plus simple est de créer une liste vide puis d'ajouter chaque valeur séparément à la liste :
L2 = [] # L2 est maintenant une liste vide L2.append(1) L2.append(3) L2.append(5) L2.append(7) L2.append(9) # Son contenu est maintenant le même que celui de L ci-dessus[/!] [!java|scala]
Pour créer une variable nommée T pouvant contenir un tableau d'entiers, on écrira :
[!java]int[] T;[/!][!scala]var T:Array[Int][/!]
[!java]int
indique que les éléments du tableau sont de type
entier;
[]
indique que nous parlons d'un tableau tandis que
T
est le nom de la variable.
Pour des raisons historiques, cela peut également être écrit sous la forme
int T[]
(avec [] à droite du nom de la variable),
mais cette forme est moins lisible et devrait probablement être évitée.[/!]
[!scala]La notation [Int]
spécialise le type Array
(«tableau» en anglais), qui est générique. Cela spécifie que chaque case du
tableau est un entier. Le type d'un tableau de booleens s'écrirait
simplement Array[Boolean]
.[/!]
Déclarer un tableau T
nous réserve juste le nom T
pour l'utiliser plus tard, mais pas la place en mémoire pour stocker les
cases. Le tableau n'est pas initialisé : il n'a pas de valeur. Que voudrait
dire T[4]
si nous n'avons pas encore dit que T
est
un tableau de 5 éléments ?
Avant tout, il faut donc lui affecter une valeur à T
:
[!java]T = new int[10];[/!][!scala]var T = new Array[Int](10)[/!]
new
indique qu'il faut créer quelque chose, et
[!java]int[10][/!][!scala]Array[Int](10)[/!]
indique qu'il
s'agit d'un tableau de 10 valeur entières. En réponse, un tableau d'entiers
de longueur 10 est crée en mémoire, et la variable T
référence ce tableau.
La taille d'un tableau est fixée et ne peut plus être changée après la
création du tableau. Pour connaître la taille d'un tableau T
,
on peut consulter la variable T.length
.
Lors de l'allocation, vous pouvez spécifier la taille à utiliser avec une
variable:
[!java]int[] T = new int[i];[/!][!scala]var T = new
Array[Int](i);[/!]
Dans ce cas, la taille du tableau est fixée à la valeur de i
quand new
a été appelé.
La taille du tableau ne peut toujours pas être modifiée. Même si la valeur
de i
est modifiée ensuite, la taille reste la même.
[!java]Enfin, il est interdit d'écrire quelque chose comme int
T[10];
pour déclarer la variable. Il faut absolument utiliser
new
pour l'allouer, comme dans int[] T = new
int[10];
[/!]
Si vous connaissez le contenu de votre tableau à l'avance, vous pouvez le déclarer, l'allouer et l'initialiser en un coup:
[!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)[/!]
Pour connaître la taille du tableau à allouer, le compilateur compte les valeurs données. Ce code est équivalent à :
[!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[/!]
C'est aussi équivalent au code :
[!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 }[/!][/!]
On peut tout à fait passer [!java|scala]un tableau[/!][!python]une liste[/!] en paramètre d'une méthode. La méthode peut alors l'utiliser comme si la variable avait été définie localement:
[!java]boolean a42Premier(int[] tableau) { return tableau[0] == 42; }[/!][!python]def a42Premier(liste): return liste[0] == 42[/!][!scala]def a42Premier(tableau:Array[Int]):Boolean = { return tableau(0) == 42 }[/!]
Coté appelant, c'est aussi simple :
[!java]int[] tab = new int[10];[/!][!scala]var tab = new Array[Int] (10)[/!][!python]tab = [1, 3, 5, 7, 9][/!] [!java|scala]// Initialisation des valeurs omise [/!]if (a42Premier(tab))[!java|scala] {[/!][!python]:[/!] [!java|scala]//[/!][!python]#[/!] faire des choses [!java|scala]}[/!][!java]
Si vous voulez allouer et initialiser le tableau au vol lors du passage de paramètre, c'est un peu plus compliqué car il faut dire au compilateur le type du paramètre que vous construisez. Il faut alors utiliser la construction suivante, même si elle n'est pas très belle.
if (has42First( new int[] {1, 3, 5, 7, 9} ) {
// faire des choses
}
[/!]
Les méthodes peuvent également retourner des [!java|scala]tableaux[/!][!python]listes[/!] comme résultat sans aucun problème. Voici une méthode retournant [!java|scala]un tableau[/!][!python]une liste[/!] de la taille demandée après avoir initialisé toutes les cases à la valeur 42.
[!java]int[] remplir42(int taille) { int[] res = new int[taille]; for (int i=0; i<taille; i++) res[i] = 42; return res; }[/!][!scala]def remplir42(taille:Int):Array[Int] = { var res = new Array[int] (taille) for (i <- 0 to taille -1) { res(i) = 42; } return res; }[/!][!python]def remplir42(taille): res = [] for i in range(taille): res.append(42) return res[/!]
Enfin ! Après toutes ces explications, nous pouvons revenir à l'exercice.
Votre mission est plutôt simple au fond. Votre code doit sauvegarder le
motif de couleurs observé sur la première colonne. Il faut bien entendu
sauvegarder ces valeurs dans [!java|scala]un tableau[/!][!python]une
liste[/!].
[!python]Le plus simple pour cela est de créer une liste vide puis d'y
adjoindre (avec append()
les différentes couleurs lues sur le
sol de la première colonne (avec getCouleurSol()
).[/!]
[!java|scala]Pour cela, il faut déclarer et créer un tableau de
Color
s. Attention, les différents mondes ne sont pas tous de la
même taille et il faut utiliser getMondeHauteur()
pour trouver
la taille du monde courant. Une fois créé, remplissez le tableau en lisant
les couleurs au sol de la première colonne (avec
getCouleurSol()
).[/!]
Une fois le motif de la première colonne lu et sauvegardé, il faut le
répliquer sur toutes les colonnes, par exemple en exécutant
getMondeLargeur()
fois une méthode écrite tout exprès.