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.

Comment faciliter la création d’exercices aléatoires dans LaboMep ?

Cet article présente une passerelle entre une librairie du logiciel R créant des QCMs mathématiques aléatoires et la plateforme pédagogique LaboMep.

Article mis en ligne le 18 septembre 2020
dernière modification le 6 janvier 2021

par Patrick Raffinat

Cet article présente une passerelle entre une librairie du logiciel R créant des QCMs mathématiques aléatoires et la plateforme pédagogique LaboMep.

A) Introduction

J3P (Javascript & Parcours Pédagogique Personnalisé) est un projet de Sésamath initié en 2011. Il permet :

  • à des développeurs Javascript de créer de nouveaux exercices (mathématiques) aléatoires, qui seront ensuite intégrés dans la plate-forme LaboMep.
  • à des formateurs de planifier, sous la forme d’un graphe à construire dans LaboMep, un enchaînement d’exercices qui dépendra des résultats de leurs élèves à ces exercices.

A l’occasion d’un précédent article dans le N°57 en 2019 (lien), je m’étais penché sur le cas des ressources algorithmiques, quasi inexistantes à mon grand étonnement, et avais apporté mes compétences de développeur Javascript d’outils pédagogiques pour y remédier. Pour y parvenir, j’avais étudié de façon approfondie les mécanismes permettant à un développeur J3P de créer des exercices interactifs aléatoires pour LaboMep. Le modèle à suivre étant loin d’être simple, cela m’a conduit à me pencher sur la problématique suivante : comment puis-je contribuer à faciliter le travail des développeurs de ressources J3P actuels (en petit nombre hélas) ou à venir ?

Les types d’exercices proposés dans LaboMep étant très variés, il aurait été utopique que je cherche à apporter une réponse universelle à ce défi. J’ai donc décidé de me focaliser sur une thématique particulière, qui aurait pu être la production de ressources Python (thématique que je connais bien pour l’avoir initiée en 2019), mais j’ai préféré un choix plus mathématique puisque c’est plus représentatif de la raison d’être de LaboMep. J’ai longtemps hésité sur ce choix, avant de lire un article de Pascal Couvrechef dans le N°71 (lien). Il y présente l’outil « rexams », une librairie du logiciel R permettant de créer des QCMs « aléatoirisés » adaptés aux évaluations en mathématiques (ex1, ex2), ce qui m’a conduit à imaginer une passerelle permettant de les transformer en exercices J3P (ex1, ex2).

B) Production de QCMs avec la librairie R « exams »

