Dans les précédents posts sur les bitboards, tt et zobrist, le solveur a avancé très rapidement, avec des calculs qui prenaient des heures qui ne prennent plus que quelques secondes. Mais pour faire tourner ce moteur sur des cas réels il faut des données, ce qui oblige à se confronter à ADE. Jusqu'ici, le faire manuellement était un véritable enfer:

  • Me connecter au portail ADE, accéder au projet de cette année;
  • Parcourir l'arborescence de toute l'unica, pour retrouver les PeiP;
  • Télécharger chaque ics de chaque ressource;
  • Renommer, nettoyer et lancer le solveur via dotnet et les arguments à la main;

Passer une demie heure à chaque changement d'edt à cliquer sur une interface essoufflée pour lancer un calcul de 3 secondes n'a plus aucun sens, il était temps d'automatiser toute la plomberie en branchant le premier tuyau directement chez ADE.

Accéder aux ressources d'ade

*ADE a fait des changements en aout, qui m'ont forcé à réécrire le parseur. les informations de cette section ont donc étés mises à jour.
ADE n'a pas de belle api rest moderne avec des endpoints json parfaitement documentés. C'est une application, qui reste à mon sens extrêmement opaque et qui repose sur des sessiosn jsessionid, des formulaires xml et des identifiants privés.
Pour récupérer les cours d'une ressource (groupe, enseignant, salle), il faut utiliser une URL - dont je n'ai pas trouvé la documentation - d'export direct vers un service anonyme :

https://ade.univ-cotedazur.fr/jsp/custom/modules/plannings/anonymous_cal.jsp?calType=ical&projectId=[]&resources=[]

Il faut donc déduire l'identifiant du projet, on a 5 pour l'année 2025/26 et 6 pour l'année 2026/27, ainsi que l'identifiant de ressource. Pour savoir quel identifiant correspond à quel groupe réel, enseignant ou salle, j'ai décidé d'écrire un client (tree_parser.py) qui navigue et aspire l'arborescence complète du projet. C'est une solution que je trouve personnellement sale et je sauterai probablement sur une alternative, mais depuis la màj d'aout certaines données (dont celles qui me permettaient d'accéder aux identifiants des ressources) ne sont plus accessibles.

graph LR
        ADE["Serveur ADE Campus<br>"] -->|Scraping IDs| Parser["Tree Parser<br><i>(Mapping IDs)</i>"]
        Parser -->|Export direct| ICS["Flux ICS bruts<br><i>(iCalendar)</i>"]
        ICS -->|Regex & Nettoyage| DB[("Base SQLite Locale<br><b>Tampon</b>")]
        DB --> Engine["willowengine<br><i></i>"]

        style ADE fill:#111,stroke:black,color:white
        style Parser fill:white,stroke:black,color:black
        style ICS fill:white,stroke:black,color:black
        style DB fill:#111,stroke:black,color:white
        style Engine fill:black,stroke:black,stroke-width:2px,color:#fff

Nettoyer les ics

une fois les .ics de chaque ressource pertinente récupérés, on fait face à la réalité du terrain : ce sont des ics faits pour faire de edt, pas des json prêts à se faire traiter par un solveur. Le résultat, c'est que chaque évènement (cours) est sous la forme suivante :

BEGIN:VEVENT
UID:ADE-102521@edtweb.univ-cotedazur.fr
DTSTART:20260925T120000Z
DTEND:20260925T140000Z
SUMMARY:TP - Algorithmique G02
LOCATION:O+102 Lucioles
DESCRIPTION:INFO4 - Département Informatique\nPolytech Nice Sophia - Emplois du temps\nINFO4-ALGO-TP-G02\nUE 4.1 Algorithmique et Complexité\nDUPONT Jean\nINFO4 Groupe 2\n(Exporté le: 25/06/2026 14:32)
END:VEVENT

Une version rêvée aurait été, à mon avis, un joli json comme :

{
    "id": "evt_ade_102521",
    "title": "Algorithmique et Complexité",
    "type": "TP",
    "status": "confirmed",
    "schedule": {
    "start": "2026-09-25T14:00:00+02:00",
    "end": "2026-09-25T16:00:00+02:00",
    "duration_minutes": 120
    },
    "course": {
    "code": "INFO4-ALGO",
    "module": "UE 4.1 - Informatique Fondamentale"
    },
    "groups": [
    {
        "id": "grp_info4_g2",
        "name": "INFO4 - Groupe 2",
        "headcount": 26
    }
    ],
    "teachers": [
    {
        "id": "tch_jdupont",
        "name": "Jean Dupont",
        "email": "jean.dupont@univ-cotedazur.fr"
    }
    ],
    "rooms": [
    {
        "id": "room_luc_o102",
        "name": "O+102",
        "building": "Lucioles",
        "capacity": 32,
        "type": "computer_lab"
    }
    ],
    "optimizer_metadata": {
    "is_locked": false,
    "allowed_slots": ["morning", "afternoon"],
    "requires_computers": true
    }
}

Enfin bon, l'API ne nous donne accès qu'aux ics, on ne pouvait pas s'attendre à y trouver de jolis json.
Là ne finit pas le problème. En pratique et sur une année entière, les cas particuliers explosent tout simplement. Le format des noms des enseignants change parfois (nom complet/initiales, accents corrompus), les responsables et secrétaires pédagogiques ont aussi plusieurs champs pour indiquer notamment les enseignants ou les SHN, en créant les planings, qu'ils indiquent minutieusement dans les bonnes cases, et qui se retrouvent sans raison tous dans DESCRIPTION sans plus d'indication. En résulte l'impossibilité pour moi de déterminer qui est un étudiant d'un shn d'un intervenant, et le système nettoyé compte encore aujourd'hui près de 1900 enseignants à polytech uniquement, ce qui ne fait pas sens.
J'ai donc passé (perdu) beaucoup de temps sur un script de normalisation qui me paraissait simple à faire, équipé d'une suite de regex et de tables de correspondance. Je n'ai pas décris tous les problèmes rencontrés, comme le fait que chaque promotion semble avoir une structure de ressources différentes (ressources séparées pour CM+TP+TD+DS pour PeiP2, correctement rangées pour les PeiP1) ce qui oblige à adapter le parseur pour chaque type. Chaque événement est découpé, nettoyé et typé pour être injecté proprement dans le prétraitement des structures binaires du moteur. C'est un travail que j'espère ne plus jamais avoir à fairemoi en aout, passer des jours à nettoyer des données salies tout en sachant qu'il existe une version propre prête à l'emploie mais inaccessible est super frustrant.

tapon

ADE est tristement connu pour mourir de temps à autre, je dirais donc qu'un avantage déterminant de ce pipeline, c'est la résilience. Je stocke donc l'ensemble des plannings décodés dans une base SQLite locale et compacte, disponible autant pour les calculs que pour les étudiants. À ceux qui pourraient être, pour certaines raisons, dérangés par cette pratique : ce ne sera plus le cas quand ce ne sera plus nécessaire. Encore faudrait-il que ce ne soit, un jour, plus nécessaire. Conséquences :

L'emploi du temps reste consultable pour tous, même sans ADE;

Dès qu'ADE est de retour, la db est remise à jour;

Les temps de réponse n'en sont pas affectés;

signer les semaines

Calculer vite c'est super, mais ne pas calculer pour rien c'est encore mieux. Pour ça, chaque calcul sauvegardé est accompagné de la signature de la semaine sur laquelle il vaut. De cette façon, si le planning change entre la date du calcul et aujourd'hui, on le saura.
Lorsque quelqu'un consulte un calcul dans Willow Optimiseur, on vérifie que la signature de la semaine actuelle à jour telle que décrite dans Willow EDT correspond bien à celle contenue avec le calcul. Autrement, on ne retire pas l'accès au résultat tant qu'il n'a pas été màj, tout en prévenant qu'il n'est plus d'actualité.

Automatiser le pipeline

On a donc créé toutes les briques nécessaires pour automatiser entierement le pipeline, j'ai donc assemblé tous les appels dans un simple script intéractif (pipeline.py) avec une jolie TUI.

Récapitulatif pipeline.py
Récapitulatif pipeline.py

On demande donc tous les paramètres nécessaires aux scripts appelés.
On peut décider de rafraichir les ressources, des parametres de willowengine, si l'on veut garder les résultat localement ou les upload sur le vps....

Calcul pipeline.py
Calcul pipeline.py

Voilà la phase de calcul. Chaque carré représente un événement de l'année, noir signifie pas encore calculé ou pas de bonne solution trouvée, un événement plus clair signifie une réduction de pénalité plus importante.

=)
=)

Ce système fonctionne bien! Il permet de tout gérer comme un client sans enfiler la casquette de développeur, je l'espère durable.

la suite

Ces scripts me font gagner un temps absolument énorme que je pourrais mieux utiliser. En ce qui concerne les groupes disponibles dans willow, il n'y a que les 9 groupes de PeiP. Pour que les étudiants qui utilisent quotidiennement Willow puisse garder leurs habitudes les années suivantes, je devrais ajouter les groupes de 3, 4 et 5a de pns. J'ai aussi discuté avec des amis de Valrose et d'autres écoles de l'unica, qui rencontrent des problèmes similaires liés à ADE. Il est hors de question que je recommence le travail décrit plus tot sur plusieurs formations ou plusieurs écoles, je tente donc d'automatiser l'opération via un nouveau projet interne de la suite, Willow Studio.

Je crois donc avoir réussi ces deux dernières semaines à suffisamment me familiariser avec ADE pour automatiser la gestion de Willow! :)

//pekmi


Changelog
  • new Global : traitement ADE (arborescence, mapping des id)
  • new Global : normalisation des ICS (découpage regex, gestion des cas limites rencontrés)
  • new EDT : tampon SQLite local toujours disponible
  • perf Optimiseur : signatures de semaines (changements d'edt, invalidation auto des calculs obsolètes)
  • new Global : pipeline complète intéractif
  • wip Studio : premier brouillon