18 septembre 2008

Cours d'initiation au langage LSL (III suite)

après la structure de contrôle IF la dernière fois, continuons ce cours d'initiation au LSL.
Aujourd'hui : les structures de contrôle (suite et fin) et les fonctions.



I. Les structures de controle


1) La boucle WHILE


Cette structure permet de répéter une série d'instructions tant qu'une condition n'est remplie.

while(condition){
instruction1;
instruction2;
....
}


Exemple : Parcourons les entiers de 1 à 10, et indiquons s'ils sont pairs ou impairs.


integer n = 1;
// on commence à 1.
// on définit la variable à parcourir
// et on l'initialise de suite

while ( n <= 10 ){ if (n%2 == 0){
llSay(0, "le nombre "+ n + " est pair");
}else {
llSay(0, "le nombre " + n + " est impair");
}
n++;
}

Voyons dans le détail ce que fait ce bout de code. On définit tout d'abord une variable n = 1, que l'on va parcourir.
Entrée dans la boucle : on teste n. Est-il plus petit que 10 ? Oui. On traite les instructions.
On calcule n%2 qui vaut 1..... donc on exécute le code du ELSE : on écrit : le nombre 1 est impair.
Ensuite, on incrémente n de 1....Fin de la boucle.

On recommence : test ( n <= 10 ?) ...oui => n%2 = 0 donc on ecrit : le nombre 2 est pair. Incrément de n... n vaut 3.
Et on recommence.... jusque n = 11.
Lors du test, la condition n <= 10 est fausse. On n'exécute donc pas le code qui suit, et on sort de la boucle. L'instruction n++ est extrêmement importante. Imaginons qu'on l'oublie. Le nombre n ne varie pas. Le test de la condition est toujours vrai, donc le code s'exécute sans fin, puisque a chaque nouvelle boucle, on teste le meme nombre. Nous sommes dans le cas d'une boucle infinie. Le programme boucle sans fin. Notons aussi que avant de démarrer une boucle, le programme effectue un test. Donc que si on parcourt les entiers de 1 à 100, 100 tests sont effectués. Dans le cas où on ne souhaite faire que une boucle un certain nombre de fois bien défini, il existe une autre structure de controle plus adéquate. Ici, aucun risque de boucle infinie, puis qu'il n'est pas nécessaire d'incrémenter une variable. Passons tout de suite à cette structure :

2) La boucle FOR

Sa structure est la suivante :

for(nom de la variable et affectation; condition de fin; incrément){
instruction1;
instruction2;
....
}

  • Nom de la variable et incrément : on précise la variable et sa valeur initiale

  • Condition : la contrainte qui est excercée sur cette variable. Dans le même genre que celle du WHILE.

  • Incrément : le pas d'incrémentation de la variable.

Reprenons l'exemple précédent avec une boucle FOR :

integer n;// l'initialisation n'est pas nécessaire

for( n = 1 ; n <= 10 ; n++){ if (n%2 == 0){
llSay(0, "le nombre "+ n + " est pair");
}else {
llSay(0, "le nombre " + n + " est impair");
}
}


Notons aussi que l'incrément n'est pas obligatoirement 1... Par exemple, comptons de 2 en 2 jusque 10 :

integer n;
for( n = 0 ; n <= 10; n+=2){ llSay(0; n);
}

on peut aussi bien sur compter à l'envers.... de 10 à 0 par saut de 2....

integer n;
for( n = 10 ; n >= 0 ; n-=2){
llSay(0; n);
}



3) Encore ??


Il existe encore deux autres structures.... le DO...WHILE et le JUMP. Mais je n'en parlerai pas. Pourquoi ?

Le DO ... WHILE fonctionne de la même manière que le WHILE, sauf que le test s'effectue à la fin et non pas au début. Ainsi, quel que soit le résultat du test, la série d'instructions de la boucle est effectuée au moins une fois. Cette structure, présente dans beaucoup de langage, est finalement très peur utilisée.

Le JUMP permet de "sauter", de faire un saut directement à une autre partie du programme. Même si cela peut parfois s'avérer pratique, cette instruction n'est utilisée que par ceux qui n'y connaissent rien à l'algorithmique, et programment comme des gougnafiers !!
Le code est alors illisible, et, même si il parait plus facile de faire des jumps plutot que de coder proprement, dans le maintient et la correction d'un code, l'utilisation du jump rend le code ingérable. Donc à fuir absolument !!



II. Les fonctions


Elles sont de deux sortes : celles qui font partie de l'API du LSL, et que l'on peut utiliser directement, et celles que l'on écrit soi même avec ses petites mains.


1) Les fonctions LSL

Elles se reconnaissent car elles commencent toujours par ll. Par exemple la fonction llSay deja rencontrée. Je détaillerai dans le prochain cours les fonctions LSL indispensables à connaitre.


2) Les fonctions que je code avec mes mimines à moi

Pour pouvoir utiliser ces fonctions, il faut tout d'abord les définir. Une fonction est une portion de code, qui effectue une serie d'instructions. Elle peut prendre des paramètres en entrée ou non. Elle peut retourner un résultat ou non.
Certains langages (mais pas le LSL) distinguent les deux, et appellent fonction quand il y a retour d'un résultat, et procédure quand il n'y en a pas.
Une fonction contenant une suite d'instructions, celles-ci peuvent etre d'autres fonctions, ou des fonctions LSL.