Dans le N°57 de MathemaTICE (lien), j’ai présenté un outil (RMarkdown) permettant de créer simplement des documents (HTML, PDF…) dont certaines parties résultent de l’exécution de code R. On peut combiner cet outil à la librairie R « exams » pour créer des QCMs aléatoires à partir de documents au format RMarkdown. Pour plus de renseignements, je renvoie les lecteurs vers le site officiel (http://www.r-exams.org/).

Dans la documentation, ils y trouveront de nombreux exemples, parmi lesquels je choisirai celui relatif à la distance euclidienne entre deux points pour illustrer l’article. Il se décline en deux versions : saisie de la réponse sous forme numérique, ou choix de la réponse dans une liste de propositions. A titre indicatif, voici le fichier RMarkdown pour la version numérique :

```{r data generation, echo = FALSE, results = "hide"}
p <- c(sample(1:3, 1), sample(1:5, 1))
q <- c(sample(4:5, 1), sample(1:5, 1))
sol <- sqrt(sum((p - q)^2))
```

Question
========
Quelle est la distance entre les deux points
$p = (`r p[1]`, `r p[2]`)$ et $q = (`r q[1]`, `r q[2]`)$
?

Solution
========
La distance $d$ entre $p$ et $q$ est donnee par
$d^2 = (p_1 - q_1)^2 + (p_2 - q_2)^2$ (formule de Pythagore).

Donc $d = \sqrt{(p_1 - q_1)^2 + (p_2 - q_2)^2} =
 \sqrt{(`r p[1]` - `r q[1]`)^2 + (`r p[2]` - `r q[2]`)^2}
  \approx `r round(sol, digits = 3) `$.

```{r distplot, echo = FALSE, results = "hide", fig.path = "", fig.cap = ""}
par(mar = c(4, 4, 1, 1))
plot(0, type = "n", xlim = c(0, 6), ylim = c(0, 6), xlab = "x", ylab = "y")
grid(col = "slategray")
points(rbind(p, q), pch = 19)
text(rbind(p, q), c("p", "q"), pos = c(2, 4))
lines(rbind(p, q))
lines(c(p[1], p[1], q[1]), c(p[2], q[2], q[2]), lty = 2)
```

Meta-information
================
extype: num
exsolution: `r round(sol, digits = 3)`
exname: Euclidean distance
extol: 0.01

Il n’est pas évident d’écrire un tel code, surtout si on n’a pas enseigné R à des étudiants comme moi (en IUT), mais on peut y parvenir grâce à un temps d’apprentissage « raisonnable » [1]. Les grandes lignes du fichier RMarkdown sont, en revanche, très faciles à comprendre :

  • la première partie permet d’engendrer aléatoirement deux points (p et q), et calcule la distance (sol) entre ces deux points.
  • la seconde partie crée l’énoncé de la question, qui tient compte de la valeur des points p et q.
  • la troisième partie, plus technique, produit deux phrases d’explication complétés par un graphique.
  • la quatrième partie est destinée au programme R qui engendrera (à plusieurs exemplaires) le QCM sous la forme de fichiers html ; elle lui indique notamment que la question est de type numérique (extype:num) et fixe la précision acceptée pour la réponse de l’élève (extol:0.01).

Ensuite, c’est un jeu d’enfant pour produire les fichiers html : en effet, il suffit d’exécuter ce petit programme R (à adapter au nom du fichier RMarkdown et à son emplacement) :

library(rexams)
nbExemplaires <- 50
qcm <- "distance.Rmd"
setwd( "C:/Users/raffinat/Documents/rexams/demo")
exams2html(qcm, n=nbExemplaires , name="ex")

Dans le cas présent, 50 fichiers html (nommés ex1.html, ex2.html … ex50.html) sont créés dans le dossier « demo ». On peut ouvrir ces fichiers avec un navigateur puis, si leur contenu n’est pas jugé satisfaisant, modifier le fichier RMarkdown et relancer le petit programme R autant de fois que nécessaire.

C) Simplification du code Javascript à écrire pour un développeur J3P

Dans son code Javascript, un développeur doit gérer une multitude de choses : création des énoncés aléatoires, création des formulaires de saisie, vérification des réponses de l’élève, génération des corrections, communication de l’analyse des erreurs de l’élève… A l’arrivée, on aboutit à des programmes complexes à mettre au point, avec de nombreuses lignes de code souvent « indigestes ». Cela fait donc plusieurs très bonnes raisons de chercher à alléger le code Javascript à réaliser.

Dans le cas des QCMs, il est naturel de chercher à tirer profit de l’automatisation proposée par « rexams ». Pour y parvenir, la stratégie retenue sera la suivante :

  • on génère un grand nombre de fichiers html avec R, qu’on stocke quelque part dans J3P.
  • chaque fois que l’élève traite la question (à répéter plusieurs fois en modifiant aléatoirement ses paramètres, nombre précisé par l’enseignant dans LaboMep), un échantillon de même taille est tiré dans la liste des fichiers html disponibles pour cette question.
  • lors de chaque répétition, le programme Javascript analyse le fichier html correspondant, en extrait la question pour l’afficher et la complète par une zone de saisie.
  • chaque fois que l’élève donne une réponse, le programme Javascript consulte le fichier pour la comparer à la réponse attendue, ce qui permet ensuite de vérifier si elle est correcte, et d’augmenter le score de l’élève si c’est le cas ; l’analyse du fichier html permet aussi de récupérer un corrigé avec des explications.

