Archives pour l'étiquette TI

Tableau d’avancement (Nspire Lua)

Décidément, nous vous gâtons.
Encore une exclusivité TI-Planet aujourd’hui !

Notre cher membre Adriweb, après avoir sorti son programme de tableau d’avancement pour TI-83+/84+, nous a programmé hier son équivalent Nspire ! C’est une grande première sur cette calculatrice, d’autant plus que celui-ci profite, comme TabVar 3, de la nouveauté principale qu’offre l’OS 3, le Lua.

Le document se compose en fait de deux parties :
-> Vous lancez le programme (Basic) avancement() et suivez les étapes pour donner les informations sur la réaction chimique à étudier.
-> Allez dans l’onglet suivant et admirez le tableau d’avancement tracé en détail et en couleur (Nspire CX uniquement) !

Un petit screenshot ?

Image

Ce programme est open-source et sous licence Creative Commons 2.0 BY-SA.

Lien du topic sur TIPlanet (téléchargement ….) : http://tiplanet.org/forum/viewtopic.php?f=43&t=8385

TI-Planet : le site qui crée des programmes intelligents !

Au passage, joyeux halloween ;-)

Enregistre un record (ou autre) sans possibilité de triche !

Dans ce tutoriel nous allons voir une notion assez intéressante du framework de la TI-Nspire en Lua : enregistrer et restaurer des données dans un format quelconque directement en Lua ce qui permet par exemple de se souvenir d’un record pour un jeu, ou une quelconque configuration pour un programme plus évolué.

Mise en situation : Nous venons de réaliser un jeu génial. Nous voulons que nos camarades puissent se mesurer à notre record, mais comment faire ?

La première méthode consiste à utiliser l’API var et d’appeler var.store(). Ainsi, on sauvegarde le record dans le classeur comme variable globale.

Votre système de record est en place ! Hum, pas si vite : un de vos camarades a réussi à faire un score de 10 000 000 ! Comment est-ce possible ?? Il a simplement édité la variable qui vous sert de record. Etant donné qu’elle est accessible via une application Calcul et modifiable à souhait cela n’est pas compliqué !

La deuxième méthode utilise la première, à ceci près que nous disposons de math.eval() qui nous permet d’exécuter n’importe quelle commande du TI-Basic, comme la commande Lock par exemple. Ainsi, si nous faisons :

math.eval("Unlock highscore")
var.store("highscore", highscore)
math.eval("Lock highscore")

Notre variable est protégée contre l’écriture. Seulement, étant donné que Lock est une commande présente dans le TI-Basic, elle peut très bien être exécutée à l’extérieur du programme Lua. Donc cela ne fait que repousser le problème.

Et si nous nous tournions vers le Lua en lui même ? En effet, il existe var.monitor() qui permet de poser une sentinelle qui vérifie si la variable pointée va être changée. Si oui, alors l’évènement on.varChange() est appelé. L’intérêt d’utiliser cette technique est qu’elle permet de contrôler la modification de la variable. En effet :

function on.create()
  if not var.recall("highscore") then
    highscore = 0
    var.store("highscore", highscore)
  end
  var.monitor("highscore")
end
 
function on.varChange(list)
  for k, v in pairs(list) do
    if k == "highscore" then
      if var.recall(k) ~= highscore then
        return 1 -- it is an external change, block modifications
      else
        return 0 -- it is an internal change, allow modifications
      end
    end
  end
  return 0 -- allow modifications of other monitored variables if any
end

Ce code empêchera toute modification extérieure de record par un message d’erreur :

Changement non autorisé : Entrée non valide.

Seulement voilà … C’est une méthode lourde et répétitive si on doit le faire pour plusieurs données, telle des données de configuration … C’est là que l’on regarde la documentation et qu’on aperçoit deux évènements qui pourraient paraître banals à première vue : on.save() et on.restore(). En réalité, ce couple d’évènement gère ce que nous essayons de faire depuis le début !

En effet, lorsque le widget est fermé (on ferme le classeur, on copie/coupe le widget), l’évènement on.save() est appelé. on.save() doit être écrit de telle sorte qu’il puisse renvoyer une donnée quelconque (booléen, nombre, chaîne de caractères, table etc …).
Lorsque le widget sera ouvert la prochaine fois (on ouvre le classeur, on colle le widget), l’évènement on.restore() sera appelé avec en paramètre cette donnée que nous avions renvoyé depuis on.save() !

