Forum général.cherche-logiciel programme et algo de tri

Posté par  . Licence CC By‑SA.
Étiquettes :
10
21
juin
2025

trier, je pense que c'est le terme correct même si s'agissant d'élèves ça peut sonner bizarrement.

Soit un ensemble de ~ 170 élèves (un niveau), 6 classes et des contraintes :
- le choix des élèves pour les options (entre 0 et 5 options)
- le profilage des classes (tous les élèves de section foot dans la classe 3, les LV2 espagnol dans les classes 5 et 6, à peu près moitié-moitié
- équilibre filles-garçons partout
- 30 élèves max par classe

enfin, vous voyez je suppose le problème : constituer les classes

Question : existe-t-il des outils libres (libres par principe et gratuit par économie), RGPD compatibles, simples à prendre en main (d'ici mercredi ;-)) qui pourrait faire le boulot, au moins en partie.

Les données brutes seront de toute façon à reformater : je connais hélas trop les mésusages des tableurs par mon administration !

Conseils, avis et propositions bienvenus

  • # recherche ?

    Posté par  (site web personnel) . Évalué à 3 (+1/-0).

    tu préfères le tri à bulle ?

    plus sérieusement :

    après une recherche ddg : https://duckduckgo.com/?q=logiciel+constitution+classe+d%27%C3%A9l%C3%A8ves&t=ftsa&ia=web

    https://www.laurentleguidec.fr/le-blog/outils-de-repartition-des-classes/ étude de l'existant : 2 en ligne, un via tableur (mais pas de licence précisée :/) https://www.tilekol.org/voici-reparticlass-2020

    en GNU/GPL, en ligne (mais données restant dans navigateur a priori) ou en local : https://educajou.forge.apps.education.fr/repartition/ et le code https://forge.apps.education.fr/educajou/repartition

    bah, je te laisse fouiller et faire un retour sur celui que tu choisis

    • [^] # Re: recherche ?

      Posté par  . Évalué à 4 (+2/-0). Dernière modification le 21 juin 2025 à 15:29.

      Merci mais ça ne convient pas vraiment : ce sont des outils prévu pour créer les structures de classes à l'échelle d'une école (primaire : faire 2 CP, un CP-CE1, un CE1, etc.) or je cherche à remplir une structure imposée par les contraintes :

      En 3e1 : des élèves LV1 anglais et LV2 allemand
      En 3e3 : tous les élèves de section foot et des LV2 anglais
      etc.

      et arriver à placer Kevin en 3e2, Jessica en 3e1 etc.

  • # Formulation formelle

    Posté par  (Mastodon) . Évalué à 6 (+3/-0).

    Je doute qu'un tel outil existe, le soucis serait dans la difficulté de donner formellement les contraintes.

    Pour avoir vu mon père faire ça pendant des années (ancien proviseur-adjoint en lycée technique), je sais que c'est un vrai casse-tête, bon courage !

    En théorie, la théorie et la pratique c'est pareil. En pratique c'est pas vrai.

    • [^] # Re: Formulation formelle

      Posté par  (site web personnel) . Évalué à 7 (+5/-0).

      Vu le petit nombre d'élève un tout petit code stochastique ne pourrait-il pas faire l'affaire ?

      • Définir une fonction de coût qui atteint sa valeur min quand toutes les contraintes sont vérifiées ;
      • initialiser la distribution des élèves au hasard ;
      • un très grand nombre de fois ;
        • sélectionner un élève au hasard et le placer dans une classe ;
        • accepter la proposition si elle réduit la fonction de coût, ou si elle vérifie un critère de probabilité (type distribution de Bolzmann) ;
      • Faire baisser progressivement la tolérance du second critère jusqu'à ce que la distribution des élèves ne varie plus.
      • Éventuellement recommencer plusieurs fois pour obtenir plusieurs solutions.

      NB : ce que je viens de décrire est un algorithme de recuit-simulé dit Monte-Carlo Metropolis ; à peu prêt la première idée qui viendrait à tout physicien pour résoudre ce genre de problème, et l'une seulement des très nombreuses méthodes qui devraient vous permettre de résoudre facilement un tel problème, au prix d'un peu de programmation, de la définition d'une fonction de coût appropriée. Si vous avez besoin d'aide, y a qu'à demander…

      « IRAFURORBREVISESTANIMUMREGEQUINISIPARETIMPERAT » — Odes — Horace

      • [^] # Re: Formulation formelle

        Posté par  (site web personnel) . Évalué à 4 (+2/-0). Dernière modification le 21 juin 2025 à 17:20.

        initialiser la distribution des élèves au hasard

        reprendre la classe de l'année précédente telle quelle plutôt :-) puis appliquer les contraintes

      • [^] # Re: Formulation formelle

        Posté par  (site web personnel) . Évalué à 8 (+6/-0).

        Avec la canicule, je n'étais pas motivé pour travailler. J'ai donc écris le code selon vos spécifications. C'est un peu brouillon. Mais ça marche parfaitement. À ceci prêt que la contrainte sur les options n'étant pas explicite, il n'était pas possible de l'appliquer ; mais équilibrer les classes par sexe, répartir les hispanisants, et placer les footeux, là, pas de problèmes, l'algorithme de Metropolis fonctionne comme un charme. Avec 170 élèves, il faut moins de mille itérations pour atteindre une répartition optimale sur 6 classes. Si le code vous intéresse…

        « IRAFURORBREVISESTANIMUMREGEQUINISIPARETIMPERAT » — Odes — Horace

        • [^] # Re: Formulation formelle

          Posté par  . Évalué à 5 (+3/-0).

          Merci. Je veux bien voir à quoi ça ressemble. Reste à savoir si je serai capable de le comprendre et de l’adapter et réutiliser… Ça c’est autre chose ;-)

          • [^] # Re: Formulation formelle

            Posté par  (site web personnel) . Évalué à 9 (+7/-0).

            Le code est en deux parties. Un premier fichier qui me génère une liste d'élèves. Pour vous ça permettra de voir le format des données à produire pour faire tourner le code.

            #!/usr/bin/env python3
            """Ce programme créé une liste (aléatoire) d'élèves qui sera 
            lue par le programme suivant qui optimisera la répartition
            des étudiants en classes.
            INTERET : permet de comprendre comment les données sont
            structurées dans le programme suivant.
            USAGE : Lancer le code suivi du nom du fichier dans lequel les
            données seront écrites. 
            Exemple : python3 createList.py eleves.dat"""
            import sys
            import numpy as np
            nbEleve = 170
            nbLV2Esp = 40
            nbFoot = 15
            def writeEleve(fout,n,sexe,espagnol,foot):
                """Ecrit la liste des élèves dans le descripteur de fichier "fout".
                C'est là qu'il faut faire d'éventuelles modifications pour rajouter 
                des options, etc."""
                fout.write("%7d %4d %7d %5d\n"%(n,sexe,espagnol,foot))
                return n+1
            if __name__ == "__main__":
                try:
                    fout = open(sys.argv[1],"w")
                except:
                    print("Run this code followed by the name of the file where you intend to write")
                    exit()
                fout.write("#Numéro sexe espagnol foot\n") #Commentaire en tête de fichier
                n=0
                nF=0
                nE=0
                """ le fichier est structuré ainsi :
                D'abord les footbaleurs, puis les hispanisant, suivi des autres."""
                while nF < nbFoot :
                           foot = 1
                           espagnol = 0
                           sexe=int(np.random.rand()*2) # donne 0, ou 1 !
                           n=writeEleve(fout,n,sexe,espagnol,foot)
                           nF+=1
                while nE < nbLV2Esp :
                           foot = 0
                           espagnol = 1
                           sexe=int(np.random.rand()*2)
                           n=writeEleve(fout,n,sexe,espagnol,foot)
                           nE+=1               
                while n < nbEleve :
                           foot = 0
                           espagnol = 0
                           sexe=int(np.random.rand()*2)
                           n=writeEleve(fout,n,sexe,espagnol,foot)
                fout.close()

            Voici le code qui applique l'algorithme.

            #!/usr/bin/env python3
            import sys
            import numpy as np
            """ Ce programme consomme une liste d'élèves (en argument) avec leurs options.
            Il les répartis ensuite entre classe en utilisant l'algorithme de 
            Monte-Carlo Metropolis.
            Exemple : python3 metropolis.py eleves.dat
            """
            def readList(fname):
                """ Lis le fichier dont le nom est fname (formaté en colonnes de chiffres)
                et retourne une matrice (de type np.array) dont chaque ligne correspont 
                à un élève et à ses options (0 ou 1 selon que l'option est choisie)."""
                data = np.loadtxt(fname,dtype=int)
                return data
            class classe:
                """Une structure permettant de gérer les classes."""
                def __init__(self,ldata):
                    """ création d'une classe vide,
                    ldata est la liste complète des élèves du niveau de cette classe."""
                    self.nbMembres = 0
                    self.nbFemelles = 0
                    self.nbMales = 0
                    self.nbEspagnoles = 0
                    self.nbFoot = 0
                    self.listMembres = [] # Liste des identifiants des élèves de la classe
                    self.ldata=ldata # Liste de l'ensemble des données sur TOUS les élèves
                def __iadd__(self,ide):
                    """ Ajoute l'élève identifié par son numéro ide à la classe """
                    self.listMembres.append(self.ldata[ide][0])
                    self.nbMembres += 1
                    if self.ldata[ide][1] == 0 :
                        self.nbFemelles += 1
                    else :
                        self.nbMales += 1
                    self.nbEspagnoles += self.ldata[ide][2]
                    self.nbFoot += self.ldata[ide][3]
                    return self
                def __isub__(self,ide):
                    """ Retire l'élève identifier par son numéro à la classe """
                    self.listMembres.remove(self.ldata[ide][0])
                    self.nbMembres -= 1
                    if self.ldata[ide][1] == 0 :
                        self.nbFemelles -= 1
                    else :
                        self.nbMales -= 1
                    self.nbEspagnoles -= self.ldata[ide][2]
                    self.nbFoot -= self.ldata[ide][3]
                    return self
                """ Deux méthode permettant de décrire la classe """
                def __str__(self):
                    s="class nbEleves %d nbFemelles %d nbEspagnoles %d nbFoots %d"%(self.nbMembres,self.nbFemelles,self.nbEspagnoles,self.nbFoot)
                    return s
                def __repr(self):
                    return self.__str__()
            
            def deplaceEleve(nouvelleClasse,ide,listeClasse,ldata):
                """ Fonction qui déplace un élève d'une classe à une autre : 
                nouvelleClasse et le numéro de la nouvelle classe dans
                listeClasse
                ide est le numéro de l'élève dans ldata """
                if ldata[ide][4] != None : # Vérifie que l'élève avait déjà été affecté à une classe auparavant
                    listeClasse[ldata[ide][4]] -= ide
                if nouvelleClasse != None : # Vérifie que l'affectation se fait bien vers une nouvelle classe
                    listeClasse[nouvelleClasse] += ide
                ldata[ide][4] = nouvelleClasse
            
            def cout(listeClasse,ldata,nbEsp):
                """ Fonction de cout
                C'est la fonction essentielle du processus. C'est elle qui conditionne 
                la réussite du processus d'affectation. Elle doit augmenter quand un 
                élève n'est pas affecté conformément aux critère choisis. Elle doit 
                décroître quand les critères sont vérifiés.
                Actuellement 5 critères :
                a : les classes doivent toutes avoir le même nombre d'élèves.
                b : autant d'hispanisant dans chacune des classes qui en ont
                c : ceux qui font du foot doivent impérativement être dans la classe 3
                d : les hispanisants sont dans les classes 5 et 6
                e : tous les élèves doivent se voir affecter une classe
                """
                nbE = len(ldata) # nombre d'élèves
                nbC = len(listeClasse) # nombre de classes
                C = 0
                a = 1
                b=0.5
                c=10
                d=4
                e=50
                for i,classe in enumerate(listeClasse):
                    ### équilibre des classes
                    C += a*(classe.nbMembres-nbE/nbC)**2
                    ### foot en classe 3 (#2)
                    if i ==2 :
                        C -= c*classe.nbFoot
                        #print(i,C)
                    else :
                        C += c*classe.nbFoot
                        #print(i,C)
                    if i > 3 :
                        C -= d*classe.nbEspagnoles
                    else :
                        C += d*classe.nbEspagnoles
                ### équilibre espagnoles
                C += b * (listeClasse[4].nbEspagnoles-listeClasse[5].nbEspagnoles)**2
                ### élève non affecté
                for i in range(nbE):
                    if(ldata[i][4] == None):
                        C+= e
                return C
            
            
            def metropolis(lClasses,ldata,nbEsp,oldC,beta):
                # Choisie un élève au hasard, et une classe au hasard,
                # affecte l'élève dans la classe,
                # calcul la fonction de coût,
                # compare à l'ancienne valeure,
                # choisi de valider l'affectation ou de revenir à l'état précédent
                ide = int(np.random.rand()*len(ldata))
                cl =  int(np.random.rand()*len(lClasses))
                #oldCl = len(lClasses)+1
                #if (ldata[ide][4] != None):
                oldCl = ldata[ide][4]
                deplaceEleve(cl,ide,lclasses,ldata)
                nC =  cout(lClasses,ldata,nbEsp)
                p = np.random.rand()
                if np.exp(beta*(nC-oldC)) < p :
                    return 1,lClasses,ldata,nC
                else :
                    #print("ancien - nouveau",oldC,nC)
                    deplaceEleve(oldCl,ide,lclasses,ldata)
                    return 0,lClasses,ldata,oldC
            def mainMetropolis(lClasses,ldata,nbEsp,oldC) :
                """ Applique l'algorithme de MC Metropolis
                Nloop fois. Plus l'affection est complexe, plus Nloop doit être grand.
                Si tout va bien, à la fin, les élèves sont affectés dans les classes 
                conformément aux critères."""
                C =  cout(lClasses,ldata,nbEsp)
                # Paramètres de l'algorithme
                beta = 1 # conditionne la distribution de Boltzmann
                Nloop = 10000 # Nombre d'itérations à réaliser
                # Le taux d'acceptation des modifications des classes
                # doit avoisinner les 50 %. En fonction de ce taux (moyenné)
                # le paramètre Beta va être modifié pour faire tendre
                # le taux vers 50%
                accept_min=0.4 
                incr = 1.25
                accept_max=0.6
                decr = 0.8
                accept = 0.5
                mix = 0.95 # Paramètre pour calculer la moyenne glissante exponentielle :-)
                # Plus c'est grand, plus la moyenne est calculée sur un grand nombre
                #de configurations précédentes.
                for i in range(Nloop):
                    acc,lClasses,ldata,C = metropolis(lClasses,ldata,nbEsp,C,beta)
                    accept = (1-mix)*acc + mix*accept
                    if accept < accept_min :
                        beta *= incr
                    if accept > accept_max :
                        beta *= decr
                    print(i,accept,C)
                return lClasses,ldata
            if __name__ == "__main__":
                """ Lecture du fichier des élèves """
                try:
                    data = readList(sys.argv[1])
                except:
                    print("Run this code followed by the name of the file where you intend to read students data")
                    exit()
                #print("OK\n ",data)
                ldata = []
                nbEsp = 0
                for e in data :
                    le = list(e)
                    le.append(None)
                    ldata.append(le)
                    nbEsp += e[2]
                #print(ldata)
                ##############
                ### create classes 
                C0 = classe(ldata)
                C1 = classe(ldata)
                C2 = classe(ldata)
                C3 = classe(ldata)
                C4 = classe(ldata)
                C5 = classe(ldata)
                print(C0)
                lclasses=[C0,C1,C2,C3,C4,C5]
                ###############
                ### Affectation manuelle d'élèves dans des classes
                ### Ici j'ai fait n'importe quoi, meilleur est
                ### l'état initial, plus rapide sera le succès final.
                print(lclasses[1])
                deplaceEleve(2,0,lclasses,ldata)
                deplaceEleve(2,1,lclasses,ldata)
                deplaceEleve(2,1,lclasses,ldata)
                deplaceEleve(2,3,lclasses,ldata)
                print(ldata[:5])
                C = cout(lclasses,ldata,nbEsp)
                print(C)
                deplaceEleve(2,2,lclasses,ldata)
                deplaceEleve(2,4,lclasses,ldata)
                deplaceEleve(2,5,lclasses,ldata)
                deplaceEleve(2,6,lclasses,ldata)
                C = cout(lclasses,ldata,nbEsp)
                print(C)   
                deplaceEleve(2,7,lclasses,ldata)
                deplaceEleve(2,8,lclasses,ldata)
                deplaceEleve(2,9,lclasses,ldata)
                deplaceEleve(2,10,lclasses,ldata)
                deplaceEleve(1,16,lclasses,ldata)
                deplaceEleve(1,17,lclasses,ldata)
                deplaceEleve(1,18,lclasses,ldata)
                deplaceEleve(1,19,lclasses,ldata)
                C = cout(lclasses,ldata,nbEsp)
                print(C)  
                #############
                ### OPtimisation
                mainMetropolis(lclasses,ldata,nbEsp,C)
                ### C'est fini
                for classe in lclasses:
                    print(classe)
                    # On peut rajouter une méthode dans "classe"
                    # pour imprimer plus de détails. Par exemple la liste
                    # des élèves de la classe.

            J'ai essayé d'ajouter beaucoup de commentaires pour aider… J'espère que ça sera suffisant car mon code est assez brouillon.

            « IRAFURORBREVISESTANIMUMREGEQUINISIPARETIMPERAT » — Odes — Horace

            • [^] # Re: Formulation formelle

              Posté par  (site web personnel) . Évalué à 2 (+1/-1).

              J'espère que ça sera suffisant car mon code est assez brouillon.

              manque une licence tout de même ;-)

              ça permettra de proposer des contributions et généraliser à d'autres structures de classes / contraintes de remplissage :p

              • [^] # Re: Formulation formelle

                Posté par  (site web personnel) . Évalué à 3 (+1/-0).

                Au temps pour moi : vous avez posté si vite que le bouton "modifier" était gardé par Gandalf.

                Licence AGPL v3 ou ultérieure.
                Bon, en fait mon code n'a rien d'original qui traduise ma personnalité, etc. Donc fondamentalement je trouve un peu étrange d'y appliquer du droit d'auteur. Mais bon.

                « IRAFURORBREVISESTANIMUMREGEQUINISIPARETIMPERAT » — Odes — Horace

            • [^] # Re: Formulation formelle

              Posté par  (site web personnel) . Évalué à 2 (+0/-0).

              PS : plutôt qu'un recuit simulé, mon algorithme fait une trempe ici (un gros bogue dans le recuit). Ça tombe bien : ça donne le résultat optimal plus vite pour un problème simple de ce type. Si jamais le problème se complexifie et qu'il faille la version sans bogue, je l'ai écrite. Il y manque juste de quoi imprimer la configuration optimale atteinte.

              « IRAFURORBREVISESTANIMUMREGEQUINISIPARETIMPERAT » — Odes — Horace

    • [^] # Re: Formulation formelle

      Posté par  . Évalué à 6 (+4/-0). Dernière modification le 21 juin 2025 à 17:19.

      open-source constraints solver ?
      - https://www.minizinc.org/
      - https://choco-solver.org/

      il y a fort longtemps, j'avais expérimenté avec "Turbo-Prolog" ; tu donnais des indications sur un input et un résultat attendu ; ensuite le logiciel se débrouillait pour trouver une solution.

      • [^] # Re: Formulation formelle

        Posté par  (site web personnel) . Évalué à 2 (+0/-0).

        open-source constraints solver ?

        trop générique

        et faut apprendre un nouveau langage, mais oui ça fait le taf' (mais faut apprendre un langage) et ensuite d'aucuns pourraient croire qu'un marteau suffit à enfoncer des vis (z'ont qu'un marteau /o\)

  • # résultats : humains : 1 - IA : 0

    Posté par  . Évalué à 4 (+2/-0). Dernière modification le 27 juin 2025 à 19:13.

    Bon, finalement on a fait ça à la main…

    Dans la pratique, il y a des contraintes qui n'en sont pas vraiment et qui auraient été délicates à implémenter

    [les profs] Cheffe, on a un problème. Si on mets les bilingues seulement dans la 51 et la 52 et que les latinistes ne peuvent pas être en 51, on a forcément 32 élèves en 52 à cause de la section bidule.

    [la cheffe] Pas grave, mettez-en aussi en 51, mais alors ne mettez pas les LV2 allemand en 54 mais seulement en 52, 53 et 55 parce que j'ai prévu d'aligner les cours de Mme X avec ceux de Mme Y pour ce niveau et elles sont 4 à pouvoir prendre les regroupement de LV1 anglais en même temps.

    [moi] : gniii ?

    [l'adjointe] : mais c'est évident, je t'explique

    [moi] : nan nan, c'est bon, on vous fait confiance

    Bon, libreoffice est quand même plus pratique que les fiches T pour filtrer, trier, compter, etc.

    • [^] # Re: résultats : humains : 1 - IA : 0

      Posté par  (site web personnel) . Évalué à 4 (+2/-0). Dernière modification le 27 juin 2025 à 19:57.

      t'en as trop dit ou pas assez :p

      ça vaudrait un journal ;-)

      d'autant que bon sur 170 élèves, c'est gérable

      • tu reportes les classes de l'année précédente => 130 kivonbien
      • tu gères ceux qui ne rentrent pas dans les cases (changement, choix d'affectation) => attribués par défaut => 20 à 40 de plus immédiatement gérés
      • tu traites les cas à la marge => 20 au plus qui restent, 2 min pour chacun, en 2h c'est plié

      et sinon, tu as les affectations proposées par le programme de pmanglade< qui fait le taf' (et a des chances de converger)

      Bon, libreoffice est quand même plus pratique que les fiches T pour filtrer, trier, compter, etc.

      les « fiches T » ?!

      PS : stait pas mercredi pour le faire ?

      • [^] # Re: résultats : humains : 1 - IA : 0

        Posté par  . Évalué à 3 (+1/-0). Dernière modification le 27 juin 2025 à 21:48.

        tu reportes les classes de l'année précédente => 130 kivonbien

        Choix politique et pas algorithmique : brasser autant que possible les élèves d'une année à l'autre. Ce qui n'est pas possible dans certains cas : les sections sportives ne peuvent pas être répartis sur deux classes différentes parce que cela augmente le nombre d'alignements de classe et les trous dans les emplois du temps. Par exemple, on met les footeux dans une seule classe. Les horaires de section sont placés sur la fin de matinée et une partie de la pause de midi. Les non-footeux sont libérés la dernière heure pour passer à la cantine mais il ne serait pas forcément possible de mettre des élèves avec une autre options dans la même classe si l'effectif ne colle pas. On y est arrivé avec la section basket et l'atelier chant choral, mais pas plus.

        Ensuite je ne suis même pas sûr que l'on arrive à 130 « stabilités » : à chaque passage de classe correspond des nouveautés. En 5e la LV2 est obligatoire, même si on en a déjà beaucoup en 6e. En 5e toujours le latin (pardon, langues et culture de l'antiquité) débute. etc.

        en 2h c'est plié

        C'est à peu près le temps que l'on a mis. Y compris le temps de comprendre que les LV1 allemand avaient juste été oubliés dans les contraintes ;-)

        et sinon, tu as les affectations proposées par le programme de pmanglade< qui fait le taf' (et a des chances de converger)

        J'ai récupéré les données des futurs 6e, on fait ça lundi (et je préfère encore aux autres « ateliers » prévus) faut que je vois ce que je peux en faire. Mais je n'ai pas les contraintes pour ceux-là :-(
        Je ferai, si j'en ai encore le courage, des tests (il me faudra votre aide) après coup.

        les « fiches T » ?!

        C'est ça : Titre de l'image

        et ça s'utilise avec ça : Titre de l'image

        Autrefois utilisé aussi pour les emplois du temps !

        PS : stait pas mercredi pour le faire ?

        si si mais brevet, surveillance, secrétariat, réunions, conseils de classe tardifs… pas eu l'occasion de faire un retour avant

        • [^] # Re: résultats : humains : 1 - IA : 0

          Posté par  (site web personnel) . Évalué à 4 (+2/-0).

          les « fiches T » ?!

          C'est ça :

          ça fait depuis le millénaire dernier que je n'en ai pas vu (ça ne me manque pas, j'ai eu le bac !) ; bienvenue au siècle dernier !)

          au moins c'est de la technologie éprouvée :D moi qui me demandais avec mon pov' diplôme d'ingénieur du siècle dernier ce que je pourrais apporter à des enseignants du XXIè ! la pointe de la techno !

          brasser autant que possible les élèves d'une année à l'autre

          ça c'est une erreur : les potes se soutiennent, les amitiés perdurent et se renforcent d'une année à l'autre
          t'façon les profs sont des cons :p ce qui est foncièrement faux : moui le prof' principal spa gagné, mais maths et français en seconde jusque terminale c'est déterminant, physique un peu moins, biolo ça dépend de l'option (pour agro faut savoir dessiner)

        • [^] # Re: résultats : humains : 1 - IA : 0

          Posté par  (site web personnel) . Évalué à 3 (+1/-0).

          PS : stait pas mercredi pour le faire ?

          si si mais brevet, surveillance, secrétariat, réunions, conseils de classe tardifs… pas eu l'occasion de faire un retour avant
          .
          et après on vous traite de feignasse /o\

Envoyer un commentaire

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.