Le travail de programmation Javascript restant malgré tout conséquent, j’en ai reporté une grande partie dans un outil mis à disposition des développeurs J3P. Et à l’arrivée, il ne leur reste plus qu’une cinquantaine de lignes à produire pour obtenir la ressource J3P, ce que j’illustre ici (voir lien vers le programme Javascript) avec la version numérique du QCM sur la distance entre deux points. Je ne commenterai ce programme que dans l’annexe. A ce stade, je me bornerai à signaler :

  • qu’il suffit d’adapter de façon cosmétique ce code d’une cinquantaine de lignes pour pouvoir traiter les autres exemples de QCMs.
  • qu’en règle générale les ressources disponibles dans LaboMep font au minimum quelques centaines de lignes de code (donc gros travail de codage), y compris dans les didacticiels de formation des développeurs J3P (exemple).

D) Plusieurs variantes de l’exemple « distance entre deux points »

Voici un exemple d’exécution de la version « saisie numérique », dont le code a été fourni dans la section précédente :

On peut constater que l’exercice consiste à demander 3 fois la distance entre deux points (qui changent à chaque fois), que l’élève vient de répondre correctement à la seconde question, mais qu’il s’est trompé pour la première puisque son score total vaut 1 (0+1). Un clic sur le bouton « Suite » permet ici de passer à la troisième question.

Pour un développeur J3P, le passage de la version numérique à la version formelle (voir écran ci-dessus) est très simple puisqu’il lui suffit :

  • de modifier le code Javascript d’une cinquantaine de lignes que j’ai fourni dans la section précédente : remplacer l’instruction « this.extype = « num » » par « this.extype = « mathquill » », et préciser que la ressource utilise deux outils J3P de calcul formel (« webxcas » et « formel ») s’ajoutant à mon outil de QCM « rexams ».
  • de modifier les fichiers « html » de la version numérique, de façon indirecte en adaptant le fichier Rmarkdown qui les produit : en effet, si la valeur formelle était déjà présente dans les explications des fichiers « html » initiaux, l’outil « rexams » n’est pas capable de détecter où elle se trouve sans indication supplémentaire (j’ai choisi comme convention de la délimiter grâce 3 points d’exclamation placés avant et après, voir lien).

Il est aussi possible de décliner l’exercice sous la forme d’un choix dans une liste de propositions :

Cela nécessite que le développeur J3P adapte le code Javascript, en remplaçant l’instruction « this.extype = « num » » par « this.extype = « schoice » ». Le fichier RMarkdown permettant de créer les fichiers « html » intermédiaires est disponible dans la documentation de http://www.r-exams.org/.

E) Conclusion

Quand j’avais développé en 2019 deux outils algorithmiques (pour Python et Blockly), je ne savais pas s’ils seraient adoptés [2] ou non par l’équipe J3P. Il en va de même pour l’outil « rexams » qui, à ce jour, a donné lieu à la création d’une unique ressource pédagogique publiée dans LaboMep. Mais c’est un bon début compte-tenu du contexte :

  • sachant qu’il y a une petite équipe de développeurs, cela suffit pour obtenir un pourcentage non négligeable de collègues ayant fait l’effort de se documenter sur RMarkdown pour utiliser ce nouvel outil J3P !
  • la période actuelle n’est guère propice au développement de nouvelles ressources, car J3P est depuis un an en cours de restructuration afin de sécuriser le processus de création et de maintenance de ses nombreuses ressources pédagogiques.

Annexe

Codage en Javascript d’une ressource de type QCM avec l’outil « rexams »

Avant d’aborder le codage en Javascript, je rappellerai quelques principes fondamentaux sur l’exécution d’une ressource dans LaboMep :

  • c’est un cas particulier (à un nœud) de l’exécution d’un graphe d’exercices pouvant être défini par l’enseignant à l’aide d’une interface.
  • tout au long du processus d’exécution d’un graphe d’exercices (appelé graphe de sections dans le jargon J3P), le moteur d’exécution de J3P s’appuie sur une notion fondamentale appelée état du nœud courant, pouvant prendre 3 valeurs :
    • énoncé : le moteur génère la question à partir de paramètres aléatoires (par exemple la distance entre deux points dont les valeurs varient à chaque répétition), génère l’environnement de saisie, puis attend la réponse de l’élève.
    • correction : le moteur contrôle la réponse de l’élève et, si l’élève a épuisé le nombre d’essais auxquels il a droit, affiche la correction.
    • navigation : le moteur passe à la question suivante de l’exercice (par exemple, la distance entre 2 points avec un nouveau jeu de données) ou, si c’était la dernière, à l’exercice suivant du graphe.

