Programmation du Next
Fonctionnement général
Le fichier next.py est un script Python permettant de gérer l'ordre d'enchainement des exercices dans une activité. Il fonctionne de manière stateless, c'est-à-dire qu'il ne conserve aucun état entre deux exécutions. Chaque fois qu’un étudiant termine un exercice, le script est entièrement réexécuté pour déterminer le prochain exercice à lancer.
Pour facilité la programmation du Next, une librairie de fonctions est disponible, appelée NextLib. Cette librairie contient des fonctions permettant de récupérer des informations sur les exercices, de lancer des exercices, de gérer la notation de l'activité, etc.
Exemple basique
Voici un exemple simple d’un script next.py qui lance chaque exercice une fois, dans un ordre aléatoire :
# Si tous les exercices ont été faits au moins une fois,
# on calcule la note de l'activité et on arrête l'activité
if isAllExercisesPlayed():
setActivityGrade(average_grade_strategy)
stopActivity()
# Empêche de passer à l'exercice suivant si le dernier lancé n'a pas été essayé
playPreviousIfUnplayed()
# Lance un exercice aléatoire qui n'a pas encore été fait
playExercise(getRandomUnplayedExerciseId())
Dans cet exemple, plusieurs points importants sont à noter :
- Interruption de l'exécution : Quand une fonction du type
play...()
lance un exercice, cela interrompt l'exécution du script Next. La suite du script ne sera donc pas exécutée. - Réexécution complète : Le script est réexécuté entièrement à chaque fois qu'un exercice est terminé. Il est donc essentiel de vérifier en début d’exécution si tous les exercices ont été faits pour arrêter l’activité sans en relancer un autre.
- Faire l'exercice en cours : La fonction
playPreviousIfUnplayed()
est utilisée pour éviter de lancer un nouvel exercice si l'étudiant n'a pas encore essayé l'exercice en cours. - Lancement des exercices non faits : Les fonctions appelées ne lancent que des exercices "unplayed", c'est-à-dire qui n'ont pas encore été faits par l'étudiant. Cela permet de s'assurer que l'on ne relance pas à l'infini le même exercice.
- Fin du script : Si on arrive à la fin du script sans avoir effectué d'action (lancer un exercice, stopper l'activité, etc.), une erreur sera levée. Il est donc important de toujours s'assurer que le script a bien une action à effectuer.
- Session de l'étudiant : Si l'étudiant ferme son navigateur ou se déconnecte, sa session est conservée. Il pourra reprendre l'activité là où il l'a laissée lors de sa prochaine connexion.
Cet exemple est très basique, mais il est possible de programmer des Next beaucoup plus complexes en utilisant des conditions et des stratégies de notation personnalisées. Ce guide explique en détail comment programmer un Next complet et intelligent.
Lancer des exercices
Pour programmer un Next, la première étape est de pouvoir lancer des exercices. Pour cela, plusieurs fonctions sont disponibles dans la NextLib.
Obtenir l'identifiant d'un exercice
getExerciseId(groupNb: int = 0, exerciseNb: int = 0) -> str
Cette fonction permet de récupérer l’identifiant unique d’un exercice en spécifiant son numéro de groupe et sa position dans ce groupe. L’ordre des exercices est déterminé par leur ordre d’ajout dans l’activité :
Lancer un exercice
playExercise(exerciseId: str, params: Optional[dict] = None) -> None
Cette fonction permet de démarrer un exercice à partir de son identifiant. Une fois appelée, elle interrompt immédiatement l’exécution du script Next, le reste du code ne sera donc pas exécuté.
Le paramètre optionnel params
permet de transmettre des données supplémentaires à l'exercice. Son utilisation est expliquée en détail ici.
playPreviousIfUnplayed()
ou playAllFromGroup(groupNb: int, randomOrder: bool = False)
.
Les détails sont disponibles dans la documentation de la NextLib.Stopper l'activité
Pour finir l'activité et afficher le récapitulatif des notes, il est possible d'utiliser la fonction suivante :
stopActivity() -> None
Exemples d'utilisation
# Récupère l'id de l'exercice 1 du groupe 0
exerciseId = getExerciseId(0, 1)
# Lance l'exercice
playIfUnplayed(exerciseId)
# Lance l'exercice 5 du groupe 2
playIfUnplayed(getExerciseId(2, 5))
# Fin de l'activité
stopActivity()
# Lance tous les exercices du groupe 1 dans un ordre aléatoire
playAllFromGroup(1, True)
# Lance un exercice aléatoire du groupe 2
playAnyFromGroup(2)
# Fin de l'activité
stopActivity()
Programmer un Next intelligent
Pour programmer un Next intelligent, il est possible d'utiliser des conditions pour déterminer le prochain exercice à lancer.
Fonctions de récupération de données
Pour récupérer des données sur les exercices, plusieurs fonctions sont disponibles, par exemple :
# Teste si un exercice a été fait
isPlayed(exerciseId: str) -> bool
# Récupère la note du dernier exercice
getPreviousGrade() -> Optional[int]
# Récupère la dernière note d'un exercice
getExerciseLastGrade(exerciseId: str) -> Optional[int]
# Récupère la meilleure note d'un exercice
getExerciseBestGrade(exerciseId: str) -> Optional[int]
# Récupère le nombre de tentatives d'un exercice
getExerciseAttempts(exerciseId: str) -> int
# Récupère l'identifiant du dernier exercice lancé ou None s'il n'y en a pas
getPreviousExerciseId() -> Optional[str]
...
Exemples d'utilisation
Ces fonctions peuvent être utilisées pour ajouter une logique d'enchainement plus complexe, par exemple :
- Relancer un exercice si la note est inférieure à 50 :
previousId = getPreviousExerciseId() # Récupère le dernier exercice lancé
if previousId and getPreviousGrade() < 50:
playExercise(previousId)
else:
playFirstUnplayedExercise()
- Lancer un exercice avancé si la note est supérieure à 80 :
previousId = getPreviousExerciseId()
if not previousId:
playExercise(getExerciseId(0, 0)) # Démarre par le premier exercice
elif getPreviousGrade() >= 80:
playExercise(getExerciseId(1, 0)) # Exercice avancé
else:
playExercise(getExerciseId(2, 0)) # Exercice de renforcement
Dans cet exemple, l'activité est organisée en trois groupes d'exercices, comme suit :
- Relancer un exercice si la meilleure note est inférieure à 70 et qu'il y a moins de 3 tentatives :
previousId = getPreviousExerciseId()
# Si aucun exercice n'a été lancé, on lance le premier exercice non fait
if not previousId:
playExercise(playFirstUnplayedExercise())
bestGrade = getExerciseBestGrade(previousId)
attempts = getExerciseAttempts(previousId)
# bestGrade peut être None si l'exercice n'a pas encore été fait
if bestGrade is not None and bestGrade < 70 and attempts < 3:
playExercise(previousId)
else:
playFirstUnplayedExercise()
Gestion de la notation
Pour gérer la notation de l'activité, il faut utiliser la fonction suivante :
setActivityGrade(grade_aggregation_strategy: Callable[[], int]) -> None
Cette fonction permet de calculer la note finale de l'activité en fonction de la stratégie de notation passée en paramètre. La stratégie de notation est une fonction qui ne prends pas de paramètre et qui retourne un entier, correspondant à la note finale de l'activité. Par défaut, la NextLib propose deux stratégies de notation :
average_grade_strategy
: Moyenne des notes de tous les exercicesbest_grade_strategy
: Note maximale obtenue
Exemples d'utilisation
- Prendre la meilleure note obtenue :
if isAllExercisesPlayed():
setActivityGrade(best_grade_strategy)
stopActivity() # On stoppe l'activité après avoir défini la note
playPreviousIfUnplayed()
playFirstUnplayedExercise()
- (Stratégie personnalisée) Enlever des points en fonction du nombre de tentatives :
def attempts_strategy():
nbAttempts = 0
for g in range(0, getGroupsCount()):
for e in range(0, getGroupExercisesCount(g)):
nbAttempts += getExerciseAttempts(getExerciseId(g, e))
# Note = Moyenne des notes - Nombre de tentatives
return max(0, average_grade_strategy() - nbAttempts)
setActivityGrade(attempts_strategy)
stopActivity()
Mémoire du Next
Pour stocker des informations entre les différentes exécutions du Next, il est possible d'utiliser les fonctions suivantes :
# Stocke une valeur
save(variableName: str, value: Any) -> None
# Récupère une valeur
load(variableName: str, default: Any = None) -> Optional[Any]
Exemple d'utilisation
Lance les exercices à faire dans l'ordre défini dans la liste exercisesToDo
:
# Charge la liste des exercices à faire ou initialise une liste par défaut
exercisesToDo = load("exercisesToDo", [0, 3, 5, 7])
# Vérifie que la liste n'est pas vide
if exercisesToDo:
# Recupère le premier exercice de la liste et le retire
todo = exercisesToDo.pop(0)
# Sauvegarde la liste des exercices restants pour la prochaine exécution
save("exercisesToDo", exercisesToDo)
# Lance l'exercice
playExercise(getExerciseId(0, todo))
else:
stopActivity()
Paramétrage d'exercices
Il est possible de transmettre des paramètres à un exercice lors de son lancement.
Pour cela, il suffit de passer un dictionnaire de paramètres en deuxième argument de la fonction playExercise(exerciseId, params)
.
Les paramètres correspondent à des variables qui seront accessibles dans l'exercice. Cela impacte l'exercice de la même manière qu'avec l'utilisation des main.plc / main.plo. Cependant, ici les paramètres sont passés via le Next, ce qui permet de les générer dynamiquement en Python en fonction de la logique du Next.
Exemples d'utilisation
# Surcharge le titre de l'exercice
playExercise(getExerciseId(0, 0), {"title": "Exercice paramétré"})
# Passe un paramètre de difficulté
playExercise(getExerciseId(0, 1), {"difficulty": 3})
# Passe plusieurs paramètres
playExercise(getExerciseId(0, 2), {"title": "Exercice 3",
"result": 42,
"previousGrade": getPreviousGrade()})
Accès aux variables d'exercices
Il est possible d'accéder aux variables d'un exercice pour récupérer des informations.
Pour cela, il faut utiliser la fonction getExerciseVariable(exerciseId, variableName)
.
Next
de l'activité pour pouvoir utiliser ces fonctions. (Configuration)Exemple d'utilisation
Utiliser la réponse à un exercice précédent pour un exercice suivant :
# Lance l'exercice 1
ex1Id = getExerciseId(0, 1)
playIfUnplayed(ex1Id)
# Récupère la valeur de la variable "form" de l'exercice 1
ex1Form = getExerciseVariable(ex1Id, "form")
# Lance l'exercice 2 en passant la réponse de l'exercice 1
ex2Id = getExerciseId(0, 2)
playIfUnplayed(ex2Id, {"previousAnswer": ex1Form})
# Fin de l'activité
setActivityGrade(average_grade_strategy)
stopActivity()
Génération d'exercices
Il est possible de générer des exercices de manière dynamique durant l'exécution du Next.
Pour cela, il faut utiliser la fonction generateAndPlayExercise(exerciseId, params)
.
Cette fonction génère un nouvel exercice à partir d'un exercice donné, modifié par les paramètres passés, et le lance.
Cela permet de créer une infinité d'exercices différents dans la même activité.
Cette fonction possède 3 comportements possibles :
- Si l'exercice n'a pas été généré, il est généré et lancé. (Et l'exécution du Next est interrompue)
- Si l'exercice a été généré à l'itération précédente, la fonction renvoie l'id de l'exercice généré.
- Sinon, la fonction renvoie
None
.
Exemple d'utilisation
L'exemple suivant génère un exercice à chacune des 3 itérations, avec un énoncé différent. Il stocke la note de chaque exercice généré. Puis lance l'exercice 1 d'origine.
ex1 = getExerciseId(0, 0)
for i in range(3):
exId = generateAndPlayExercise(ex1, {"statement": "Exercice avec i = " + str(i)})
if exId:
# Ici, on peut utiliser l'id du dernier exercice généré pour,
# par exemple, récupérer des informations
save("grade" + str(i), getExerciseLastGrade(exId))
playIfUnplayed(ex1, {"statement": "Le vrai ex1"})
stopActivity()
Débogage du Next
Pour faciliter le débogage du Next, il est possible d'utiliser la fonction platon_log(*args: Any)
.
Cette fonction affiche un message dans la console de débogage de l'exercice lancé.
Le fonctionnement est le même que pour les exercices.
Exemple d'utilisation
platon_log("Début du script Next")
platon_log("Note actuelle :", getPreviousGrade(), "/ 100")
Dans la console de débogage :
Début du script Next
Note actuelle : 42 / 100