Les nouvelles technologies pour l’enseignement des mathématiques
Intégration des TICE dans l’enseignement des mathématiques

MathémaTICE, première revue en ligne destinée à promouvoir les TICE à travers l’enseignement des mathématiques.

Pour collègues geeks
Python dans un émulateur Numworks préparé
Une utilisation en classe

Ou pourquoi j’ai inséré des codes en Python directement dans le code source de Numworks

Article mis en ligne le 5 octobre 2018
dernière modification le 19 novembre 2018

par Nicolas Patrois

Le langage de programmation Python est maintenant suggéré en classe de seconde. Après quelques tentatives directes infructueuses, l’utilisation du µPython dans l’émulateur de Numworks m’a paru un meilleur choix.
Pourquoi la calculette Numworks ? Parce que j’avais l’émulateur sous la main, que je pouvais le bidouiller et le recompiler sans demander quoi que ce soit à mon administrateur contrairement à un environnement de développement ou à un émulateur concurrent. Je ne sais pas si j’aurais tenté si Python avait été installé, ça m’aurait demandé moins de travail.

Des débuts infructueux

Avec Python

L’an dernier, j’ai déjà utilisé Python en demi-groupe en classe mais le faible niveau des élèves en programmation a rendu les heures pénibles.
Ainsi, je proposais de se connecter à un site comme ideone pour y exécuter des bouts de code en Python (calculs, quelques tests et boucles simples) mais les élèves ne voyaient pas la finalité de ce b.a.-ba et perdaient beaucoup de temps avec les fautes de frappe et le respect de la syntaxe.

Avec Algobox

Finalement, je me suis rabattu les deux premiers trimestres de cette année sur Algobox en construisant cinq heures sur les entrées et sorties, les tests, les boucles pour, les boucles tant que et enfin les fonctions (présentes dans la version 1.0.2). Les élèves devaient recopier un code presque complet dans leur fenêtre d’Algobox mais leur manque d’aisance dans l’utilisation d’Algobox leur a pris beaucoup de temps avant de pouvoir commencer à comprendre ce qu’ils faisaient, même la cinquième et dernière heure.
Proposer des codes incomplets à ouvrir et modifier ? Je n’y avais pas pensé et il me semblait, puisqu’il n’y a pas d’erreur de syntaxe dans Algobox, que ce serait plus facile.

Avec Numworks

Depuis 2017, Numworks vend une calculatrice qui contient une version simplifiée de Python (µPython 1.9.4 donc sans gestion des accents). Ses spécifications techniques sont publiques et son code source peut se compiler dans une version en JavaScript (comme sur leur site). L’énorme avantage est qu’il n’y a rien à installer, juste trois fichiers à copier quelque part dans un répertoire accessible aux élèves et un navigateur comme Chrome ou Firefox. Bonus pour moi, je peux compiler depuis Linux, ça fonctionnera dans Windows (ou Mac ou tout ce qu’on veut).
Avantage supplémentaire, il n’a pas besoin d’un environnement de développement qui nécessite une installation par l’administrateur.
J’ai donc compilé moi-même l’émulateur de la calculette en JavaScript puisqu’on ne peut pas, pour le moment, sauvegarder l’état de l’émulateur. J’y ai alors inséré les bouts de code dont j’avais besoin pour deux heures en seconde et deux heures en 1STI. Voir le bloc ci-dessous pour plus d’informations sur la compilation.

La compilation

La compilation est expliquée sur leur site. Pour compiler en JS, on installe en plus emscripten et on tape make simulator.zip PLATFORM=emscripten au lieu de make simulator.
On insère le code source dans apps/code/script_template.cpp, il y a besoin de modifier aussi les fichiers apps/code/script_template.h et apps/code/script_store.cpp avant de recompiler.
Vous pouvez demander de l’aide sur le forum officiel où l’équipe de Numworks est active et disponible.

Les élèves pouvaient télécharger l’archive contenant l’émulateur à partir du logiciel de cahier de textes.

En seconde

Puisque j’ai abordé les cinq parties du programme d’algorithmique (mais sans Python) pendant les deux premiers trimestres, j’ai tenté Python avec une autre approche. Lors de la première des deux heures (je n’ai pas eu le temps de faire plus), ils avaient à leur disposition l’émulateur de la calculette (fichiers joints python1.pdf pour le document et python1.zip pour l’émulateur).
L’application Python contenait les trois scripts corrects suivants :