A chaque exécution d’un graphe d’exercices, le moteur d’exécution de J3P crée un objet global (très complexe) de classe « Parcours », composé :

  • d’informations diverses : nœud courant du graphe, état du nœud courant, score de l’élève…
  • de très nombreuses méthodes (terme employé en programmation objet pour désigner les sous-programmes de la classe Parcours) pour gérer le parcours de l’élève, dont certaines proviennent des développeurs de ressources.

Ces informations préliminaires vont me permettre de commenter brièvement le code Javascript de la version numérique de l’exercice de démonstration « distance entre deux points ». J’en reproduis ici une partie de la cinquantaine de lignes de code :

  1. // on ajoute à la classe Parcours la méthode Sectiontestrexams_dist
  2. Parcours.prototype.Sectiontestrexams_dist = function() {
  3.     // toute section doit avoir une fonction nommée ainsi
  4.     function _Donnees() {
  5.         this.nomsection = "testrexams_dist";
  6.         this.touche_entree = false;
  7.         this.nbchances = 1;  // un seul essai accordé à l’élève
  8.         this.numeroessai = 1;
  9.         this.structure = "presentation1";
  10.         this.pe = 0; // score initial mis à 0
  11.         ...
  12.     }
  13.     // pour récupérer les fichiers html créés avec RMarkdown
  14.     this.chemin = "sections/EssaisPatrick/rexams/dist/";
  15.     this.nom_fichier = "ex";
  16.     this.nb_fichiers = 50; // ex1.html ... ex50.html
  17.     this.extype = "num";  // QCM de type numérique
  18.     this.extol = 0.01;  // tolérance pour une réponse approchée
  19.     // pour gérer 3 états possibles pendant l’exécution du graphe
  20.     switch (this.etat) {
  21.         case "enonce":
  22.             if (this.debutdelasection) {
  23.                 this.DonneesSection = new _Donnees();
  24.                 j3pRexams.enonce_debutdelasection_vrai(this);
  25.             } else {
  26.                 j3pRexams.enonce_debutdelasection_faux(this);
  27.             }
  28.             break;
  29.         case "correction":
  30.             j3pRexams.correction(this);
  31.             break;
  32.         case "navigation":
  33.             j3pRexams.navigation(this);
  34.             break;
  35.     }
  36. }

Télécharger

Voici les principaux points à retenir à propos ce code :

  • le code de la ressource « testrexams_dist » est introduit comme méthode (nommée « Sectiontestrexams_dist ») de la classe « Parcours ».
  • quand le moteur de J3P exécute un graphe de ressources, un objet de classe « Parcours » est créé et la méthode « Sectiontestrexams_dist » est appelée à plusieurs reprises pendant que l’exercice « distance entre deux points » est traité par l’élève : à chaque répétition de la question, elle est exécutée trois fois (une fois dans l’état « énoncé », une fois dans l’état « correction », une fois dans l’état « navigation »).
  • les this.xxx présents dans le code sont relatifs à une instance quelconque (this) dde la classe « Parcours » : par exemple, this.nbchances=1 précise qu’élève n’a droit qu’à une tentative à chaque question, this.extype=« num » précise qu’une zone de saisie doit être affichée…
  • les j3pRexams.xxx (j3pRexams.correction, j3pRexams.navigation…) présents dans le code appellent des sous-programmes de l’outil « rexams » que j’ai développé ; leur paramètre est l’objet de type « Parcours » (à savoir this).

Une interface pour créer et tester en ligne des ressources « rexams »

Supposons qu’un collègue utilisant LaboMep dans ses enseignements désire qu’une nouvelle ressource pédagogique (pas forcément de type QCM) soit développée. Deux options s’offrent à lui :

  • soumettre son souhait à l’équipe J3P pour qu’un développeur la code en Javascript.
  • se former à J3P, coder sa ressource en Javascript avec un émulateur J3P à installer localement sur son ordinateur, la faire tester par l’équipe J3P en la transférant sur le serveur de développement, puis enfin demander au technicien chargé de la maintenance d’en faire le transfert sur LaboMep.

