Les Fonctions

Les Fonctions

> Tutoriel LeekScript

Dans un programme, le plus important est de bien structurer son code. Pour cela vous avez appris l'utilisation des commentaires et c'est à peu près tout... Mais on va vite changer cela avec les fonctions, une des notions les plus importantes en programmation et vous allez vite comprendre. Vous en avez déjà croisées et même utilisées dans le chapitre des Les Fonctions Natives.

Qu'est-ce que c'est ?

Une fonction est une suite d'instructions, rien de plus. Ainsi plus de duplication de code, il suffit d’appeler la fonction qui va exécuter ces instructions. Afin de rendre les fonctions plus polyvalentes, on peut leur donner des paramètres comme par exemple le poireau que l'on veut frapper, le nombre de MP qrestants pour ce tour, etc. De plus la fonction peut retourner une valeur comme un tableau avec toutes les cases accessibles par notre poireau. Voici le prototype, i.e. la signature, d'une fonction :

NomDeLaFonction ( parametre1, parametre2, ..., parametreN ) : Retour

Le prototype, c'est la description de la fonction : son nom, son retour si il en y a un et ses paramètres qui sont aussi optionnels. La définition d'une fonction, c'est l'ensemble des instructions présentes dans celle-ci. Tous les prototypes des fonctions natives sont accessibles dans la documentation. Sur la gauche, dans la liste des fonctions triées par thème, si on sélectionne "UseWeapon" dans la catégorie Armes, on trouve ceci : !UseWeapon-Mod

Que se passe-t-il lorsque l'on appelle une fonction?

Lors de l'appel d'une fonction, le programme 'principal' se met en pause pour exécuter le programme stocké dans la fonction. Puis à la fin de cette fonction, le programme 'principal' reprend là où il s'était arrêté.

La déclaration

On parle aussi de déclaration pour les fonctions. En effet le LS vous propose des fonctions natives prêtes à l'emploi tel que "getNearestEnemy / useWeapon / ...". Mais il est possible d'en créer par vous mêmes. Voici la syntaxe à adopter :

function NomDeLaFontion ( parametre1, parametre2, ..., parametreN ) { /* Les instructions */ }

Il n'est pas possible de tout faire dans une fonction : la déclaration d'une nouvelle fonction ainsi que la déclaration d'une variable globale sont interdites !

Pour être plus parlant, nous allons créer une fonction très simple, son but va être de se rapprocher du centre de la carte, de lancer une puce de bouclier et une de soin. Voici son prototype : (A noter que le prototype n'est pas à mettre dans le code, sauf à la rigueur en commentaire pour expliquer votre fonction)

ArmorAndCare()

Rien de plus simple en effet, notre fonction ne prend pas de paramètre et ne retourne rien !

Il lui manque tout de même une définition que voilà :

function ArmorAndCare(){ moveTowardCell(306); useChip(CHIP_ARMOR, getEntity()); useChip(CHIP_CURE, getEntity()); }

Pour appeler la fonction, c'est comme les autres :

ArmorAndCare(); // Se rapproche du centre de la carte puis lance ARMOR et CURE

Remarque importante, une fonction ne peut pas accéder aux variables extérieurs sauf les globales. Il faut imaginer que lorsque l'on appelle la fonction, celle-ci "vit" dans son propre monde et que la seule chose à laquelle elle a l'accès sont les variables globales et les autres fonctions.

Afin d'illustrer le système des paramètres et des retours de fonctions nous allons prendre cet exemple :

// Prototype : getCellDistanceTo(leek) : (Nombre) Distance entre mon poireau et celui en paramètre function getCellDistanceTo(leek){ return getCellDistance(getCell(), getCell(leek)); }

D'après le prototype, la fonction prend en paramètre un poireau (son ID), et retourne la distance entre celui-ci et son propre poireau. La liste des paramètres est (presque) infinie, il suffit de séparer chaque paramètre par une virgule. Le retour de la fonction s'effectue avec le mot clé 'return'. Dans cet exemple la fonction 'getCellDistance' renvoie un nombre que l'on renvoie directement. Lorsque la fonction rencontre un 'return', elle s’arrête et reprend à l'endroit de l'appel de la fonction. Pour les intéressés, le principe de réduire le nombre de paramètre d'une fonction s'appelle la 'currification'. Si vous voulez arrêter prématurément la fonction sans renvoyer une valeur, il suffit de placer le mot-clé 'return' sans valeur.

Passage par référence

Dans les exemples ci-dessus, les données envoyées lors de l'appel d'une fonction sont copiés. Voici ce qu'il se passe :

function getCellDistanceTo(leek){ return getCellDistance(getCell(), getCell(leek)); }

var enemy = getNearestEnemy();

getCellDistanceTo(enemy );

// 1 - Appel de getNearestEnemy qui renvoie un ID de poireau (exemple : 2) // 2 - enemy vaut maintenant '2' // 3 - Appel de getCellDistanceTo qui prend un paramètre (dans l'exemple : enemy soit 2) // 4 - Dans la fonction getCellDistanceTo : 'leek = 2;' s'execute puis la définition de la fonction // 5 - Appel de getCellDistance : copie de 'getCell()' (le retour) et de 'getCell(leek)' (le retour aussi) // 6 - Retour de la distance entre les deux poireaux

Que signifie cette copie ? Si l'on modifie 'leek' dans 'getCellDistanceTo', notre variable 'enemy' ne sera pas modifiée.

Prenons un exemple qui illustrera mieux le passage par référence :

// Prototype // canDivide (result, (Nombre) a, (Nombre) b) : (Bool) True si l'on peut diviser 'a' par 'b' et stocke le resultat dans 'result'

// Définition function canDivide (result, a, b) { result = 0; if (b === 0) return false; // La division par zéro n'est pas possible // Pas besoins de 'else' car si b === 0 la fonction sera arrete result = a / b; return true; }

Pour l'instant on parle de "passage par valeur" car lors de l'appel à cette fonction, tous les paramètres sont copiés. Pour effectuer ce passage par référence, il faut utliser un '@' avant le paramètre (dans la définition) :

function canDivide2 (@result, a, b) { result = 0; if (b === 0) return false; // La division par zéro n'est pas possible // Pas besoins de 'else' car si b === 0 la fonction sera arrêtée result = a / b; return true; }

Grâce à ceci, si l'on modifie result, la variable qui a servi à l'appel de la fonction sera aussi modifié. Testons les deux fonctions :

var result;

if (canDivide(result, 5, 2)) // Fonction avec passage par valeur debug("La division est possible entre 5 et 2, le resultat est : " + result); else debug("La division de 5 par 2 n'est pas possible !");

if (canDivide2(result, 5, 2)) // Fonction avec passage par référence debug("La division est possible entre 5 et 2, le resultat est : " + result); else debug("La division de 5 par 2 n'est pas possible !"); /* Si on test, on obtient : "La division est possible entre 5 et 2, le resultat est : null" puis "La division est possible entre 5 et 2, le resultat est : 2.5" */

Si vous voulez plus d'explication sur le comportement du @ qui ne sert pas que dans les paramètres, je vous conseil cette page : Comportement du @

Fonction en tant qu'objet de première classe

En Leekscript, les fonctions sont des objets de première classe. On peut donc considérer la déclaration de fonction de la forme function name([parameters]) {[code]} comme étant une syntaxe spécial. Cela se remarque notamment en terme de périmètre. Le langage considère que les fonctions déclarées de la sorte sont à part, et seul les objets dans le périmètre global (dont elles-mêmes) sont accessibles à l'intérieur de leur propre périmètre. Manipuler les fonctions comme n'importe quel objet de première classe nous permet de les considérer de manière bien plus intéressante. Rappelez vous ce qu'il est possible de faire avec les nombres/chaînes de caractères/tableaux:

Fonction en paramètre

Reproduire la Lib

C'est en faisant qu'on apprends. Pour l'instant, nous allons nous contenter de reproduire les fonctions arrayX qui prennent une "callback" (c'est juste une fonction, évitons le terme callback à l'avenir). La fonction en paramètre n'attendras qu'un ou deux arguments, (nous ne manipulerons pas les tableau associatifs), et nous placerons les paramètres dans un ordre différent en prévision de la section sur les fonctions en retour. Il est recommandé de commencer par iter.

Ajouter des Fonctions Utiles

Fonction en retour