Ainsi, plus de prise de tête :

function on.save()
  return highscore
end
 
function on.restore(data)
  if type(data) == "number" then
    highscore = data
  end
end
 
function on.create()
  if not highscore then
    highscore = 0 -- first time we initialize highscore
  end
end

L’Essentiel pour bien comprendre

Cette partie va tenter de vous expliquer comment le Lua fonctionne concrètement dans l’OS et vous aider à comprendre ce que vous faites lorsque vous écrivez un script pour TI-Nspire. Toute connaissances préalable en Lua ou d’un quelconque langage évènementiel n’est pas inutile, mais pas nécessaire.

Le Lua est un langage script interprété, ce qui signifie que ce n’est pas aussi rapide que l’ASM/C mais que cela reste bien mieux que le TI-BASIC. Une bonne chose à noter, c’est que ce langage est en parfaite harmonie avec l’OS car lié par une structure évènementielle et un assez confortable environnement graphique (GC). Tout d’abord, nous devons comprendre comment tout cela fonctionne.

Le Lua est normalement un langage script séquentiel. Par exemple, quand on demande d’afficher une valeur avec la commande print(), on peut très facilement deviner dans le code quand est-ce que la commande sera lancée. Voici un code d’exemple :

a = 1
print(a)
a = a + 1
print(a)

En sortie :

1
2

Rien de très surprenant. Seulement, sur TI-Nspire, le Lua a une toute autre approche. On rencontre cette approche lorsqu’on programme avec des langages de haut niveau ou objet (tel que le C++/Qt4, C#, etc …). Dans ces langages, nous ne sommes pas maîtres de l’exécution de tel ou tel code. Oui, c’est étrange d’entendre dire ça, et pourtant c’est la vérité. Nous allons programmer dans un langage qui ne nous obéit pas ? En quelque sorte, oui.

Pas d’inquiétude ! Nous sommes là pour vous aider à ce passage difficile si c’est la première fois que vous le franchissez !

Tout d’abord, il faut vous placer de l’autre côté du miroir. Avant, vous étiez le patron, c’est à dire que vous ordonniez à la machine de vous calculer 1 + 1 et elle vous renvoyait fièrement 2. Maintenant, vous êtes un ouvrier. On vous donne l’autorisation de faire une tâche, vous dites comment faire à la machine. Concrètement, les « autorisations » sont des évènements. Vous avez le droit de faire ce que vous voulez, à moins que vous en ayez reçu l’autorisation. Voici un pseudo code qui montre que faire lorsque l’évènement « FaireLaCuisine » est appelé :

function FaireLaCuisine()
	organiserLaPaillasse()
	couperLesIngredients()
	assembler()
	chauffer()
	servir()
end

Vous comprenez bien que vous n’allez pas faire la cuisine une fois qu’on vous a embauché. Vous allez attendre que votre maître de maison vous en donne l’autorisation/l’ordre pour la faire ! Et bien c’est la même chose en Lua sur TI-Nspire. Tout est question d’évènements ! Dans notre exemple – en imaginant que FaireLaCuisine est un évènement de l’API – l’API appelle la fonction FaireLaCuisine si elle existe lorsque les conditions nécessaires sont réunies.

Donc, si on résume, tout code de notre part doit être mis dans des fonctions que la TI-Nspire va lancer. Mais comment savoir lesquelles ? Et bien c’est là que nous vous invitons à jeter un œil à cette liste des évènements. Lorsqu’un évènement est appelé, il lui est passé zéro ou plusieurs arguments que l’on peut réutiliser dans le corps de la fonction. Cela permet par exemple de savoir quelle touche est actuellement active, car lorsque l’évènement charIn() est appelé, on lui passe en plus une chaîne de caractère correspondant à cette touche. Par contre, lorsque l’évènement enterKey() est appelé, aucun argument n’est nécessaire, donc aucun n’est passé.

Avant, dans un langage quelconque n’étant pas évènementiel (BASIC, C, PHP, etc …), on programmait de cette manière :

-- Initialisation des constantes ici
...
 
k = 0
while k != 0 do
	k = getKey()
end
if k == 72 then
	-- quelque chose
end

Maintenant, cela ressemblera à ça :

-- Initialisation des constantes ici
...
 
function on.charIn(ch)
    if ch == "7" then
	-- quelque chose
    end
end

>> Partie 2