Notons tout de suite que la déclaration des fonctions se fait au début du script, généralement apres la declaration des variables globales.
D'où le squelette d'un script LSL (squelette définitif) :


//définition des variables globales


// Définition des fonctions personnelles


// un état du script : etat1

state etat1 {

evenement1(){
fonction1();
fonction2();
}

evenement2(){
fonction3();
fonction4();
}

}


Voyons tout d'abord une fonction sans paramètre; son squelette est le suivant :


ma_fonction(){
instruction1;
instruction2;
....
}


Par exemple, une fonction qui ecrit : "bonjour à tous !!" dans le chat....

dire_bonjour(){
llSay(0, "Bonjour à tous !!");
}


Lorsqu'on souhaite appeler cette fonction, il suffit d'écrire :

dire_bonjour();

Et c'est tout !!


Ensuite, une fonction avec paramètre. Son squelette est le suivant :


ma_fonction( type1 variable1, type2 variable2, ...){
instruction1;
instruction2;
....
}


Par exemple :

dire_bonjour2(string nom){
llSay(0, "Bonjour " + nom + " !! Comment vas tu ?");
}


Lorsqu'on souhaite appeler cette fonction, il suffit d'écrire :

dire_bonjour2("Nounours");

Ce qui affiche : Bonjour Nounours !! Comment vas tu ?
(C'est vrai ça... Bonjour Nounours !! Tu vas bien ?? Oui j'espère !! )


Ou encore :

parite(integer i){
if (i%2 == 0){
llSay(0, "le nombre "+ i + " est pair");
}else {
llSay(0, "le nombre " + i + " est impair");
}
}

que l'on appellera de cette manière :

parite(25);


Une petite dernière avec plusieurs paramètres :

compare(integer i, integer j){
if ( i <=j ){ llSay(0, i + " est plus petit ou égal que "+ j);
} else {
llSay(0, i + " est plus grand que "+ j);
}
}


Et pour finir une fonction qui retourne une valeur, quelle est ou non des paramètres. Son squelette :


type ma_fonction(type1 variable1, type2 variable2, ...){
instruction1;
instruction2;
....
return valeur;
}


Prenons un exemple : une fonction qui fait la somme de deux entiers. Bon je sais, on peut le faire avec un simple +, mais enfin !! C'est qui le prof ici ?? Grrrrrr......

integer ajoute(integer i, integer j){
return i+j;
}


On utilise cette fonction de la manière suivante :

integer h;
h= ajoute(10, 25);



III. Un peu de pratique


Dans son cours sur l'importance d'un bon algorithme, Nounours nous donne deux fonctions, écrites en langage algorithmique. Essayons de les ecrire en LSL. Je rappelle que l'une de ses fonctions est optimisée alors que l'autre non


1) La fonction non optimisée :

Je rappelle l'algorithme :

somme_entier_naturels_version1 ( n )
{
// Cette fonction va sommer tous les entiers de 1 à n (n étant un paramètre)
// On crée une variable résultat qui aura pour nom "somme"
somme = 0
POUR compteur DE 1 A n FAIRE
// On crée une variable compteur qu iprendra successivement
// les valeur entieres de 1 à n

// On fait la somme des entiers de 1 à n et on le stocke dans "somme"
somme = somme + compteur;

// Fin de la boucle "POUR", donc le programme restera dans cette boucle
// tant que compteur sera compris entre 1 et n.
// L'incrémentation de compteur se fait automatiqueemnt
// à la ligne "POUR compteur..."
FIN_POUR

// On retourne le résultat "somme" qui contient, grace à la boucle "POUR",
// la sommation des entiers de 1 à n
RETOURNER somme
}


Cela nous donnera en LSL :

integer somme_entier_version1(integer n){
integer somme = 0;
integer compteur;

for (compteur = 1; compteur <= n; compteur++){ somme = somme + n ;
// ou encore : somme += n;
}

return somme;
}



2) La fonction optimisée

Je rappelle l'algorithme :


somme_entier_naturels_version2 ( n )
{
// Cette fonction va sommer tous les entiers de 1 à n (n étant un paramètre)
// On sait que la somme des entiers naturels de 1 à n est une formule mathématique!
// http://fr.wikipedia.org/wiki/Somme_(arithm%C3%A9tique)
// somme = n * (n + 1) / 2
// Pourquoi ne pas réutiliser ce résultat?
// On crée une variable somme, et on lui met la formule!

somme = n * (n + 1) / 2

// Et maintenant, on retourne le résultat!
RETOURNER somme
}


Cela nous donnera en LSL :

integer somme_entier_version2(integer n){
integer somme;
somme = n * ( n + 1) / 2;
return somme;
}

On pourrait aller encore plus vite en écrivant directement :

return n * ( n + 1) / 2;




IV. Conclusion

Voilà, c'est tout pour aujourd'hui. Vous pouvez éteindre votre cerveau. La prochaine fois, je parlerai de certaines fonctions LSL, dont celles en rapport avec le type string, qui je le rappelle, ne concerne en rien le vêtement coupe-crotte très à la mode.
Ce prochain cours sera l'avant dernier dernier......

Non, pas d'inquiétude, je ne vais pas arrêter !! Mais puisqu'il s'agit d'un cour d'initiation au LSL, nous en avons fini. Nous passerons à des cours tout courts !!
Avec de vrais bouts de code utiles dedans.

Aucun commentaire: