Bienvenue sur le site francophone des TI-83 Plus et des TI-83 Plus Silver Edition   Le matériel Câble TI-PC fait maison et bon marché Télécharger Émulation Jouer en réseau avec deux TI Écouter de la musique sur sa TI
Espace programmation Tutoriels FAQ, Questions fréquemment posées Forum Trafiquer sa TI-83 Plus Liens vers les meilleurs sites sur les TI
 

Sondage Chat
Nouveautés
Contactez-moi

 
Découvrez le jeu Web de serpent addictif
réalisé par l'auteur de ce site :


Poster carte du monde satellite et politique XL 91,5 x 121,6 cm (noms en français)
Affiche murale géante de carte du monde moderne et artistique :
visuel réaliste, issu d'images satellites de la NASA, aux couleurs vives.
Image très détaillée et informative : les noms des pays et villes sont en Français.

Accueil / Espace programmation / Dossiers de programmation / Optimisations BASIC

Nous allons voir comment optimiser le code des programmes, autant pour faire baisser la taille que pour en augmenter la rapidité!
Vous apprendrez comment modifier telle ou telle ligne à bon écient.
Ce dossier s'étoffera au fur et à mesure que des astuces seront découvertes : vous pouvez participer en envoyant vos astuces.

Documentation utilisée
Pour faire ce tutorial, je me suis aidé de 83trix.txt (que j'ai traduit pour les besoins de ce tutoriel) et de Saving Memory in TI-BASIC Programs.
J'ai également ajouté des trucs que j'ai trouvé par moi même ou que l'on m'a indiqué.
Je remercie également Raphaël Domenge qui m'a aidé en ce qui concerne les tests de rapidité (variables et autres).
Vous découvrirez ainsi beaucoups d'optimisations inédites...
Optimisations simples :
En fin de ligne, vous pouvez ne pas fermer les parenthèses ou les gillemets. C'est la règle la plus importante!
Le caractère "->" ferme aussi les parenthèses automatiquement, de même que les guillemets.
Par contre, le caractère ":" ferme les parenthèses mais pas les guillemets.
If LSN(8)>-1 : dans ce genre d'utilisations, il ne faut pas hésiter à réinterpréter comme ceci : If -1<LSN(8 pour gagner un octet (la parenthèse de fermeture)
Calculez le plus posible d'opérations si elles ne demandent pas de variables. Exemple : 4^3 deviendra 64 : vous gagnez un octet.
Idem pour A^2 et A^3 qui deviennent A2 et A3 (le 3 se trouve dans [MATHS] [3]).
N'utilisez jamais * si vous faites un multiplication avec au moins une variable. Exemple : 5*X deviendra 5X.
De même, une multiplication est plus rapide qu'une division. Exemple : remplacez toujours A/2 par .5A. Et A/10 par .1A.
Les nombres en zéro virugle quelque chose n'ont pas besoin du zéro initial pour être compris par l'OS. Ainsi 0.214 peut s'écrire .214 pour gagner un octet!
100
s'écrit E2 (2 est le nombre de 0) : vous gagnez un octet ceci est plus lent (en effet, la calculatrice calule ce que donne E2 alors que pour 100, il n'y a pas besoin).
Réorganisations du code :
Si vous avez l'occasion d'utiliser IS>( ou DS<(, faites-le : c'est plus petit et plus rapide.
If K=24:X-1->X peut s'écrire plus rapidement X-(K=24->X. Vous gagnerez deux octets et le programme s'exécutera plus rapidement.
De même pour plusieures conditions : If K=24:X-1->X:If K=26:X+1->X s'écrit X-(K=24)+(K=26->X.
Préferez DelvarA à 0->A : vous ne gagnez aucun octet (en effet, il s'agit d'une commande qui prend deux octets) mais cela s'exécute plus rapidement et vous pouvez omettre les : si vous réinitialisez plusieures variables à la suite. Exemple : DelvarADelvarBDelvarC. Ici, vous gagnez deux octets et cela libère l'espace reservé à la variable (18 octets).
Il n'y a pas que Delvar qui prend deux octets ; il y a aussi Picx : lorque vous stoquez ou recalez une image, mettez juste le numéro de l'image et non sa variable. Exemple : StorePic Pic1 peut être remplacé par StorePic 1.
À l'instart de Delvar, toujours, avec les instructions Archive et Unarchive, les : peuvent être négligés. Attention : ceci n'est valable que pour la version 1.12 et n'est pas possible avec la 1.14. Il est donc recommandé de ne pas utiliser cette optimisation si vous mettez votre programme sur internet.
Les conditions peuvent souvent être amoindries. Exemple : If N<>0 devient If N et If N=0 devient If not(N.
Pour passer de zéro à un ou de un à deux dans l'exemple d'un jeu à deux joueurs à tour de rôle, normalisez le joueur un comme égal à 0 et le joueur deux comme égal à 1 (pour afficher le joueur en cours, ajoutez 1). Ensuite, pour passer d'un joueur à un autre, faites simplement not(N->N. Il existe aussi une autre solution : N xor 1-> N. Vous perdez un octet mais il est bon de savoir cette astuce...
Pour remettre à zéro une liste, utilisez cette formule : DelvarL1:X->dim(L1. Cela permet de remettre à zéro la liste (en l'effacant : au cas où il y aurait déjà des nombres stoqués) puis de la recréer. C'est la structure la plus petite possible.
Disp"HELLO
Disp"WORLD

et
Disp"HELLO","WORLD prennent autant d'octets : c'est plutot un choix estétique qui est à faire.
Par contre, si vous voulez faire une pause après ce Disp, vous pouvez utiliser
Disp"HELLO
Pause "WORLD
: vous gagnerez deux octets.
Sachez aussi que vous pouvez mêttre plusieurs textes à écrire avec l'instrucion Text(. Exemple : Text(25,20,P," points. Ici, la variable numérique est directement concaténée au texte " points" pour être affiché sur l'écran grapique.
Si vous avez une incrémentation négative dans une boucle For(, préférez For(L,0,8:Disp 8-L à For(L,8,0,-1:Disp L : vous gagnerez un octet.
Je vous conseille de ne jamais utiliser Stop : en effet, il vous viendra peut-être un jour à l'idée (ou quelqu'un d'autre) d'insérer votre programme dans un shell en BASIC : préférez Return et, le plus souvent possible, essayez de finir à la fin du programme : cela vous épargnera deux octets.
Pour faire des sprites, utilisez l'instruction Text( avec des espaces pour effacer une partie de l'écran rapidement.
Si vous avez de plus grands espaces à effacer, utilisez Text(-1.
Préférez l'utilisation des boucles (For(, Repeat(, While() le plus souvent possible et banissez à tout prix les labels (sauf pour les menus, bien sûr) car lors d'un appel, le programme est scanné de haut en bas : ce qui peut être très long.
Rappelez-vous que votre TI est faite pour faire des calculs : optimisez le plus possible vos algorithmes en utilisant les instructions disponibles sur la TI.
Pour calculer 1/X, utilisez X-1 en appuyant sur la touche [x -1].
L'application Finance contient dbd( qui permet de calculer le nombre de jours entre deux dates.
De même, servez-vous aussi de vos acquis en mathématiques : ainsi, A(B+C)-7 deviendra AB+AC-7 après dévelopement. Il s'agit là d'un exemple simple car tout le monde connaît les dévelopements mais vous pouvez utiliser d'autres théorèmes (Pythagore (pour des coordonnées...), identités remarquables...).
En reprennant cet exemple, on remarque qu'on ne peut pas enlever la parenthèse fermante car ensuite il y a une soustraction (si c'était un plus, on aurai pu le mettre au début pour enlever la parenthèse)... Faites attention à ne pas supprimer des parenthèses qui servent réellement, surtout dans des calculs...
Utilisez des sous-programmes si une suite d'instructions est répétée.
"->L1
: si la liste n'existe pas, elle est crée avec une dimention de 0. Si celle-ci existe, la dimention et les valeurs sont gardées (rien n'est changé).
Enfin, faites attention : l'utilisation de la variable Y n'est pas une bonne solution car, lors de l'utilisation de ClrDraw, celle-ci est remise à zéro.
Utilisation de la variable Ans :
Cette variable est la plus rapide et elle vous permet parfois de gagner pas mal d'octets.
Exemple d'utilisation : Repeat Ans:getKey:End:If Ans=105:Goto M ...
Ce code peut remplacer : Repeat K:getKey->K:End:If K=105:Goto M ...
De même, voici un programme qui choisit au hazard une chaine et l'affiche (cas dun chat avec la calculatrice par exemple) : les variables de type Strx prennent deux octets : il convient d'utiliser Ans de cette façon :
:randInt(1,5->N
:If N=1:"SALUT
:If N=2:"CA VA ?
:If N=3:"MON CHIEN EST MORT
:IF N=4:"JE PEUT PARLER ?
:If N=5:"IL FAUT QUE J'Y AILLE!
:Disp Ans

Ici, on voit nettement le gain d'octets. Attention: on ne peut pas faire :randInt(1,5:If Ans=... car si Ans serai égal à un chiffre (2 par exemple, si randInt( a renvoyé ce chiffre) alors la chaine correspondante serai aussi stoquée dans Ans ; or, à la ligne suivante le test voudrai dire "Si une chaine (Ans) est égale à un chiffre (3 dans notre exemple) Alors..." Or cela est impossible! Faites attetion dans l'utilisation de cette variable.
Pour savoir si une fonction modifie la variable Ans, tapez-la dans l'écran principal : si un résultat est renvoyé alors celui-ci est placé dans Ans.
Maintenant, c'est à vous de voir ce que vous pouvez faire de cette variable et de l'utiliser à bon escient. Son utilisation étant vaste, elle ne sera pas détaillée : à vous de faire des tests et, après quelque temps, vous la connaitrez bien...
Plus de rapidité :
Bien entendu, vous utiliserez toutes les astuces vues précédemments et, dans la plupart des cas, un octet en moins permet d'accélérer le programme (même si ca ne se voit pas forécment).
Mais ce n'est pas toujours le cas : Output( est deux fois plus rapide que Disp ! Cela s'explique par le fait qu'il n'y a aucun formatage à faire avant l'affichage, ni réorganisation de l'écran (passer une ligne...). Très utile si vous devez effacer l'écran en "gardant" la première ligne par exemple : l'effacement puis le réafichage se fait quasi-instantanément.
Ensuite, la variable Ans doit être utilisée le plus souvent possible!
L'astuce la plus simple pour accélérer un jeu est en même temps la moins connue : lorsque vous configurez l'écran graphique, ajoutez cette ligne : 0->Xscl:0->Yscl . Ainsi, lorsque vous appelerez ClrDraw, cette commande sera 50% plus rapide! Pratique pour accélérer des pseudo-vidéo faites d'images séparrées par un effacement de l'écran.
Si vous ne refermez pas vos boucles (Goto menant hors de la boucle, voir même à l'interieur de celle-ci qui ne se terminera donc pas normalement), le programme ralentira rapidement. Idem si vous utilisez Goto dans Then-End.
Certaines variables sont plus rapides d'accès que d'autres. Dans l'ordre, de la plus rapide à la plus lente : Ans;theta;X;Y;A;B;C;...;W;Z. Mais la différence est minime! (0.015 secondes pour X et 0.019 secondes pour Z, la plus lente). Utilisez theta dans les boucles For(.
De même, L1 est la liste la plus rapide (après Ans) et la vitesse décroit jusqu'à L6. Ensuite, viennent les listes personnalisées qui sont bien plus lentes.
Un petit test pour vous éclairer : pour 100 accès et avec la ROM 1.12 :
Matrice A : 1.48 s
Liste perso X : 1.24 s
Liste L1 : 1.10 s
Variable A : 0.85 s
On en conclue qu'il est préférable d'utiliser des variables que des listes et si ce choix devait être fait, utiliser les liste 1 à 6 avant celles personnalisées, etc...
Les instructions Pxl-On(), Pxl-Off() et Pxl-Change() sont un peu plus rapides que les instructions Pt-On(), Pt-Off() et Pt-Change() (gain de sept secondes sur 2000 instructions). Par contre, ces deux groupes de trois s'exécutent à la même vitesse respectives.
Ajouter un nombre à la suite d'une liste : Vous avez deux solutions :
- augment(L1,{N->L1
- dim(L1)+1->dim(L1:N->L1(Ans
La première ligne ne prend que 9 octets et la seconde 17 octets.
Mais la contrepartie est que la première ligne est deux fois plus lente que la seconde.
Pour 100 rajouts, la première ligne met 6 secondes contre 3 pour la première.
Le précalculé :
Au lieu de faire :
Getkey-> K
X+(Ans=26)-(Ans=24->X
Y+(K=34)-(K=25->Y

On peut faire :
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,1,0,0,0,0,0,0,0,1->L1
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,1->L2
Getkey->K
X+L1(Ans->X
Y+L2(K->Y

Ceci est une petit aproche du précalculé. En effet, si le joueur appui sur [Y=], rien ne se passera (0 sera ajouté à X et à Y). En revanche, s'il appuie sur droite, X sera augmenté de 1, etc... Pour être plus efficace et ne pas générer de plantage si le joueur appuie sur [ENTER] par exemple (ENTER=105 : L1(105 donne ERR:INVALID DIM ), il faudrai faire comme suit :
105->dim(L1
-1->L1(24
1->L1(26

Idem pour L2...
Vous remarquerez que l'on gagne beaucoup de vitesse avec le précalculé!
Exemple plus flagrant : si l'on veut faire un jeu avec des angles, il faudra utiliser sin( et cos( (voir même tan( ). Or, ces fonctions sont très lentes! C'est dans ce genre de situation que l'on voit l'interêt du précalculé : il faudra précalculer les angles et y accéder via une liste qui contiendra d'avance les résultats...
Un autre exemple? Et bien rand et randInt( sont des commandes aussi coûteuses en rapidité. Si vous désirez avoir un jeu rapide, faites une étape de chargement qui calculera une liste de nombres aléatoires avant de jouer. Mais atention : si vous ne prévoyez pas assez de nombres, le jeu risque de planter. Aussi, si vous ne savez pas combien de nombres devront être tirés au hazard, vous pouvez revenir au début de la liste à chaque fois que celle-ci est terminée. Ou alors, s'il y a une petite pause entre deux moments, profitez-en pour "piocher" les nombres suivants.
Cette méthode ouvre la voie à beaucoupe de possibilités. Je vous y ai juste sensibilisé : ce sera à vous de voir quel programme demande du précalculé pour fonctionner plus rapidement. Il serai bon d'appliquer le premier exemple dans tous les jeux qui demandent de la rapidité...
Compression :
Si vous utilisez des listes pour stoquer de nombreuses données (coordonnées par exemple), il est bon de la compresser avant de terminer le programme pour libérer de la place. En effet, chaque case d'une liste prend invariablement 9 octets quel que soit le nombre stoqué (entier ou à virgule). Autant mettre 2 voir 4 chiffres dans chaque case : vous diminurez ainsi par quatre la taille de la liste. Et, si elle est utilisée pour stoquer des niveaux, vous pourrez ainsi en mettre quatre fois plus sur une TI! Comment faire?
Tout d'abord, il faut que ces nombre ne puissent pas dépasser un sertain nombre : exemple si ce sont des coordonnées qui sont stoquées, elles vont de 0 à 94 (X et Y confondus) si WINDOW est bien configuré.
Ainsi, par exemple, le code de compression de coordonnées par 2 sera : X+.01Y->L1(A
Et la lecture se fera ainsi pour X : iPart(L1(A->X ; et pour Y : 100fPart(L1(A.
Nous venons de voir une compression par deux. En continuant, on obtiendrai une compression par quatre :
100A+B+.01C+.0001D->L1(A
Si A=12 ; B=53 ; C=45 ; D=86 : L1(A=1253.4586. Quatre chiffres seront ainsi stoqués dans une seule case de neuf octets (contre 36 sans compression).
La décompression se fera de la même façon que pour l'exemple un :
L1(X->Y:iPart(.01Y->A:iPart(Y-100A->B:iPart(100fPart(Y->C:100fPart(100fPart(Y->D
Ce sera plus long (décompression oblige) mais l'avantage d'avoir plus de niveaux (ou de place pour le reste des programmes) est un assez bon argument pour employer cette méthode. Bien sûr, ce ne devra pas ce faire durant un jeu (chargement seulement) et le nombre de coordonnées doit être un multiple de quatre si vous optez pour cette compression.
Tout comme le précalculé, on ne peut donner toutes les méthodes de compression : ce paragraphe n'a pour but que la sensibilisation à ce sujet : vous compresserez comme vous le voudrez, comme le programme le permettra, mais surtout vous savez maintenant que ce moyen existe...
Le bon et le mauvais programme :
Un bon résumé que j'ai trouvé je ne sais plus où sur internet :
BON PROGRAMME : original ; rapide ; petit en taille ; pleins de fonctions ; facile à utiliser
MAUVAIS PROGRAMME : trop de If ou de labels ; gros en taille ; lent ; contient des erreurs
Conclusion :
Je suis sûr que vous avez trouvé ça interessant (mais long, le sujet étant vaste) : si vous voulez faire des jeux rapides, il va falloir passer par là, de même que si vous faites beaucoups de petits programmes : vous pouvez gagner beaucoup d'espace! Je vous conseille de reprendre pas mal de programmes et de les optimiser à fond : vous découvrirez surement une astuce par vous même. Plus vous vous entrainerez, moins cette étape sera indispensable pour vous car vous aurez pris le réflexe d'optimiser automatiquement.