Un script qui affiche un petit sapin de taille variable.

def sapin(n):
 for i in range(n):
   print(" "*(n-i)+"#"*(2*i+1))
 print(" "*n+"#")

Un autre qui détermine la nature d’un triangle si on lui donne les noms et coordonnées de ses trois sommets.

def triangles(A,B,C):
 def distance2(A,B):
   pA,xA,yA=A
   pB,xB,yB=B
   return (xB-xA)**2+(yB-yA)**2
 pA,xA,yA=A
 pB,xB,yB=B
 pC,xC,yC=C
 dAB2=distance2(A,B)
 dBC2=distance2(B,C)
 dCA2=distance2(C,A)
 nom=pA+pB+pC
 if dAB2==dBC2==dCA2:
   print(nom+" est equilateral.")
 elif dAB2==dBC2:
   print(nom+" est isocele en "+pB+".")
 elif dBC2==dCA2:
   print(nom+" est isocele en "+pC+".")
 elif dCA2==dAB2:
   print(nom+" est isocele en "+pA+".")
 else:
   print(nom+" est quelconque.")
 cABC=dAB2+dBC2-dCA2
 cBCA=dBC2+dCA2-dAB2
 cCAB=dCA2+dAB2-dBC2
 if cABC<0 or cBCA<0 or cCAB<0:
   print(nom+" est obtus.")
 elif cABC==0:
   print(nom+" est rectangle en "+pB+".")
 elif cBCA==0:
   print(nom+" est rectangle en "+pC+".")
 elif cCAB==0:
   print(nom+" est rectangle en "+pA+".")
 else:
   print(nom+" est aigu.")

Et un qui affiche la liste des facteurs premiers d’un nombre entier.

def facteurs(n):
 if type(n) is not int or n<1:
   raise TypeError("Vous devez entrer un entier positif.")
 nn=n
 p=2
 div=dict()
 while nn!=1:
   while nn%p==0:
     if p in div:
       div[p]+=1
     else:
       div[p]=1
     nn/=p
   p+=1
 print(str(n)+"="+"*".join("%d^%d"% (p,div[p]) for p in sorted(div)))

Les élèves devaient se contenter de les faire tourner, le deuxième en allant chercher des exercices dans leur manuel.
Il contenait aussi trois scripts à modifier :

Le calcul des coefficient directeur et ordonnée à l’origine d’une droite (non parallèle à l’axe des ordonnées) dont on donnait les coordonnées de deux points.

def distance(A,B):
 from math import sqrt # la racine carree
 xA,yA=A
 xB,yB=B
 return sqrt(0) # a vous de completer

Le calcul de la longueur d’un segment.

def eqdroite(A,B):
 xA,yA=A
 xB,yB=B
 a=0 # a vous de completer
 b=0 # a vous de completer
 return a,b

La détermination du signe d’une fonction affine en fonction de son coefficient directeur et de son ordonnée à l’origine.

def signeaffine(a,b):
 x=-b/a
 print("f(x)=%fx+%f est "% (a,b))
 if a<0:
   print("signeacompleter si x<%s et"%x)
   print("signeacompleter si x>%s."%x)
 elif a>0:
   print("signeacompleter si x<%s et"%x)
   print("signeacompleter si x>%s."%x)

Les passages à modifier ou à compléter étaient des questions de cours de seconde, rien d’insurmontable. Ces trois fonctions répondaient n’importe quoi mais sans se planter, c’était important pour ne pas charger la console d’exécution de messages d’erreur. La partie technique difficile (c’est-à-dire recopier un code sans erreur) était prête et le travail était écrit dans le code.

Ce que devait faire le script (avec un exemple d’utilisation et de sortie corrects) était précisé sur la feuille de consignes.

Pour la deuxième heure (fichiers joints python2.pdf et python2.zip), le travail à faire était de même nature mais plus difficile. Ils avaient pu jouer un peu avec la suite de Syracuse et celle de Conway (look and say) avant de s’attaquer à un script plus conséquent qui devait afficher la nature d’un quadrilatère si on lui donnait les noms et coordonnées de ses quatre sommets (dans l’ordre qui va bien). Comme la première heure, ce script tournait sans planter mais était faux.
Ils devaient d’abord modifier un sous-programme qui donnait le carré de la longueur d’un segment et un autre qui calculait les coordonnées d’un vecteur, par exemple :

