A) Introduction
Quand MathémaTICE m’a signalé début Octobre 2022 que la revue risquait une pénurie d’articles à partir de Janvier 2023, je n’avais aucune idée à soumettre. Et puis, peu après, le déclic est venu suite à un TP effectué en première année d’IUT, où j’utilisais le logiciel « blocs/Python » développé par Vittascience (voir http://revue.sesamath.net/spip.php?article1525) et dont un exercice portait sur deux cryptarithmes présentés dans http://revue.sesamath.net/spip.php?article1033.
Cela peut surprendre que j’aie encore recours à la programmation par blocs pour coder en Python à l’IUT, mais depuis deux ans j’avais constaté pas mal de lacunes chez mes étudiants (n’ayant pas suivi d’option informatique au lycée) malgré la réforme de 2018. Et comme en plus j’avais cette année des étudiants étrangers n’ayant jamais programmé, les trois premiers TPs du module d’algorithmique ont été effectués avec le logiciel « blocs/Python » de Vittascience. Selon les exercices, une des approches suivantes a été choisie :
- demander aux étudiants de programmer par blocs, produisant ainsi automatiquement un code Python à copier-coller dans leur compte-rendu.
- amorcer la programmation avec des blocs, produisant ainsi automatiquement un code Python à compléter.
- coder directement en Python.
Avant d’entrer dans le vif du sujet, c’est à dire le déroulement du TP3, je vais le resituer dans son contexte. Chaque semaine, les étudiants ont un cours (1 h), un TD (1h30) et un TP (1h30). Les cours et les TDs se font en notations algorithmiques, comme je le faisais déjà avant les réformes du collège (Scratch en 2016) et du lycée (Python en 2018). Pour justifier cette approche algorithmique aux étudiants, j’ai illustré dans plusieurs langages (utilisés pendant leur cursus en IUT) un programme élémentaire affichant tous les entiers compris entre 1 et 10 :
Il est clair que les notations sont très diverses et pas toujours intuitives (notamment le « 11 » de Python et le « k<=10 » de Javascript), d’où l’intérêt d’une notation algorithmique « universelle » conceptualisant la boucle « Pour » :
Et pour justifier le « Fin Pour », j’ai fait une analogie avec la programmation par blocs : le « Fin Pour » correspond à la fin du bloc.
B) Exercice 1 du TP3 : tortue et carrés imbriqués
Le TP1 se terminait par la programmation des deux figures ci-dessus (sans le coloriage en vert) :
- utiliser un bloc « répéter 5 fois » pour afficher la taille des différents carrés, puis en déduire un programme construisant la figure de gauche.
- utiliser un bloc « répéter 3 fois » et le programme de la question (1) afin de dessiner la figure de droite.
L’objectif était de jauger ainsi le niveau d’abstraction des étudiants à leur arrivée en IUT. Peu d’étudiants ont réussi à programmer la figure de droite, beaucoup ayant déjà été en difficulté pour réaliser la figure de gauche, voire n’ayant pas eu le temps d’aborder ces deux questions.
J’ai donc décidé de remettre la programmation de la figure de gauche au menu du TP3, en demandant cette fois-ci aux étudiants d’utiliser une boucle « Pour ». Pour cela, la consigne était de reproduire le programme ci-dessous et de l’exécuter, puis de le compléter afin de dessiner les 5 carrés imbriqués :
Je pensais que cela serait une formalité, ce qui n’a pas hélas été le cas pour au moins la moitié des étudiants. Je leur ai alors fourni oralement l’indication suivante : ajoutez un bloc « répéter 4 fois ». Même si cela a aidé certains de ces étudiants à finaliser l’exercice, j’ai encore eu de mauvaises surprises telles que :
- étudiants ajoutant le bloc « répéter 4 fois » à la suite du bloc « compter », et non dedans.
- étudiants ne sachant pas quoi mettre dans le « répéter 4 fois ».
- étudiants faisant un carré de taille fixe (par exemple 23), sans arriver à faire le lien avec la variable « taille » dont le programme donné initialement faisant pourtant afficher les différentes valeurs (23, 46, 69, 92 et 115).
Cela m’a d’autant plus déçu que, lors du cours de la semaine 2 (consacré à la boucle « Pour »), j’avais fourni l’algorithme suivant pour résoudre ce problème :
Pour taille de 23 à 115 par 23 Faire
Répéter 4 fois
Avancer(taille)
Gauche(90)
Fin Répéter
Fin Pour
Non seulement les étudiants ne sachant pas résoudre l’exercice ignoraient l’existence de cet algorithme, mais la plupart n’ont ensuite pas daigné sortir leur cours lorsque je leur ai indiqué qu’il y figurait…
C) Exercice 2 du TP3 : cryptarithmes
En TDs (semaines 2 et 3), j’avais posé de nombreux exercices « classiques » d’algorithmique sur la boucle « Pour ». Avant de le faire en Python dans ce TP3 (exercice 3), j’avais décidé d’innover cette année avec un sujet plus « ludique » et original : la résolution des cryptarithmes NON + NON = OUI et OUI + OUI = NON.
Dans l’énoncé de cet exercice découpé en plusieurs questions, j’avais commencé par indiquer qu’un cryptarithme était un casse-tête numérique et logique consistant en une équation mathématique où les lettres représentent des chiffres (tous différents) à trouver.
Exemple : NON + NON = OUI
- une solution est 373 + 373 = 746 (N=3, O=7, U=4, I=6)
- 242 + 242 = 484 ne convient pas car O=I=4
Pour commencer, la consigne était de reproduire le programme par blocs ci-dessous :
Cela permettait d’obtenir directement un programme Python donnant le chiffre des centaines (variable « O ») et le chiffre des unités (variable « I ») d’un entier compris entre 100 et 999 (variable « OUI »). Il restait à le compléter pour récupérer le chiffre des dizaines (variable « U »), ce qui fut souvent « épique »…
J’ai donc dû distiller au fur et à mesures les informations suivantes, débloquant ainsi à chaque étape de nouveaux étudiants :
- trouver une formule permettant d’obtenir le nombre entier formé des deux derniers chiffres de OUI : par exemple, pour OUI=743, il faut obtenir 43
- une formule possible pour obtenir cet entier est OUI – 100*O
- la formule donnant le chiffre des dizaines d’un nombre à deux chiffres est similaire à celle donnant le chiffre des centaines d’un nombre à trois chiffres
- la formule mathématique est PartieEntiere( (OUI-100*O)/10 )
- en Python c’est math.floor( (OUI-100*O)/10 ) ), après m’être aperçu qu’un étudiant avait traduit la formule en « (OUI-100*O) %10 »
Il me semble que j’ai dû donner la formule « PartieEntiere( (OUI-100*O)/10 ) » à environ la moitié des étudiants, car cette question leur avait déjà pris une demi-heure, ce à quoi je ne m’attendais pas.
La consigne était de reproduire le programme par blocs ci-dessous, puis de l’exécuter afin connaître les solutions potentielles de NON+NON=OUI :
Cela permettait donc d’obtenir automatiquement un programme Python trouvant 5 solutions potentielles au cryptarithme (121, 242, 252, 373 et 494), dont certaines seront à éliminer dans la question 3 car les lettres (N, O, U et I) n’ont pas des valeurs distinctes.
Mais hélas, tous les étudiants ne sont pas parvenus à obtenir ce résultat, à cause d’erreurs logiques en reproduisant le programme par blocs :
- la variable « O » de la boucle interne a été parfois nommée « 0 » (zéro), ce que Blockly acceptait en le traduisant par « my_0 » dans le code Python, ce qui n’a pas étonné outre mesure les étudiants ayant fait cette erreur (« ben, j’ai fait ce que vous m’avez demandé en reproduisant le programme par blocs, vous n’aviez pas dit dans l’énoncé qu’il fallait aussi comprendre le code Python obtenu »).
- la formule « NON=100*N+10*O+N » n’a parfois pas été programmée correctement par blocs, ce qui a débouché sur un code Python ( « NON=100*N+10*(N+0) » ) qui aurait dû interpeller les étudiants concernés s’ils avaient eu du recul mathématique sur le travail demandé…
- un manque de recul sur l’imbrication des blocs définissant la condition du « si » a quelquefois débouché sur le code Python « if centaines == (O and N != O) » ; en grande partie, il s’agissait des étudiants étrangers n’ayant jamais programmé auparavant (y compris avec Scratch), dont le maniement laborieux des blocs accaparait leur attention.
La consigne était de combiner le code Python des questions 1 et 2, afin d’éliminer les solutions potentielles dont les valeurs des lettres (N, O, U et I) n’étaient pas toutes différentes. Cela devait déboucher sur un code du type :
import math
for N in range(1,5) :
for O in range(0,10) :
NON = 100*N + 10*O + N
OUI = NON+NON
centaines = math.floor (OUI/100) # chiffre des centaines de OUI
U = math.floor ((OUI-100*O)/10) # chiffre des dizaines de OUI
I = OUI %10 # chiffre des unités de OUI
if (centaines==O) and (N!=O) and (N!=I) and (I!=O) and (U!=N) and (U!=I) and (U!=O) :
print(NON,OUI)
Télécharger
Là encore, ça ne s’est pas passé comme prévu, y compris pour étudiants plutôt à l’aise jusqu’ici : « on rajoute quoi au code Python de la question 2 et où ??? ». Et pour des étudiants plus en difficulté, il y a assez souvent eu des problèmes d’indentation pour les instructions donnant U et I, ou un mauvais placement avant le calcul de « OUI ».
J’ai effectué à quatre reprises ce TP, à chaque fois avec une quinzaine d’étudiants. Dans le dernier groupe, comme personne n’avait résolu cette question dix minutes avant la fin de la séance, je suis allé dans mon bureau mettre la solution en ligne sur l’ENT, puis suis revenu dans la salle pour que les étudiants aillent voir la solution et me posent des questions s’ils ne la comprenaient pas. Beaucoup ont joué la montre en n’allant pas récupérer ce programme, attendant « stratégiquement » la fin de la séance… Comme c’était le dernier enseignement de la journée pour ce groupe de TP, quelques étudiants sont cependant restés au-delà de la séance qui finissait à 16h30 : à une exception près, cocorico, il s’agissait des étudiants étrangers du groupe...
Compte-tenu des difficultés rencontrées dans les questions précédentes, peu d’étudiants ont abordé ce nouveau cryptarithme, à programmer directement en Python. Et un seul l’a résolu. A titre indicatif, voici le code Python que j’espérais a priori :
import math
for O in range(1,5) :
for U in range(0,10) :
for I in range(0,10) :
OUI = 100*O + 10*U + I
NON = OUI+OUI
N = math.floor (NON/100) # chiffre des centaines de NON
O1 = math.floor ((NON-100*N)/10) # chiffre des dizaines de NON
N1 = NON %10 # chiffre des unités de NON
if (N==N1) and (O==O1) and (N!=O) and (N!=I) and (I!=O) and (U!=N) and (U!=I) and (U!=O):
print(OUI,NON)
Télécharger
D) Exercice 3 du TP3 : diviseurs et nombres premiers
Cet exercice, qui n’a été abordé par personne, était à résoudre directement en Python.
1) Testez le programme suivant avec les valeurs 28 et 29 :
n = int(input('Entrez un entier :'))
for k in range(1, n+1):
if n % k == 0 : # reste de la division de n par k
print(k)
Télécharger
2) Complétez le programme Python de la question 1 afin qu’il :
- calcule et affiche le nombre de diviseurs de « n »
- indique si « n » est premier (c’est à dire si son nombre de diviseurs est 2) ou non
3) Déduisez-en un programme Python affichant tous les nombres premiers inférieurs à 100.
E) Conclusion
Les cryptarithmes n’ont hélas pas rencontré un grand engouement, contrairement aux problèmes de tortue qui restent une valeur sûre au-delà du secondaire. Ce manque d’intérêt a été renforcé par un manque d’abstraction mathématique : par exemple, sachant que j’avais déjà fourni les formules donnant le chiffre des centaines et le chiffre des unités d’un entier « OUI » compris entre 100 et 999, je ne m’attendais pas à ce qu’il me faille donner explicitement la formule « U = PartieEntiere( (OUI-100*O)/10 ) » en IUT.
Par ailleurs, j’avais demandé il y a deux ou trois ans à un collègue de lycée s’il pensait que l’introduction de Scratch au collège et de Python au lycée (hormis les options informatiques) allait selon lui améliorer significativement le niveau algorithmique des élèves à leur arrivée dans l’enseignement supérieur. Il m’avait répondu que non, et je confirme hélas son pronostic pessimiste.
- le sujet des 3 TPs