Ta formidable TI-83 Premium CE dispose depuis janvier 2017 de Oiram CE, un superbe moteur de jeu Mario-like par MateoConLechuga.
Un moteur qui en plus de venir avec des niveaux par défaut a le gros avantage d'accepter les niveaux perso, et également celui de la disponibilité d'un éditeur de niveaux pour Windows / Mac.
Nous nous attardons aujourd'hui sur un pack de niveaux perso absolument remarquable par Dabmaster_Arush. Ce dernier s'est en effet lancé le défi de recréer les niveaux du Super Mario Bros, le jeu vidéo sorti en 1985 pour console de jeux Nintendo NES.
Bien des difficultés en perspective, puisque Oiram CE s'inspire non pas du gameplay de Super Mario Bros, mais de celui de Super Mario Bros 3. Or ces deux jeux ont beaucoup de différences, déjà sans rentrer dans les détails rien qu'au niveau des blocs et ennemis.
Pour résumer il s'agit donc de reproduire aussi fidèlement que possible Super Mario Bros avec les 241 spritesSuper Mario Bros 3 illustrées ci-contre.
Ce n'était pas assez pour décourager Dabmaster_Arush qui nous signe ainsi Super Mario Bros Remake. Ce pack de 32 niveaux perso reproduit les 32 niveaux répartis entre les 8 mondes sur Super Mario Bros.
Nous allons te montrer de suite de quoi ça a l'air, et traiter des différences.
1er des 8 mondes du Royaume Champignon. Au menu :
1er niveau sur la terre ferme
2ème niveau sous-terrain
3ème niveau de plateformes dans une forêt de champignons géants
Ici nous renonçons aux éléments de fond d'écran, arbres, collines et nuages, bien que Oiram CE dispose pourtant de sprites qui auraient permis de les imiter. Pas de variation de couleur pour les briques sous-terraines, le sprite de brique sombre n'existant pas dans Oiram CE. Le mât de fin de niveau n'ayant lui non plus aucune existence dans Oiram CE est ici remplacé par un empilement de pièces. Le mini-donjon décoratif qui lui fait suite en fin de niveau est par contre absent et ce sera toujours le cas.
On remarque ici un manque bien embêtant de Oiram CE dans le sens où c'est visuellement très gênant; il n'y a pas de sprite pour les pièces utilisant le fond noir, et elles sont donc affichées comme si elles étaient en plein jour à l'air libre. Là encore quelque chose qui n'existe pas dans Oiram CE, les ascenseurs continus à la pater noster d'Europe centrale, sont remplacés par des paires verticales de deux plateformes constituées de blocs qui tombent. La salle secrète de warp zone est bien présente mais non fonctionnelle puisque les warp zones ne sont hélas pas gérées par Oiram CE. Au lieu de te permettre de passer au choix aux mondes 2, 3 ou 4, elle te permettra juste de passer au niveau suivant exactement comme la fin normale du niveau. C'est quand même un beau clien d'oeil de l'avoir incluse, même non inopérante.
On apprécie la belle reproduction extérieure du mini-donjon en début de niveau. Pas vraiment de sprites équivalents pour les champignons géants, Dabmaster_Arush fait comme il peut et c'est assez réussi. Dans le même style, on renonce ici aux plateformes mobiles. Celles qui se déplacent verticalement sont là encore remplacées par des paires verticales de deux plateformes de blocs qui tombent. Celles qui se déplacent horirontalement sont directement remplacées par des blocs qui tombent. Le château décoratif n'est pas illustré à la fin du niveau, et ce sera toujours le cas.
Et enfin le château. Il nous faut ici renoncer aux barres de feu remplacées par des canons, ainsi qu'au pont escamotable sur lequel déambule Bowser. Pas d'écran de fin "but our princess is in another castle" non plus.
2ème monde ici aquatique :
1er niveau sur la terre ferme
2ème niveau sous-marin
3ème niveau en bord de mer
4ème niveau avec le château
Oiram CE ne gérant pas de découpage des packs en différents mondes, les niveaux y seront numérotés 5 à 8.
Ici un manque de Oiram CE bien embêtant visuellement, les pièces placées sous l'eau n'utilisent pas le fond aquatique elles non plus. Outre les méduses, le niveau original présentait deux espèces de poissons : rouges et gris, ces derniers étant plus lents. Nous déplorons ici nos premiers ennemis manquants faute d'équivalent, tous les poissons étant donc rouges. Les algues rouges ici encore faute d'équivalent, sont remplacés par des éléments non fonctionnels de tuyaux rouges.
Dans l'original, l'enneigement était suggéré par les éléments de fond d'écran, ne pouvant être reproduits ici puisque Oiram CE ne dispose pas de version enneignée des sprites d'arrière plan. Il existe bien par contre des blocs enneigés dans Oiram CE, mais ils ont le défaut d'être glissant ce qui n'aurait pas été conforme au gameplay original. Donc bref, pas de neige ici. Nous attendions également la première apparition des emblématiques tortues frères marteaux, mais hélas elles n'existent pas dans Oiram CE et se voient remplacées chacune par une tortue zombie accomagnée de deux tortues à épines.
Autre défection parmi les ennemis, la tortue chevauchant son nuage pour lancer des oeufs de tortues à épines manque dans Oiram CE, tous comme les oeufs en question d'ailleurs. Ils se voient donc remplacés ici par une pluie directe de tortues à épines.
Ici encore un absent, les scarabés nous font défaut dans Oiram CE et sont remplacés par des tortues zombie. Les deux salles secrètres de warp zone sont là encore présentes mais non fonctionnelles, ne te permettant que de passer au niveau suivant au lieu de t'amener au choix aux mondes 5, 6, 7 ou 8.
Le château est ici difficile à reproduire car il est spécial. C'est un labyrinthe, dans le sens ou si l'on n'enchaîne pas les bonnes plateformes on est ramené en boucle au début du niveau, élément de gameplay non géré par Oiram CE. Tout juste Dabmaster_Arush t'a-t-il rajouté quelques blocs infranchissables pour te forcer à enchaîner les bonnes plateformes, là encore un clin d'oeil inutile et donc absolument indispensable.
5ème monde qui reprend le découpage du 3ème monde mais cette fois-ci en plein jour :
1er + 2ème niveaux sur la terre ferme
3ème niveau de plateformes dans une forêt de champignons géants
4ème niveau avec le château
Les niveaux correspondants sont ici numérotés 17 à 20 dans Oiram CE.
Ici encore il s'agit d'un château labyrinthe qui te ramène en boucle au début si tu n'enchaînes pas les bonnes plateformes, impossible à reproduire. Dabmaster_Arush y fait référence en te rajoutant des blocs infranchissables pour te forcer à enchaîner les bonnes plateformes comme dans l'original.
Et enfin 8ème monde avec une organisation inédite :
1er + 2ème + 3ème niveaux sur la terre ferme
4ème niveau avec le château
Les niveaux correspondants sont ici numérotés 29 à 32.
Ici encore un château-labyrinthe mais d'une autre façon. Tu dois trouver cette fois-ci le bon enchaînement de tuyaux qui t'amènera à Bowser, tout mauvais tuyau te ramenant en début de niveau. Dans l'original si tu avançais sans rentrer dans aucun tuyau, le château bouclait et te ramenait également au début, élément de gameplay impossible à reproduire ici; tu devras choisir obligatoirement un tuyau avant le mur rajouté pour t'empêcher d'aller plus loin. Dommage que Peach ne t'attende pas à la fin.
Bref un superbe pack de niveaux et avec 32 niveaux le plus grand jamais créé pour Oiram CE !
Dans la limite des nombreuses contraintes imposées par Oiram CEDabmaster_Arush te signe quand même une reproduction extrêmement fidèle de Super Mario Bros, une reproduction méticuleuse au bloc près, et tout élément ne pouvant être reproduit a été pensé et adapté avec talent toujours dans le respect du jeu original !
Félicitations Dabmaster_Arush, nous n'osons pas imaginer combien de temps tu as pu passer là-dessus !
Au nom de tous les confinés, merci en tous cas pour ce superbe cadeau qui nous va droit au cœur en ces temps si difficiles, de quoi bien nous occuper cette semaine !
Attention, pour fonctionner correctement, Oiram CE a besoin des bibliothèques C téléchargeables ci-dessous. Mais rien de bien compliqué, il suffit juste de récupérer et transférer leur fichier.
détection des simples pressions de touches clavier (sans validation donc) par l'utilisateur, avec même l'éventuel modificateur actif (
2nde
ou
alpha
), et ça marche aussi avec un clavier USB !
affichage dans la console à la ligne que tu veux
exportation de listes de nombres (entiers, flottants ou complexes) existant dans le contexte Python vers l'environnement de la calculatrice, pour traitement à l'aide d'autres applications
importation depuis le contexte Python de listes ou équation de régression existant dans l'environnement de la calculatrice
et donc plus généralement un début d'intégration du Python à l'environnement mathématique de la calculatrice, enfin l'application Python va pouvoir servir non plus seulement à coder un truc déconnecté dans un coin, mais à traiter des problèmes et tâches complexes dans leur globalité !
ti_plotlib, une bibliothèque graphique pour tracer dans un repère, conformément aux programmes de Physique-Chimie, SNT et NSI, tout en permettant également nombre d'applications en Mathématiques !
ti_hub, pour les projets d'objects connectés à l'aide de l'interface TI-Innovator Hub
def getplatform(): id=-1 try: import sys try: if sys.platform=='nspire':id=0 if sys.platform.startswith('TI-Python') or sys.platform=='Atmel SAMD21':id=4 except:id=3 except: try: import kandinsky id=1 except: try: if chr(256)==chr(0):id=5+(not ("HP" in version())) except: id=2 return id
platform=getplatform() #lines shown on screen #plines=[29,12, 7, 9,11,0,0] plines=[29,16, 7, 9,11,0,0] #max chars per line #(error or CR if exceeded) pcols =[53,99,509,32,32,0,0]
def mprint(*ls): global curline st="" for s in ls: if not(isinstance(s,str)): s=str(s) st=st+s stlines=1+int(len(st)/ncols) if curline+stlines>=nlines: input("Input to continue:") curline=0 print(st) curline+=stlines
def sstr(obj): try: s=obj.__name__ except: s=str(obj) a=s.find("'") b=s.rfind("'") if a>=0 and b!=a: s=s[a+1:b] return s
def isExplorable(obj): s=str(obj) return s.startswith("<") and s.find(" ")>=0 and not s.startswith("<module")
def explmod(pitm,pitmsl=[],reset=True): global curline if(reset): curline=0 pitmsl=[sstr(pitm)] hd="."*(len(pitmsl)-1) spath=".".join(pitmsl) c,c2=0,0 spitm=str(pitm) for itms in sorted(dir(pitm)): c,c2=c+1,c2+1 try: itm=eval(spath+"."+itms) mprint(hd+itms+"="+str(itm)) if isExplorable(itm) and itm!=pitm: pitmsl2=pitmsl.copy() pitmsl2.append(itms) c2=c2+explmod(itm,pitmsl2,False)[1] except: mprint(hd+itms) if c>0 and reset: mprint(hd+"Total: "+str(c)+" 1st level item(s)") if c2>0 and c2!=c: mprint(hd+" "+str(c2)+" item(s)") return [c,c2]
Pas mal de choses a première vue, nous découvrons déjà 30 éléments accessibles rien qu'au premier niveau, et jusqu'à 45 en comptant les sous-éléments.
Une première lecture des noms de différentes fonctions, comme getPixel() et setPixel() nous permet de deviner de quoi il s'agit. ti_graphics est un module Python permettant de dessiner sur l'écran de ta TI-83 Premium CE Edition Python, non pas en donnant des coordonnées approximatives dans un repère mais en accédant directement les pixels de l'écran ! Pour te donner un point de repère, nous pouvons donc a priori le rapprocher des modules casioplot sur Casio Graph 90/35+E II ou kandinsky sur NumWorks.
Nous allons bien évidemment te tester et documenter tout ça sans tarder, mais en attendant cela nous permet déjà de mettre à jour notre petit classement des Pythonettes :
Explorons maintenant notre environnement graphique. Pour cela nous allons utiliser quelques premières fonctions élémentaires, commençons déjà par en préciser les spécifications :
getPixel(x, y)
setPixel(x, y, c)
Quelles sont donc les dimensions de la zone graphique que nous contrôlons ? Petite astuce pour la détecter automatiquement sans intervention humaine, on peut remarquer que getPixel() renvoie (0,0,0) lorsque l'on interroge un pixel hors écran.
Un simple boucle de tests suffit alors, avec un éventuel changement de couleur préalable pour les quelques pixels de l'écran qui seraient déjà noirs.
Mettons à jours notre classe de compatibilité écrans polyscr en ce sens :
class polyscr: w, h = 0, 0 # get_pixel(x, y) # set_pixel(x, y, color(r8, g8, b8)) show_screen = lambda self: None need_show_screen = False # color mode : # 0: (R8, G8, B8) # 1: int RGB-565 color_mode = 0
def color(self, r, g=0, b=0): if isinstance(r, tuple) or isinstance(r,list): r, g, b = r[0], r[1], r[2] return self.color_mode == 0 and (r,g,b) or r<<11 | g<<5 | b
def _can_get_pixel(x, y): c = self.get_pixel(x, y) if c == self.color(0, 0, 0): self.set_pixel(x, y, self.color(255,0,0)) c = self.get_pixel(x, y) return c is not None and c != self.color(0, 0, 0)
self.w, self.h, dw, dh = 0, 0, 1, 1 while dw or dh: if not _can_get_pixel(self.w - (dw == 0),self.h - (dh == 0)): if _can_get_pixel(self.w,self.h-1): dh = 0 elif _can_get_pixel(self.w-1,self.h): dw = 0 else: dw, dh = 0, 0 self.w += dw; self.h += dh
Appelons ensuite le code suivant pour obtenir la réponse :
scr = polyscr() print('can get {}x{} pixels at (0,0)'.format(scr.w, scr.h))
Mais c'est fantastique, nous bénéficierions donc apparemment un contrôle plein écran 320×240 pixels !
Sauf que... non, fausse joie.
On se rend vite compte que même si Texas Instruments nous autorise contrairement à la concurrence à lire tous les pixels de l'écran, ceux utilisés pour l'affichage de la barre d'état en haut d'écran ne peuvent apparemment pas être réécrits :
def color(self, r, g=0, b=0): if isinstance(r, tuple) or isinstance(r,list): r, g, b = r[0], r[1], r[2] return self.color_mode == 0 and (r,g,b) or r<<11 | g<<5 | b
def _can_get_pixel(x, y): c = self.get_pixel(x, y) if c == self.color(0, 0, 0): self.set_pixel(x, y, self.color(255,0,0)) c = self.get_pixel(x, y) return c is not None and c != self.color(0, 0, 0)
self.w, self.h, dw, dh = 0, 0, 1, 1 while dw or dh: if not _can_get_pixel(self.w - (dw == 0),self.h - (dh == 0)): if _can_get_pixel(self.w,self.h-1): dh = 0 elif _can_get_pixel(self.w-1,self.h): dw = 0 else: dw, dh = 0, 0 self.w += dw; self.h += dh
# detect writable pixel array # remove top status bar
def _can_set_pixel(x, y):
def _invert_color(r, g=0, b=0): if isinstance(r, tuple) or isinstance(r,list): r, g, b = r[0], r[1], r[2] return self.color(~r & 0xFF, ~g & 0xFF, ~b & 0xFF)
c = self.get_pixel(x, y) self.set_pixel(x, y, _invert_color(c)) return c != self.get_pixel(x, y)
self.w0, self.h0 = self.w, self.h while not _can_set_pixel(0, self.y0): self.y0 += 1; self.h0 -= 1
Appelons enfin le code suivant pour obtenir toutes les informations écran :
scr = polyscr() print('can get {}x{} pixels at (0,0)'.format(scr.w, scr.h)) print('can set {}x{} pixels at ({},{})'.format(scr.w0, scr.h0, scr.x0, scr.y0))
Voilà, nous bénéficions en réalité d'un accès total à seulement 320×210 pixels, les écritures sur les 30 premières lignes de l'écran étant ignorées.
A noter que l'origine restant tout en haut à gauche de l'écran, les valeurs de paramètres y à utiliser pour tes scripts adressant les pixels démarreront obligatoirement à 30.
Puisque notre classe polyscr cible la compatibilité, profitons-en pour comparer avec les modèles concurrents :
Dans la version alpha qui a fuité pour HP Prime avec l'application Python, il y a bien une fonction prime.pixon(x, y, c) pour allumer les pixels. Mais à la différence, rien pour tester l'état d'un pixel.
Procédons donc autrement en tentant de tracer un rectangle aussi grand que possible à l'aide du code suivant :
def rect(x, y, w, h, c=(0,0,0)): for k in range(w): scr.pixon(x+k, y, c) scr.pixon(x+k, y+h-1, c) for k in range(h): scr.pixon(x, y+k, c) scr.pixon(x+w-1, y+k, c)
L'appel rect(0, 0, 320, 240, 255<<16) nous affiche bien un rectangle au complet et nous confirme donc que nous contrôlons ici la totalité des 320×240 pixels de l'écran.
D'où le classement en terme de zones graphiques dédiées au Python :
Comme vu plus haut avec les fonctions getPixel() et setPixel() et comme l'on peut encore le remarquer à quelques couleurs remarquables définies dans ti_graphics, les couleurs sont spécifiées en coordonnées RGB-888 (Rouge, Green/Vert, Bleu, avec 8 bits par canal autorisant donc des entiers de 0 à 28-1=255).
Mais couleurs spécifiées et affichées sont deux choses différentes. Pour mieux t'illustrer les possibilités Python de ton écran graphique en terme de couleurs, nous allons t'afficher un dégradé avec toutes les couleurs et tous les éclairages.
Pour cela nous travaillerons en coordonnées HSV/TSV (Hue/teinte, Saturation, Valeur), bien plus naturelles et donc intuitives pour l'oeil humain que les coordonnées RGB :
teinte qui sera ici codée par un nombre flottant de 0 à 2 est en gros ce que tu appelles naturellement couleur.
saturation, un flottant de 0 à 1 indique de façon inverse la quantité de blanc.
valeur, ici encore un flottant de 0 à 1 indique de façon inverse la quantité de noir.
Les coordonnées ainsi précisées seront alors converties en coordonnées RGB compatibles avec la calculatrice.
Bricolons-nous donc quelques petites fonctions pour ça :
def hsv2c(h,s,v): c=v*s x,m,k=c*(1-abs((h%(2/3))*3-1)),v-c,(h*3)//1 return (round(255*(m+x*(k%3==1)+c*(k%5==0))),round(255*(m+c*(k==1 or k==2)+x*(k%3==0))),round(255*(m+x*(k%3==2)+c*(k==3 or k==4))))
def grad(x,y,w,h): for i in range(w): for j in range(h): c=hsv2c(2*j/(h-1),i>=w//2 and 1 or i/(w//2-1),i<w//2 and 1 or (w-1-i)/((w-w//2)-1)) scr.set_pixel(x+i,y+j,c)
L'appel suivant nous produit alors l'affichage ci-contre :
Fantastique, non ? Quand tu penses que dans le langage TI-Basic historique tu n'avais droit qu'à 15 couleurs, mais comment as-tu pu survivre avec ça ?
Déjà pour information, on peut mesurer précisément le temps d'affichage à l'aide du script suivant. L'appel timer(grad, scr.x0, scr.y0, scr.w0, scr.h0) nous renvoie alors 25min 24,283s.
Or, remarquons un petit truc fort intéressant, une exclusivité à ce jour par rapport à la concurrence. Le module ti_graphics fournit d'origine une fonction de conversion de coordonnées HSV en coordonnées RGB, hsv_to_rgb(h, s, v). Ce qui veut dire que tu n'as pas à t'embêter à la coder et peux donc ainsi économiser de la mémoire, et qu'elle est peut-être déjà optimisée.
Empressons-nous de tester. Modifions déjà notre bibliothèque de compatibilité pour permettre l'accès à ce genre de fonction spécifique :
def color(self, r, g=0, b=0): if isinstance(r, tuple) or isinstance(r,list): r, g, b = r[0], r[1], r[2] return self.color_mode == 0 and (r,g,b) or r<<11 | g<<5 | b
def _can_get_pixel(x, y): c = self.get_pixel(x, y) if c == self.color(0, 0, 0): self.set_pixel(x, y, self.color(255,0,0)) c = self.get_pixel(x, y) return c is not None and c != self.color(0, 0, 0)
self.w, self.h, dw, dh = 0, 0, 1, 1 while dw or dh: if not _can_get_pixel(self.w - (dw == 0),self.h - (dh == 0)): if _can_get_pixel(self.w,self.h-1): dh = 0 elif _can_get_pixel(self.w-1,self.h): dw = 0 else: dw, dh = 0, 0 self.w += dw; self.h += dh
# detect writable pixel array # remove top status bar
def _can_set_pixel(x, y):
def _invert_color(r, g=0, b=0): if isinstance(r, tuple) or isinstance(r,list): r, g, b = r[0], r[1], r[2] return self.color(~r & 0xFF, ~g & 0xFF, ~b & 0xFF)
c = self.get_pixel(x, y) self.set_pixel(x, y, _invert_color(c)) return c != self.get_pixel(x, y)
self.w0, self.h0 = self.w, self.h while not _can_set_pixel(0, self.y0): self.y0 += 1; self.h0 -= 1
Modifions maintenant le script de tracer du dégradé :
def grad(x,y,w,h): for i in range(w): for j in range(h): c=scr.myscr.hsv_to_rgb(360*j/(h-1),i>=w//2 and 1 or i/(w//2-1),i<w//2 and 1 or (w-1-i)/((w-w//2)-1)) scr.set_pixel(x+i,y+j,c)
Ce n'est pas la révolution mais c'est quand même significatif, l'appel timer(grad, scr.x0, scr.y0, scr.w0, scr.h0) ne mesure plus que 24min 33,282s. On gagne 1 minute, soit environ 4%.
Bon, revenons-en enfin à cet affichage de dégradé. Si tu regardes bien, tu remarqueras que les lignes tirant sur le vert donnent 2 fois plus de teintes intermédiaires et donc un dégradé bien plus continu, bien moins saccadé.
C'est-à-dire que même si les coordonnées sont spécifiées en RGB-888, le matériel utilise pour sa part du RGB-565 :
25=32 teintes de rouge
26=64 teintes de vert
25=32 teintes de bleu
Passons maintenant à la HP Prime. La version alpha avec Python publiée par erreur n'étant pas très stable, nous utiliserons un code dédié mais équivalent :
def grad(x,y,w,h): for i in range(w): for j in range(h): _h = 2*j/(h-1) _s = i>=w//2 and 1 or i/(w//2-1) _v = i<w//2 and 1 or (w-1-i)/((w-w//2)-1) _c=_v*_s _x,_m,_k=_c*(1-abs((_h%(2/3))*3-1)),_v-_c,(_h*3)//1 scr.pixon(x+i,y+j,round(255*(_m+_x*(_k%3==1)+_c*(_k%5==0)))*2**16 + round(255*(_m+_c*(_k==1 or _k==2)+_x*(_k%3==0)))*2**8 + round(255*(_m+_x*(_k%3==2)+_c*(_k==3 or _k==4))))
On pourrait croire à la capture d'écran ci-contre présentant des saccades régulières dans l'ensemble des teintes que l'on aurait affaire à du RGB-666, ce qui n'est pas très logique. En réalité, c'est le protocole utilisé pour les captures d'écran qui fait perdre des informations couleur, et il faut donc se référer à la photo ci-contre. Sur la photo donc aucune saccade mais un dégradé des plus lisses, c'est ici du RGB-888 :
28=256 teintes de rouge
28=256 teintes de vert
28=256 teintes de bleu
Ici encore, il serait bien de pouvoir détecter cela automatiquement sans intervention humaine.
Et bien c'est possible si on se rend compte que les valeurs effectivement réglées pour les pixels diffèrent parfois de celles spécifiées.
Modifions encore une fois notre classe polyscr avec un test de ces différences :
def color(self, r, g=0, b=0): if isinstance(r, tuple) or isinstance(r,list): r, g, b = r[0], r[1], r[2] return self.color_mode == 0 and (r,g,b) or r<<(self.col_bits[0]+self.col_bits[1]) | g<<self.col_bits[0] | b
def _can_get_pixel(x, y): c = self.get_pixel(x, y) if c == self.color(0, 0, 0): self.set_pixel(x, y, self.color(255,0,0)) c = self.get_pixel(x, y) return c is not None and c != self.color(0, 0, 0)
self.w, self.h, dw, dh = 0, 0, 1, 1 while dw or dh: if not _can_get_pixel(self.w - (dw == 0),self.h - (dh == 0)): if _can_get_pixel(self.w,self.h-1): dh = 0 elif _can_get_pixel(self.w-1,self.h): dw = 0 else: dw, dh = 0, 0 self.w += dw; self.h += dh
# detect writable pixel array # remove top status bar
def _can_set_pixel(x, y):
def _invert_color(r, g=0, b=0): if isinstance(r, tuple) or isinstance(r,list): r, g, b = r[0], r[1], r[2] return self.color(~r & 0xFF, ~g & 0xFF, ~b & 0xFF)
c = self.get_pixel(x, y) self.set_pixel(x, y, _invert_color(c)) return c != self.get_pixel(x, y)
self.w0, self.h0 = self.w, self.h while not _can_set_pixel(0, self.y0): self.y0 += 1; self.h0 -= 1
if not self.color_mode:
# test color screen self.set_pixel(self.x0, self.y0, (0, 127, 255)) col = self.get_pixel(self.x0, self.y0) self.has_color = col[0] != col[1] or col[1] != col[2]
# detect color channel bits self.set_pixel(self.x0, self.y0, (255, 255, 255)) col = list(self.get_pixel(self.x0, self.y0)) for k in range(3): while col[k]<255: col[k] += 2 ** (8 - self.col_bits[k]) self.col_bits[k] -= 1
Appelons enfin le code suivant pour obtenir l'intégralité des informations écran, et les comparer aux solutions concurrentes :
scr = polyscr() print('can get {}x{} pixels at (0,0)'.format(scr.w, scr.h)) print('can set {}x{} pixels at ({},{})'.format(scr.w0, scr.h0, scr.x0, scr.y0)) print(scr.has_color and 'color' or 'monochrome') if scr.has_color: print('internal : RGB{}{}{}'.format(scr.col_bits[0], scr.col_bits[1], scr.col_bits[2]))
Voilà, nous obtenons bien comme prévu du RGB565 pour le format utilisé en interne pour les pixels
Testons également la concurrence en lançant le même code :
Au classement selon les meilleurs rendus de couleurs, nous avons donc :
24 bits / 16777216 couleurs: HP Prime(version alpha)
Faisons maintenant un script allumant un par un tous les pixels de l'écran, et afin de mieux pouvoir mesurer et comparer les performances graphiques nous minimiserons les calculs en ne faisant pas appel à notre classe de compatibilité, mais en appelant directement les fonctions graphiques :
Passons maintenant sur Casio. Ici hélas pas de module timer, donc il va falloir chronométrer à la main, bien évidemment avec une montre Casio. Autre différence, les affichages sont à la différence effectués ici sur un calque invisible et ne passent à l'écran que lorsqu'on le demande. Afin donc de tester dans des conditions aussi équivalentes que possibles, nous demanderons un affichage écran après chaque traitement de pixel.
4995 pixels/s : Casio Graph 35+E II / fx-9750/9860GIII
265 pixels/s: TI-Nspire
121 pixels/s: TI-Nspire CX CR4+
60 pixels/s: TI-Nspire CX CR3-
48 pixels/s : TI-83 Premium CE Edition Python
En terme de boucle d'allumages individuels de pixels, la TI-83 Premium CE Edition Python ne serait donc apparemment pas très performante. Mais attends un petit peu avant de partir, nous sommes très loin d'avoir dit notre dernier mot, nous allons approfondir cela de suite dans les deux prochaines parties.
Nous avions été assez déçus des instructions d'affichage de texte présentes dans les modules ti_plotlib et ti_system :
impossibilité de positionner le texte comme on voulait verticalement, nous ne pouvions que choisir une des 11 à 12 bandes horizontales de 17 pixels de hauteur, numérotées de haut en bas, même dans le contexte de ti_plotlib pourtant censé travailler dans un repère
impossibilité de positionner le texte comme on voulait horizontalement, nous ne pouvion que choisir entre l'aligner à gauche, au centre ou à droite
et en prime effet de bord sur l'affichage avec effacement de la partie droite non utilisée de la bande ou même de toute la bande
ti_graphics dispose lui aussi d'une instruction d'affichage similaire drawString('texte', x, y).
Mais ici rien à voir avec les précédentes, (x, y) sont les coordonnées comptées cette fois-ci au pixel près à partir du coin en haut à gauche, et le tout ne produit aucun effet de bord !
Si si, tu pourras bien afficher tes textes en toute liberté !
tw = 10 s = 'Thank you TI' xmin, xmax, ymin, ymax = 0, 319, 30, 239 x, y, dx, dy = xmin, ymin, 1, 9
scr.cls() while x <= xmax - tw*len(s): scr.drawString(s, x, y) y += dy x += dx dx += 1 disp_wait()
C'est le cas de le dire, merci TI !
Et puis, ce n'est pas tout. Le test de la partie précédente nous a donc donné une vitesse de traitement calamiteuse de moins d'une 50aine de pixels à la seconde.
Et pourtant, aucun problème ici avec la fonction drawString(), l'affichage pourtant conséquent en nombre de pixels prenant moins d'une paire de secondes !
Que se passe-t-il donc ? Sans doute que c'est ici qu'il faut tenir comtpe de l'architecture matérielle très spéciale de la TI-83 Premium CE, avec :
un cœur secondaire Atmel SAMD21E18A-U intégrant un ARM Cortex-M0+ cadencé à 48 MHz, coprocesseur 32-bits dédié à l'exécution des scripts Python
un cœur principal eZ80 qui à la différence dispose d'un accès direct à l'ensemble des autres composantes matérielles (Flash, contrôleur écran, cœur secondaire...)
Et justement, on peut donc imaginer que chaque appel à setPixel() dans le test précédent génère un événement de mise à jour écran qui doit repasser par le processeur principal avant d'atteindre ce dernier, d'où une certaine latence pour une boucle travaillant de façon individuelle sur des pixels. Alors qu'ici chaque appel à drawString() allume d'un coup plein de pixels que l'on peut supposer à la différence partager un seul et unique événément de mise à jour.
Un comparatif s'appuyant sur une boucle d'allumage de pixels n'est donc pas représentatif des performances graphiques moyennes de la TI-83 Premium CE Edition Python puisque c'est pour elle le pire des cas, et donc non pertinent. Mais en même temps, quand les modules graphiques de la concurrence sont à la différence très minimalistes, nous ne voyons pas d'autre fonction commune et identique à utiliser pour construire un test de performances...
Abordons maintenant les autres fonctions de tracer de ti_graphics.
Les modules équivalents chez la concurrence sont assez minimalistes, te fournissant juste de quoi choisir la couleur, allumer/éteindre des pixels, et afficher du texte. Tu devais te fabriquer tes autres fonctions graphiques (lignes, rectangles, cercles, etc...). Et bien ici tu es gâté, ti_graphics est très riche.
Mais c'est aussi surtout un moyen de répondre au problème découvert plus haut, à savoir que la TI-83 Premium CE Edition Python est très lente pour les boucles appelant des setPixel(). Coder toi-même ces mêmes fonctions en utilisant setPixel() faute de mieux eut été désastreux.
Commençons déjà par de la configuration. Déjà, on eut effacer l'écran à l'aide de la fonction cls(). Son comportement semble identique à celui des fonctions ti_plotlib.cls() et ti_system.disp_clr().
La fonction cursor(c=1) permet d'activer ou désactiver l'affichage du curseur de texte, comme le permettait déjà la fonction ti_system.cursor(c). A la différence ici que les effets des valeurs sont inversés :
0: curseur affiché
1: curseur masqué
Autre différence également; contrairement à ti_system.cursor() la fonction cursor() admet un comportement par défaut : si appelée sans paramètre elle masque le curseur.
On peut maintenant choisir la couleur du stylo avec setColor(r, g, b), appel équivalent à ti_plotlib.color(r, g, b). D'ailleurs si l'on importe les deux modules ti_graphics et ti_plotlib, on peut appeler n'importe laquel de ces deux fonctions pour obtenir le même effet, et ce simultanément dans les deux contextes graphiques. Sans doute que ces deux fonctions partagent le même code.
On peut également régler la plume du stylo, avec setPen(taille, type), un appel donc similaire à ti_plotlib.pen('taille', 'type'). A la différence près que setPen() n'accepte pas d'arguments sous forme de chaînes de caractères, uniquement des entiers. On peut donc supposer que ti_plotlib.pen() est définie pour faire appel à setPen() de la façon suivante :
nta, nty = 4, 4 lx = [xmin + k*(xmax-xmin)/(2*nta+1) for k in range(1, 2*nta+1)] ly = [ymin + k*(ymax-ymin)/(2*nty+1) for k in range(1, 2*nty+1)] l = (xmax-xmin+1) / (2*nta+1)
scr.cls() for i in range(nty): scr.drawString(str(i), xmin-tw, ly[i*2]) for j in range(nta): scr.drawString(str(j), lx[j*2], ymin-th) scr.setPen(j, i) scr.drawLine(lx[j*2], ly[i*2], lx[j*2 + 1], ly[i*2]) disp_wait()
Ci-contre l'affichage obtenu, ainsi que pour comparaison celui du test similaire dans le contexte de la fonction ti_plotlib.pen().
Ce qui nous permet de terminer la documentation de pen() :
setPen(0, 0) = ti_plotlib.pen('thin', 'solid')
setPen(1, 1) = ti_plotlib.pen('medium', 'dot')
setPen(2, 2) = ti_plotlib.pen('thick', 'dash')
Quant à l'appel setPen(3, 3), il permet donc d'accéder à deux réglages secrets non offerts via ti_plotlib :
une taille de stylo encore plus grande que 'thick'
un tracé en pointillés qui enchaîne non pas des tirets mais des petits points
Des valeurs supérieures à 3 donnent quant à elles la même chose que la valeur 2.
Testons maintenant de façon similaire les fonctions drawPolyLine([(x1,y1), (x2,y2), ..., (xn,yn)]) et fillPolyLine([(x1,y1), (x2,y2), ..., (xn,yn)]) :
nta, nty = 4, 4 lx = [xmin + k*(xmax-xmin)/(2*nta+1) for k in range(1, 2*nta+1)] ly = [ymin + k*(ymax-ymin)/(2*nty+1) for k in range(1, 2*nty+1)] l = (xmax-xmin+1) / (2*nta+1)
scr.cls() for i in range(nty): scr.drawString(str(i), xmin-tw, ly[i*2]) for j in range(nta): scr.drawString(str(j), lx[j*2], ymin-th) scr.setPen(j, i) scr.setColor((255,0,0)) scr.fillPolygon([(lx[j*2], ly[i*2]), (lx[j*2 + 1], ly[i*2]), (lx[j*2], ly[i*2+1]), (lx[j*2 + 1], ly[i*2+1])]) scr.setColor((0,0,0)) scr.drawPolyLine([(lx[j*2], ly[i*2]), (lx[j*2 + 1], ly[i*2]), (lx[j*2], ly[i*2+1]), (lx[j*2 + 1], ly[i*2+1])]) disp_wait()
La fonction drawPolyLine() permet donc de tracer une ligne brisée. Elle serait donc équivalente au code suivant :
def drawPolyLine(l): for k in range(len(l) - 1): drawLine(l[k][0], l[k][1], l[k+1][0], l[k+1][1])
La fonction fillPolygon() permet quant à elle de colorier le polygone obtenu en fermant cette ligne brisée. Et comme tu vois c'est remarquable, elle marche même avec des polygones croisés !
Passons maintenant à drawRect(x, y, w, h) et fillRect(x, y, w, h) :
nta, nty = 4, 4 lx = [xmin + k*(xmax-xmin)/(2*nta+1) for k in range(1, 2*nta+1)] ly = [ymin + k*(ymax-ymin)/(2*nty+1) for k in range(1, 2*nty+1)] l = (xmax-xmin+1) / (2*nta+1)
scr.cls() for i in range(nty): scr.drawString(str(i), xmin-tw, ly[i*2]) for j in range(nta): scr.drawString(str(j), lx[j*2], ymin-th) scr.setPen(j, i) scr.setColor((255,0,0)) scr.fillRect(lx[j*2], ly[i*2], lx[j*2+1]-lx[j*2], ly[i*2+1]-ly[i*2]) scr.setColor((0,0,0)) scr.drawRect(lx[j*2], ly[i*2], lx[j*2+1]-lx[j*2], ly[i*2+1]-ly[i*2]) disp_wait()
drawRect(x, y, w, h) permet donc de tracer un rectangle :
de dimensions w et h données en pixels
aux côtés parallèles aux bors de l'écran
et en utilisant le point de coordonnées (x, y) comme sommet supérieur gauche
La fonction fillRect() quant à elle permet de colorier le rectangle en question.
Voici maintenant du lourd avec drawArc(x, y, w, h, t1, t2) et fillArc(x, y, w, h, t1, t2) :
nta, nty = 4, 4 lx = [xmin + k*(xmax-xmin)/(2*nta+1) for k in range(1, 2*nta+1)] ly = [ymin + k*(ymax-ymin)/(2*nty+1) for k in range(1, 2*nty+1)] l = (xmax-xmin+1) / (2*nta+1)
scr.cls() for i in range(nty): scr.drawString(str(i), xmin-tw, ly[i*2]) for j in range(nta): scr.drawString(str(j), lx[j*2], ymin-th) scr.setPen(j, i) scr.setColor((255,0,0)) scr.fillArc(lx[j*2], ly[i*2], lx[j*2+1]-lx[j*2], ly[i*2+1]-ly[i*2], 0, 3150) scr.setColor((0,0,0)) scr.drawArc(lx[j*2], ly[i*2], lx[j*2+1]-lx[j*2], ly[i*2+1]-ly[i*2], 0, 3150) disp_wait()
La fonction drawArc(x, y, dx, dy, t1, t2) permet donc de tracer un arc d'une ellipse elle-même inscrite dans un rectangle :
de dimensions w et h données en pixels
aux côtés parallèles aux bors de l'écran
et en utilisant le point de coordonnées (x, y) comme sommet supérieur gauche
t1 et t2 sont les angles au centre orientés délimitant l'arc en question, exprimés en dixièmes de degrés.
Et La fonction fillArc() permet quant à elle de colorier le secteur d'ellipse obtenu par balayage de l'arc en question.
Petite curiosité, nous avons une fonction fillCircle(x, y, r) permettant de préciser des éléments caractéristiques différents plus naturels dans le cas particulier d'un disque. La fonction serait donc équivalente au code suivant :
def fillCircle(x, y, r): fillArc(x-r, y-r, 2*r, 2*r, 0, 3600)
Ce qui est curieux ? Et bien qu'il n'y ait apparemment pas de fonction similaire drawCircle(x, y, r) pour le tracé d'un cercle, obligeant dans ce cas à utiliser une logique complètement différente.
nta, nty = 4, 4 lx = [xmin + k*(xmax-xmin)/(2*nta+1) for k in range(1, 2*nta+1)] ly = [ymin + k*(ymax-ymin)/(2*nty+1) for k in range(1, 2*nty+1)] l = (xmax-xmin+1) / (2*nta+1)
scr.cls() for i in range(nty): scr.drawString(str(i), xmin-tw, ly[i*2]) for j in range(nta): scr.drawString(str(j), lx[j*2], ymin-th) scr.setPen(j, i) scr.setColor((255,0,0)) scr.fillCircle(lx[j*2]+(ly[i*2+1]-ly[i*2])/2, (ly[i*2]+ly[i*2+1])/2, (ly[i*2+1]-ly[i*2])/2) scr.setColor((0,0,0)) scr.drawArc(lx[j*2], ly[i*2], ly[i*2+1]-ly[i*2], ly[i*2+1]-ly[i*2], 0, 3600) disp_wait()
Enorme surprise, ti_graphics dispose apparemment de pas moins de 3 fonctions dédiées à l'affichage d'images, et donc entre autres de sprites pour tes interfaces de menus et jeux !
C'est sans doute un moyen une fois encore de répondre au problème de performances des boucles d'allumage de pixels que tu aurais utilisées par défaut
Mais ces fonctions dédiées n'en restent pas moins un formidable avantage sur la concurrence, ces boucles d'allumage n'étant sur la plupart des modèles pas assez rapides pour permettre d'animer ou déplacer un sprite de façon fluide dans le contexte par exemple d'un jeu.
Comme ces fonctions ne sont pas au menu il nous faut donc arriver à deviner ce qu'elles attendent comme arguments.
L'appel pushImage(x, y, w, h) semble définir une image de dimensions w×h qui pourra être affichée avec comme coin supérieur gauche le pixel de coordonnées (x,y). La fonction popImage() quant à elle en déclenche ensuite l'affichage, effectivement très rapide même si par défaut cela nous affiche ici n'importe quoi.
Par exemple ci-contre, le résultat du code suivant :
drawImage(?, ?, ?) doit pour sa part servir à dessiner l'image en question avant affichage, mais nous n'avons pas réussi à en comprendre le fonctionnement.
Si l'on se réfère à notre test précédent ayant mis en évidence que nous disposions de près de 17.5K de mémoire de tas (heap) il semble impensable que cette fonction puisse accepter des données d'image brutes, que ce soit sous forme de liste ou de chaîne de caractères. 320×240 pixels codés sur 16 bits nécessiteraient en effet pas moins de 153.6 Ko, qui déclencheront ici une erreur de mémoire.
Nous avons deux hypothèses :
Soit la fonction attend une liste ou une chaîne de données compressées par exemple en RLE, et peut-être que TI a prévu un outil générant automatiquement à partir d'une image fournie la liste ou chaîne compressée à coller dans ton script. Mais en tous cas cet outil ne nous as pas été passé.
Soit la fonction attend le nom d'une ressource image à aller chercher en externe dans les variables du système de la calculatrice. En fouillant l'application Python à l'éditeur hexadécimal nous avons effectivement trouvé un indice en ce sens, avec un 'imgname' qui est bien présent en clair dans le code même nous n'avons trouvé pour le moment aucun menu l'affichant.
En tous cas, faire appel aux variables images préchargées dans le calculatrice avec par exemple scr.drawImage('Image1', 50, 50) semble ne rien donner.
On pouvait quand même s'en douter, vu que ces images ont une taille fixe prévue pour un affichage en plein écran :
265×165 pixels pour les images 16 couleurs Pic0 à Pic9
133×83 pixels pour les images d'arrière plan Image0 à Image9(agrandies d'un facteur 2 pour l'affichage)
C'est donc en total contradiction avec les quelques arguments devinés pour le moment.
Peut-être donc plutôt que drawImage() va chercher des AppVars (variables d'applications) qui contiendraient des images dédiées au Python et qu'un futur TI-Connect CE 5.5 effectuera la conversion à la volée lorsque l'on lui fournira des images. Ce serait l'hypothèse la plus plausible, mais en tous cas on ne nous l'a pas passé.
ti_graphics comporte également quelques autres fonctions privées ou issues d'autres modules.
Déjà, il inclut le module sys que tu n'auras donc pas à importer simultanément.
Il inclut également une fonction sleep() équivalente à time.sleep(), autre économie de mémoire pour tes importations.
La fonction privée _write('') semble être équivalente avec ti_plotlib._write('').
Sauf qu'ici elle est accompagnée d'une fonction _read(n). Attention, si on lui demande de lire plus de données qu'il y en a, on ne sait où en passant, la calculatrice rentre dans une boucle d'attente infinie qu'il est apparemment impossible d'interrompre autrement que par un reset.
Egalement quelques autres mystères à découvrir et qui peut-être nous permettront des choses bien pratiques : _grcmd(''), _grcif('') et _handshake(?).
Texas Instruments nous signe donc ici un module ti_graphics de dessin sur écran extrêmement complet, face à une concurrence à ce jour très minimaliste sur ce sujet.
Il y a clairement eu un travail très conséquent là-dessus, c'est un module conçu à partir de zéro et taillé sur-mesure pour te donner le meilleur avec le matériel choisi pour ta TI-83 Premium CE Edition Python.
Pixels, textes, formes géométriques diverses et images, chaque fonction te permet ici d'exploiter l'intégralité des capacités matérielles. ti_graphics te permet de réaliser avec de bien meilleurs performances tout ce que tu pouvais déjà faire avec le langage historique TI-Basic et même davantage, notamment au niveau des ellipses, couleurs et images !
De quoi initier de formidables créations (interfaces de menus, jeux, ...) pour tes projets, aussi bien scolaires (SNT, NSI, ...) que non scolaires !
détection des simples pressions de touches clavier (sans validation donc) par l'utilisateur, avec même l'éventuel modificateur actif (
2nde
ou
alpha
), et ça marche aussi avec un clavier USB !
affichage dans la console à la ligne que tu veux
exportation de listes de nombres (entiers, flottants ou complexes) existant dans le contexte Python vers l'environnement de la calculatrice, pour traitement à l'aide d'autres applications
importation depuis le contexte Python de listes ou équation de régression existant dans l'environnement de la calculatrice
et donc plus généralement un début d'intégration du Python à l'environnement mathématique de la calculatrice, enfin l'application Python va pouvoir servir non plus seulement à coder un truc déconnecté dans un coin, mais à traiter des problèmes et tâches complexes dans leur globalité !
ti_plotlib, une bibliothèque graphique pour tracer dans un repère othogonal, conformément aux programmes de Mathématiques et Physique-Chimie
ti_graphics pour tracer directement sur l'écran au pixel près
ti_hub, pour les projets d'objects connectés à l'aide de l'interface TI-Innovator Hub
Nous t'avions donc déjà exploré les possibilités des modules ti_system, ti_plotlib et ti_graphics.
Envie de découvrir les formidables possibilités des nouveaux modules Pythonti_hub et ti_rover couplés aux périphériques TI-Innovator Hub et TI-Innovator Rover ?
Texas Instruments t'invite ce mercredi 6 mai 2020 à 18h30 pour une vidéoconférence précisément dédiée à ces nouveaux modules Python.
Au cours de cette formation en ligne d'1h30 te seront présentés plusieurs projets réalisables en classe, particulièrement dans le contexte de l'enseignement SNT niveau 2nde.
Notons que ton hôte Jean Baptiste Civet, professeur de Mathématiques sur Marseille et formateur T3 pour Texas Instruments, est justement coauteur des cahiers d'activités dédiés à ta TI-83 Premium CE Edition Python disponibles chez Eyrolles :
détection des simples pressions de touches clavier (sans validation donc) par l'utilisateur, avec même l'éventuel modificateur actif (
2nde
ou
alpha
), et ça marche aussi avec un clavier USB !
affichage dans la console à la ligne que tu veux
exportation de listes de nombres (entiers, flottants ou complexes) existant dans le contexte Python vers l'environnement de la calculatrice, pour traitement à l'aide d'autres applications
importation depuis le contexte Python de listes ou équation de régression existant dans l'environnement de la calculatrice
et donc plus généralement un début d'intégration du Python à l'environnement mathématique de la calculatrice, enfin l'application Python va pouvoir servir non plus seulement à coder un truc déconnecté dans un coin, mais à traiter des problèmes et tâches complexes dans leur globalité !
ti_plotlib, une bibliothèque graphique pour tracer dans un repère othogonal, conformément aux programmes de Mathématiques et Physique-Chimie, comparable à matplotl chez Casio ou encore matplotlib.pyplot
ti_graphics pour contrôler directement les pixels de l'écran, comparable à kandinsky chez NumWorks ou encore casioplot
ti_hub, pour les projets d'objects connectés à l'aide de l'interface TI-Innovator Hub
Nous t'avions donc déjà exploré les possibilités des modules ti_system, ti_plotlib et ti_graphics.
A priori donc pas de module turtle. Trouvais-tu donc les possibilités graphiques décevantes ?
Et bien si, crois-le ou pas mais la formidable mise à jour 5.5 n'en a pas terminé de te révéler sa pléthore de secrets. Texas Instruments nous a bien concocté en secret un module comparable à turtle ici appelé ce_turtl !
Décidément, c'est bien une mise à jour historique que Texas Instruments est en train de te préparer. La plus grande mise à jour depuis le lancement de la TI-83 Premium CE à la rentrée 2015 ?
Non non tu ne rêves pas. Nous ne t'en avions pas parlé jusqu'à présent car la solution retenue est étrangement similaire à celle de Casio. C'est-à-dire que le module ce_turtle n'est pas intégré à la mise à jour 5.5 et voilà donc pourquoi tu n'as pu en noter aucune trace jusqu'à présent. Il prend en fait la forme d'un fichier externe de variable d'application ce_turtle.8xv qu'il faut à ce jour rajouter manuellement.
Toutefois ce_turtle semble nous réserver quelques surprises, puisqu'une fois rajouté au contenu de la calculatrice ses icônes et types dans l'explorateur de TI-Connect CE diffèrent de ceux utilisés pour les scripts Python, un objet donc a priori fort intéressant...
Effectivement grosse surprise, la calculatrice ne liste pas ce_turtl avec les autres scripts Python transférés, mais avec les autres modules intégrés importables !
Cela voudrait-il dire que Texas Instruments a codé un moyen de rajouter ses propres modules ?
Outre ce détail, en quoi ce_turtl diffère-t-il d'un script Python normal ?
Et bien à partir de l'entrée précédente tu as ici accès à un menu par onglets documentant ses différentes fonctions et en facilitant l'accès !
Peut-être y a-t-il d'autres avantages à utiliser un module rajouté plutôt qu'un script Python normal comme Casio, comme la disponibilité en mode examen. Ne disposant pas à ce jour du fichier ce_turtle.8xv nous ne pouvons pas tester, mais ne manquerons pas de t'en informer aussitôt que possible.
Maintenant pour l'utilisation, l'importation du module ce_turtle apporte apparemment un objet turtle.
Il est donc a priori possible de construire du code compatible avec différents modèles à l'aide des lignes suivantes :
try: from ce_turtl import turtle except: import turtle
Terminons justement avec quelques exemples pour commencer à découvrir la compatibilité. Nous utiliserons une fonction annexe mypencolor() pour le réglage de la couleur de crayon, afin de contourner une divergence déjà évoquée chez NumWorks.
try: from ce_turtl import turtle except: import turtle
def mypencolor(t): cmax=255 try: turtle.pencolor((2, 2, 2)) except: cmax=1 if cmax==1 and max(t)>1: t=tuple(u/255 for u in t) elif cmax==255 and any(isinstance(u, float) for u in t): t=tuple(int(255*u) for u in t) turtle.pencolor(t)
try: from ce_turtl import turtle except: import turtle
def mypencolor(t): cmax=255 try: turtle.pencolor((2, 2, 2)) except: cmax=1 if cmax==1 and max(t)>1: t=tuple(u/255 for u in t) elif cmax==255 and any(isinstance(u, float) for u in t): t=tuple(int(255*u) for u in t) turtle.pencolor(t)
def sierp(n, l): if n == 0: for i in range (0, 3): turtle.fd(l) turtle.left(120) if n > 0: sierp(n-1, l/2) turtle.fd(l/2) sierp(n-1, l/2) turtle.bk(l/2) turtle.left(60) turtle.fd(l/2) turtle.right(60) sierp(n-1, l/2) turtle.left(60) turtle.bk(l/2) turtle.right(60)
Merci Texas Instruments pour cette belle surprise des modules Python rajoutables à laquelle nous ne nous attendions absolument pas.
Le module ce_turtl hautement pertinent et a priori bénéficiant d'une certaine compatibilité avec le turtle standard, offrira donc très bientôt de quoi réinvestir en Seconde les acquis du langage Scratch du collège pour une transition en douceur vers le Python !
Mais au-delà de cela, la solution technique retenue est des plus intéressantes. Cela voudrait-il dire qu'il serait à l'avenir possible pour des entités tierces de fournir des modules d'extension Python pour la TI-83 Premium CE Edition Python; avec peut-être validation par le constructeur via une signature électronique si le mode examen entre dans l'équation ?...
détection des simples pressions de touches clavier (sans validation donc) par l'utilisateur, avec même l'éventuel modificateur actif (
2nde
ou
alpha
), et ça marche aussi avec un clavier USB !
affichage dans la console à la ligne que tu veux
exportation de listes de nombres (entiers, flottants ou complexes) existant dans le contexte Python vers l'environnement de la calculatrice, pour traitement à l'aide d'autres applications
importation depuis le contexte Python de listes ou équation de régression existant dans l'environnement de la calculatrice
et donc plus généralement un début d'intégration du Python à l'environnement mathématique de la calculatrice, enfin l'application Python va pouvoir servir non plus seulement à coder un truc déconnecté dans un coin, mais à traiter des problèmes et tâches complexes dans leur globalité !
ti_plotlib, une bibliothèque graphique pour tracer dans un repère othogonal, conformément aux programmes de Mathématiques et Physique-Chimie, comparable à matplotl chez Casio ou encore matplotlib.pyplot, et gérant ici les diagrammes suivants :
nuage de points
diagramme en ligne brisée
droite de régression linéaire
ti_graphics pour contrôler directement les pixels de l'écran, comparable à kandinsky chez NumWorks ou encore casioplot
ti_hub, pour les projets d'objects connectés à l'aide de l'interface TI-Innovator Hub
Nuage de points, diagramme en ligne brisée et droite de régression linéaire. Etais-tu déçu(e) par le peu de types de diagrammes différents traçables via le module Pythonti_plotlib intégré ?
Et bien non Texas Instruments n'a rien oublié; en fait les autres types de diagrammes offerts chez toute ou partie de la concurrence et bien d'autres seront bel et bien disponibles.
C'est juste qu'ils sont apportés par 3 autres modules Python optionnels dont il faut à ce jour rajouter les fichiers manuellement, d'où leur absence jusqu'à présent.
Comme chez Casio, le module optionnel ce_box te permettra de tracer des boîtes de Tukey, plus connues sous les noms de diagrammes en boîte ou à moustaches. On apprécie ici la légende automatique précisant les valeurs des différents paramètres statistiques illustrés.
from ce_box import * data = [3,2,3,3,1,5,4,3,1,5,2,1,4,3,3,0,1,3,3,1,2,4,2,4,0,0,2,2,3,2] Ex1 = box(data) Ex1.title('Exercice 4-1') Ex1.show()
Le module optionnel ce_chart pour sa part te permettra de tracer des histogrammes comme chez Casio et NumWorks. On noce ici l'affichage automatique des étiquettes de valeurs ainsi que le choix automatique des couleurs.
Mais ce n'est pas tout car comme son nom l'indique ce_chart ne sert pas qu'aux histogrammes, loin de là.
Il est également capable de représenter des graphes de fonctions; plus besoin donc de t'embêter à les approcher à l'aide de diagrammes en ligne brisée.
Et bien évidemment d'autres représentations associées aux fonctions sont alors disponibles, comme l'aire entre deux courbes approchée via la méthode des rectangles.
Enfin autre possibilité avec le module optionnel ce_quivr, dédié aux diagrammes utilisant des vecteurs que l'on utilise en Physique-Chimie, vecteurs vitesse notamment.
def motion(min, max, n): dt = (max-min) / n t = min for i in range(n): quiver(t, fx(t), t+dt, fx(t+dt), 1, 'blk', 'line') if i % 7 == 0: quiver(t, fx(t), 0, dx(t), .4, 'r', 'vector') quiver(t, fx(t), 0, d2x(t), .4, 'b') t += dt
plt.window(-.25, 4, -5, 7) plt.cls() plt.title('Motion in one Dimension') plt.color(0, 0, 0) plt.axes('on') plt.labels('Time', ' X Position ', 7, 3) motion(0, 4, 49) plt.show_plot()
Décidément, la charge de travail accomplie par Texas Instruments avec le Python de la mise à jour 5.5 pour ta TI-83 Premium CE Edition Python est des plus impressionnantes.
Aussi bien par la quantité de nouvelles fonctionnalités apportées, que par leur haute qualité systématique à chaque fois... Le travail de conception fut apparemment méticuleux, puisque de façon régulière hautement pertinent aussi bien comme déjà vu du point de vue de l'adéquation au matériel de la calculatrice, qu'en terme de programmes scolaires, et notamment de spécificités du programme scolaire français.
A combien d'enseignants experts PythonTI a-t-il fait appel et depuis combien de mois années travaillent-ils là-dessus ?...