def distance2(A,B):
 return (A[0]+B[0])**2+(A[1]+B[1])**2
# Ligne precedente a modifier

Ils avaient à expliquer d’autres lignes de code correctes, qui consistaient à calculer les coordonnées de vecteurs, à tester leur égalité puis celle des carrés leurs normes :

# Deux lignes a expliquer (1)
 vecteur01=vecteur(coord[0],coord[1])
 vecteur32=vecteur(coord[3],coord[2])

Petite erreur de ma part, j’aurais pu nommer les vecteurs vecteurAB et vecteurDC, ils ont eu du mal à faire le lien mais il n’y aurait eu plus rien à faire. Le (1) signifie qu’il s’agit du premier bout de code à expliquer dans leur feuille de consignes.
Enfin, ils devaient modifier quelques affichages, c’est-à-dire reconnaître les cas du losange et du rectangle.
Ils étaient invités à tester leur script terminé sur des exercices de leur manuel.

Le script complet

def distance2(A,B):
 return (A[0]+B[0])**2+(A[1]+B[1])**2
# Ligne precedente a modifier

def vecteur(A,B):
 return B[0]+A[0],B[1]+A[1]
# Ligne precedente a modifier

def quadrilatere(p0,p1,p2,p3):
 liste=[p0,p1,p2,p3]
 coord=[]
 nom=""
 for p in liste:
   coord+=[p[1:]]
   nom+=p[0]
 phrase=nom+" est un "

# Deux lignes a expliquer (1)
 vecteur01=vecteur(coord[0],coord[1])
 vecteur32=vecteur(coord[3],coord[2])

 if vecteur01==vecteur32:
# Ligne precedente a expliquer (2)
   longueur01=distance2(coord[0],coord[1])
   longueur12=distance2(coord[1],coord[2])
   longueur13=distance2(coord[1],coord[3])
   longueur02=distance2(coord[0],coord[2])
   if longueur01==longueur12 and longueur13==longueur02:
# Ligne precedente a expliquer (3)
     print(phrase+"carre.")
   elif longueur01==longueur12:
     print(phrase+".")
# Ligne precedente a modifier
   elif longueur13==longueur02:
     print(phrase+".")
# Ligne precedente a modifier
   else:
     print(phrase+"parallelogramme.")
 else:
   print(phrase+"quadrilatere quelconque.")

En 1STI

J’ai aussi tenté l’an dernier un peu de Python en 1STI et l’expérience n’a pas été plus concluante qu’en seconde pour la même raison.
Cette année, j’ai testé le même genre de travail qu’en seconde : une découverte de Python puis un script plus conséquent à modifier.

Lors de la première heure, les élèves avaient à disposition ces scripts fonctionnels (oui, je recycle, fichiers joints naturetriangles.pdf et triangles.zip) :

  • Un script qui donnait (comme en seconde) la liste des facteurs premiers d’un nombre entier.
  • Un autre qui calculait la distance entre deux points.
  • Un dernier qui donnait l’équation réduite d’une droite (comme en seconde mais complets).

En revanche, le script à modifier était plus conséquent : il s’agissait de celui donné en seconde sur la nature d’un triangle mais cette fois-ci, il n’était pas fonctionnel. Les élèves devaient modifier un sous-programme qui calculait la distance (donné juste avant) ainsi que quelques lignes dans la fonction principale :

 dAB2=distance2(A,B)
 dBC2=0 # a vous de completer
 dCA2=0 # a vous de completer

Ou :

 if cABC<0 or cBCA<0 or cCAB<0:
   print(nom+" est a vous de completer.")
 elif cABC==0:
   print(nom+" est a vous de completer en "+pB+".")

Le code complet