S’il choisit la première option, le collègue demandeur risque de devoir patienter longtemps car le nombre de développeurs est restreint, sans oublier les réformes du collège et du lycée qui sont très chronophages. Et s’il a des compétences suffisantes en codage pour envisager la seconde option, il devra être très persévérant pour parvenir à ses fins… Alors, comment faire afin de parvenir à des délais moins longs pour concrétiser un projet de nouvelle ressource ?

Cette question, j’ai été amené à me la poser pour la production de ressources Python après avoir reçu ce courriel suite à un de mes articles :

Je cherche le moyen de créer un exercice Labomep qui demanderait aux élèves un bout de code Python (tels que les exercices que vous avez apportés dans les sections J3P lycée). C’est votre article « Quid des ressources algorithmiques dans LaboMep ? » de la revue MathémaTICE qui me fait penser que cela est possible d’autant que la fonction verifierPython que vous proposez semble fort commode pour tester la solution élève.

...

Serait-il possible que vous m’indiquiez, s’il vous plaît, le moyen de procéder ?

Comme son souhait était hélas moins simple à concrétiser que mon article n’en donnait l’illusion [3] et que Sésamath est dans une longue phase transitoire entre J3P et SésaParcours, j’ai simplement redirigé ce collègue vers les responsables de J3P. Mais j’ai bien l’intention, quand j’en aurai le temps, de réfléchir à des moyens à mettre en œuvre pour faciliter le développement de ressources algorithmiques (Python et Scratch).

Dans le cas de la production de ressources de type QCM, le gros du travail consiste à élaborer des documents RMarkdown et à les tester, ce qui est à la portée de tout enseignant puisque R est un logiciel de mathématiques très bien documenté. Pour débuter, il est possible d’éviter l’installation de R (et de l’environnement graphique RStudio) en passant par une interface web disponible sur mes pages professionnelles [4] :

Une liste déroulante permet de télécharger quelques exemples de fichiers RMarkdown (distance entre deux points, dérivée…), mais on peut bien sûr en changer le contenu avant de cliquer sur le bouton « Exécuter  » pour obtenir une version aléatoire du QCM [5]. Et un clic sur le bouton « J3P  » permet de tester en ligne le QCM grâce à un émulateur J3P installé sur mes pages professionnelles (voir copie d’écran).

De J3P à SésaParcours

Quand, en 2019, je m’étais autoformé à J3P pour initier le développement de ressources algorithmiques (en Python et en programmation par blocs), j’avais eu des impressions contrastées :

  • très bonnes en découvrant les mécanismes sophistiqués permettant de créer des ressources variées, puis de les utiliser dans LaboMep (paramétrage des exercices par l’enseignant, parcours personnalisé sous la forme d’un graphe d’exercices).
  • réservées sur la façon de former les développeurs J3P, en « encourageant plus ou moins volontairement » une programmation peu modulaire, que ce soit dans la documentation ou dans les squelettes d’exercices types (fournis avec l’environnement J3P à installer localement) dont on complète les trous : j’en comprenais parfaitement les motivations initiales (rendre rapidement les développeurs opérationnels pour étoffer le catalogue de ressources), mais je trouvais en effet qu’on avait trop tardé à envisager une programmation plus sécurisée devenue indispensable compte-tenu de l’importance stratégique des services rendus par ce projet [6].

J’ai donc découvert avec intérêt, en intégrant la liste de diffusion j3p-sections@sesamath.net, qu’un futur J3P (nommé SésaParcours) est élaboré depuis plusieurs mois pour sécuriser J3P. En attendant qu’un hypothétique auteur en détaille dans MathémaTICE les motivations et les évolutions techniques par rapport au J3P actuel, j’ai un temps songé à aborder ce sujet car il peut intéresser de nombreux lecteurs (utilisateurs de LaboMep ou amateurs de codage), mais j’ai jugé plus judicieux d’y renoncer.