def triangles(A,B,C):
 def distance2(A,B):
   pA,xA,yA=A # le nom d'un point suivi de ses coordonnees
   pB,xB,yB=B
   return 0 # a vous de completer

 pA,xA,yA=A
 pB,xB,yB=B
 pC,xC,yC=C
 dAB2=distance2(A,B)
 dBC2=0 # a vous de completer
 dCA2=0 # a vous de completer
 nom=pA+pB+pC
 if dAB2==dBC2==dCA2:
   print(nom+" est a vous de completer.")
 elif dAB2==dBC2:
   print(nom+" est a vous de completer en "+pB+".")
 elif dBC2==dCA2:
   print(nom+" est a vous de completer en "+""+".")
 elif dCA2==dAB2:
   print(nom+" est a vous de completer en "+""+".")
 else:
   print(nom+" est quelconque.")
 cABC=dAB2+dBC2-dCA2
 cBCA=0 # a vous de completer
 cCAB=0 # a vous de completer
 if cABC<0 or cBCA<0 or cCAB<0:
   print(nom+" est a vous de completer.")
 elif cABC==0:
   print(nom+" est a vous de completer en "+pB+".")
 elif cBCA==0:
   print(nom+" est a vous de completer en "+""+".")
 elif cCAB==0:
   print(nom+" est a vous de completer en "+""+".")
 else:
   print(nom+" est aigu.")

La deuxième heure, moins réussie car plus difficile et surtout plus abstraite pour des élèves de 1STI, leur ont fait utiliser les suites de Syracuse et de Conway puis étudier un script incomplet qui devait afficher les termes successifs de la suite de Robinson qu’on avait vue auparavant en exercice (fichiers joints suites.pdf et robinson.zip).

La suite de Robinson

Il s’agit d’une variante de la suite de Conway où on compte toutes les occurences de chaque chiffre, pas seulement consécutives, ordonnées dans l’ordre. Si son premier terme est 0, les suivants sont 10 (un 0), 1011 (un 0 et un 1), 1031 (un 0 et trois 1), 102113 (à vous)… On remarque qu’à partir d’une dizaine de termes, la suite est périodique, c’est ce que détecte le script fourni aux élèves.

Comme les élèves de seconde, ils devaient expliquer quelques lignes de code exactes et en modifier d’autres par exemple dans la fonction qui renvoyait le terme suivant de la suite :

def suivante(chaine):
 liste=[0 for _ in range(10)]
 for caractere in chaine: # Que fait ce bloc ? (1)
   chiffre=int(caractere)
   liste[chiffre]+=0 # Modifier cette ligne
 nouvelle=""
 for chiffre in range(9,-1,-1): # Que fait ce bloc ? (2)
   if liste[chiffre]>0:
     nouvelle+=str(liste[0])+str(0) # Modifier cette ligne
 return "nawak" # Modifier cette ligne

La fonction centrale

def robinson(chaine):
 chaines=[]
 compte=0

 while chaine not in chaines: # Que fait ce bloc ? (3)
   chaines+=[chaine]
   compte+=0 # Modifier cette ligne
   print("%d %s"%(compte,chaine))
   chaine=suivante("0") # Modifier cette ligne

 index=0
 while chaine!=chaines[index]: # Que fait ce bloc ? (4)
   index+=1
 print("%s est au numero %d"%(chaine,index))

Conclusion

Les élèves ne connaissaient pas la calculette mais n’ont pas eu peur de l’émulateur, bien au contraire. Un seul petit point négatif : ils ne pouvaient pas agrandir l’écran d’autant plus que les caractères étaient clairs (ce qui est corrigé aujourd’hui avec en prime une coloration syntaxique) et que le nombre de caractères affichés sur une ligne était limité ce qui empêchait d’avoir une vue plus globale du code. Depuis version 1.7, en bas de l’émulateur on peut agrandir l’écran de la calculette à la taille de la fenêtre du navigateur.
Quant à la notation de ces deux fois deux heures, sur la suggestion d’un collègue, j’ai parsemé la feuille de travail de rectangles gris que je validais en passant dans les rangs, chacun valait un point (5 pour la première, 6 pour la seconde).
Je reprendrai cette manière de travailler la programmation en classe en commençant plus tôt, en allant plus progressivement et plus loin. Le temps de préparation fut plus conséquent puisque les va-et-vient entre le code en C++, la compilation, l’émulateur compilé et la feuille de consignes ont pris du temps mais les élèves en redemandaient…