Dans Bordure, vous êtes le directeur sportif, pas un coureur. Vous préparez la saison, écrivez le plan de course, puis vous regardez depuis la voiture, radio en main. Cela impose une exigence au moteur : il doit mener une course à son terme, de façon crédible, sans que personne ne lui dise quoi faire après le départ, avec jusqu’à 176 partants, des équipes qui jouent toutes selon les mêmes règles et aucun vainqueur décidé à l’avance.
Ce billet suit une course dans l’ordre où le moteur la fabrique : le tick, la physique, les réserves d’énergie, les groupes, les décisions, la perception, la radio, la malchance, puis ce qui rend le tout rejouable et mesurable. Il ne parle ni de carrière, ni de contrats, ni d’entraînement : seulement de ce qui se passe entre le départ et l’arrivée. Tout vit dans un paquet TypeScript sans Node, sans Electron et sans React, qui ne lit ni l’horloge ni Math.random.
Sept règles avant la première ligne
Le moteur ne vient pas d’une liste de fonctionnalités mais de sept piliers, posés avant le code et vérifiés par des tests. Chacun a une conséquence technique précise, et c’est pourquoi le reste de ce billet se lit comme leur mise en œuvre.
Des intentions, pas des commandes
Vous émettez un plan et des consignes radio. Jamais une puissance, une trajectoire ou le déclenchement exact d’une attaque.
Voir le plan et l’IA →Une course se finit seule
Sans aucune intervention après le départ, la course se termine intelligemment avec le seul plan du staff.
Voir le plan par défaut →Les mêmes règles pour tous
Les équipes adverses jouent les mêmes plans, avec les mêmes règles et la même perception que vous. Aucun vainqueur scripté.
Voir la fonction de décision →Information imparfaite
L’interface ne reçoit que des projections filtrées, avec leur source et leur âge. Jamais l’état interne du moteur.
Voir la perception →Une radio avec délai
Une consigne part avec un délai, reçoit un accusé, se suit par destinataire. Répéter un ordre ne donne aucun bonus.
Voir la radio →La présentation ne touche pas la simulation
Le texte, la vitesse de lecture et les pauses n’ont aucune influence sur la course. Découper la lecture autrement ne change ni la course, ni le fil, ni les arrêts.
Voir le rejeu →Le déterminisme
Même graine, même contenu, mêmes commandes aux mêmes ticks : même résultat, sur n’importe quel moteur JavaScript.
Voir le déterminisme →Un tick, sept phases
Le moteur avance par pas de 5 secondes simulées (TICK_S). L’inertie est négligée à cette granularité : le modèle est quasi statique, et la vitesse d’un groupe se calcule à partir de la puissance de chacun, sans intégrer d’accélération.
Le moteur mécanique se contente d’appliquer des allures. Ceux qui les choisissent, l’IA et la radio, sont séparés de lui par une interface (PacingDecisions). Sans politique, tout le monde roule à une allure « tempo » par défaut, ce qui permet de tester la mécanique sans les décisions.
Autour du moteur, la session
Dans le moteur
Depuis la météo (T08), le moteur glisse entre le regroupement et les décisions la fin des retours derrière les voitures, les incidents et le placement dans les bordures.
Deux détails comptent plus qu’il n’y paraît. D’abord, les décisions de toutes les équipes sont lues sur l’état au début du tick : personne ne réagit à ce qu’un autre vient de décider dans le même pas, donc l’ordre de traitement des équipes ne compte pas. Ensuite, l’arrivée est interpolée à l’intérieur du tick : l’instant de passage n’est pas arrondi au pas de 5 secondes, ce qui laisse un sprint se jouer sur des fractions de seconde.
La physique tient en une équation
Pour un coureur qui pousse une puissance donnée, la vitesse est celle où la puissance fournie égale les forces qui s’opposent : la pesanteur, le roulement et l’air.
Le moteur doit trouver v sachant P : la fonction speedForPower inverse la relation par bissection, à chaque tick et pour chaque coureur. C’est pourquoi le sinus et le cosinus de l’angle de la pente ne passent pas par la trigonométrie : pour une pente g/100, sin(atan g) = g/√(1 + g²) et cos(atan g) = 1/√(1 + g²), identiques mathématiquement et bien plus rapides.
Le revêtement entre par le coefficient de roulement : 0,004 sur l’asphalte, 0,0075 à 0,0315 sur les pavés selon les étoiles du secteur et l’attribut cobbles du coureur. En descente, la vitesse est plafonnée par la technicité de la route et l’aisance du coureur. Quant à l’abri, c’est le facteur qui fait toute la tactique du vélo : 1 seul, moins de 1 dans un groupe (section 04).
| Cas | Entrée | Attendu |
|---|---|---|
| Plat, seul | 70 kg · 250 W | ≈ 10,3 m/s (37 km/h) |
| Côte à 8 % | 60 kg · 360 W | ≈ 5,7 m/s (20,5 km/h, VAM ≈ 1 630 m/h) |
| Descente à −6 % | 70 kg · roue libre · technicité 0 | ≈ 14,7 m/s (53 km/h) |
Les jambes : une puissance, deux réservoirs
Chaque coureur porte quinze attributs entiers, de flat à composure. La conversion en paramètres physiques appartient au moteur, pas au contenu : le contenu décrit un coureur, la mécanique en tire ce qu’il peut tenir. L’attribut du terrain fixe sa puissance critique (CP) ; ses réserves se vident et se reconstituent tick après tick.
| Grandeur | Ce qu’elle représente | Comment elle évolue |
|---|---|---|
| Puissance critique | Ce que le coureur tient sans s’épuiser. cpWkg = 4,4 + 2,2 · a/100, a étant l’attribut du terrain, fondu entre flat, hill et mountain selon la pente. | Multipliée par la forme et par la forme du jour. Réduite par la durabilité, la fringale et, au-dessus de 1 500 m, l’altitude. |
| W′ (réserve anaérobie) | De 12 à 30 kJ à 70 kg, selon acceleration, hill et sprint. C’est le carburant des attaques. | Au-dessus de CP : W′bal −= (P − CP) · dt. En dessous, reconstitution selon Skiba, plus lente quand on roule près de CP : τ de 316 à 862 s pour un coureur moyen. |
| Glycogène | (7 000 + 30 · endurance) · m/70 kJ. Dépense métabolique P · dt / 0,23, dont une part glucidique qui monte avec l’intensité. | Ravitaillement à 1 500 kJ/h, sauf dans les 20 derniers km. |
| Durabilité | La fatigue accumulée. Après 1 500 kJ de travail, CP perd une fraction par 1 000 kJ supplémentaires. | Fraction 0,035 − 0,025 · resistance/100, perte plafonnée à 15 %. |
| Fringale | Le mur. Sous 25 % du glycogène de départ, CP baisse. | Linéairement jusqu’à 0,75 + 0,15 · resistance/100 de CP quand le glycogène tombe à zéro. |
| Forme du jour | Un « jour avec » ou un « jour sans », caché : aucune équipe ne le connaît. | Facteur exp(0,035 · z), z tiré dans une loi normale bornée à ±2,5. |
La forme du jour est discrète mais indispensable : sans elle, les résultats suivaient presque exactement la hiérarchie des attributs, et la course n’avait plus de raison d’être courue. Son écart type de 3,5 % dépasse un peu la variabilité mesurée d’un jour à l’autre : il absorbe aussi ce que le modèle ne représente pas (placement, motivation, petits ennuis).
Dans la première version, W′ et le glycogène étaient en joules absolus. Un grimpeur de 53 kg avait donc autant de réserves qu’un rouleur de 75 kg, soit 30 % de plus par kilo : il gagnait presque toutes les courses en montée, tandis que les sprinteurs lourds tombaient en fringale. Au premier passage du banc de calibration, un coureur de 57 kg gagnait 36 à 38 % des courses vallonnées et de montagne. Depuis, les réserves sont rapportées à la masse.
Les groupes : l’abri fait la course
Un peloton n’est pas une liste de coureurs, c’est un objet physique. Deux coureurs consécutifs à 20 m ou moins forment un groupe ; le peloton est le plus grand de tous. Les écarts ne sont pas posés à la main : l’écart en temps entre deux groupes est la distance qui les sépare divisée par la vitesse du groupe de derrière. Ils naissent de la physique.
Les chiffres sont inventés pour le schéma. Dans le moteur, chaque groupe a un identifiant stable (celui du coureur le plus avancé au moment de sa formation) et chaque écart est recalculé à chaque tick.
L’abri multiplie la traînée : à 1 on subit tout l’air, à 0,5 on n’en subit que la moitié. Il dépend de la place dans le groupe.
| Situation | Facteur | Remarque |
|---|---|---|
| Seul, ou en tête | 1 | Aucun abri. |
| File de relais, 2 à 5 coureurs | 0,75 | Facteur de la file, pour celui qui n’est pas en tête. |
| File de relais, 6 à 19 coureurs | 0,68 | |
| File de relais, 20 coureurs ou plus | 0,62 | |
| Dans les roues d’un groupe de 20 ou plus | 0,5 | Le coureur est enveloppé par le peloton. |
Un relayeur passe 1/n du temps en tête, n étant le nombre de relayeurs. Le facteur moyen est (1 + (n − 1) · abri de file) / n. Exemple calculé avec la formule : quatre relayeurs dans un groupe de 20 ou plus, (1 + 3 × 0,62) / 4 = 0,715.
Ensuite, les règles s’enchaînent. Les relayeurs désignés visent une intensité, fraction de leur CP effective, qui est une puissance moyenne sur la rotation : un groupe qui s’entend va donc plus vite qu’un coureur seul à la même intensité. Chaque membre calcule la puissance qu’il lui faut pour tenir cette vitesse avec son abri ; tant qu’elle est dans ses moyens il suit et puise dans W′ au-dessus de CP. Quand W′ est vide, il décroche, roule à sa CP et l’écart se creuse tout seul. Pour éviter les va-et-vient, un lâché ne peut plus forcer pour revenir tant que W′ n’est pas remonté à 25 %.
Un groupe où personne ne veut rouler ne profite pas d’une rotation que personne n’a décidée : sa vitesse est la moyenne de celles que chaque membre tiendrait seul en tête à 60 % de sa CP effective, ce qui donne un peloton à 36 ou 38 km/h sur le plat. Une attaque est un coup planifié à part du reste du groupe : les attaquants visent leur intensité, bornée par la puissance dont ils disposent sur le tick, et le reste du groupe est recalculé sans eux. Un sprint, enfin, est un effort à puissance maximale qui s’éteint quand W′ est vide.
« Sans cette règle, un grimpeur et un sprinteur relayant ensemble montaient à l’allure moyenne des deux, et personne n’était lâché. »
À propos de l’allure en montée (T10)Cette règle est la raison pour laquelle la montée ne se règle pas comme le plat : à partir de 2 % de pente, l’allure d’un groupe glisse de la moyenne de ses relayeurs vers la plus haute de leurs vitesses, qu’elle atteint à 5 %. Là, l’abri ne vaut presque plus rien et c’est le plus fort qui impose son rythme.
Une seule IA pour toutes les équipes
Il n’y a pas une intelligence pour les adversaires et une autre pour vous. Il y a decideTeam : une fonction qui reçoit la vue de l’équipe, les connaissances publiques, son plan et sa mémoire, et rend les décisions de chaque coureur. L’équipe du joueur passe par elle, avec le plan que le joueur a écrit. Les équipes adverses aussi, avec le plan que leur staff a dérivé de la réputation publique des coureurs.
Cette symétrie est testée. Des effectifs identiques sous des identifiants d’équipe différents reçoivent les mêmes rôles, et les décisions d’une équipe ne changent pas quand on modifie les réserves d’un adversaire.
Le plan est la seule porte d’entrée tactique
| Champ | Valeurs | Sens |
|---|---|---|
| doctrine | finale · sprint · offensive | Préserver pour le final, contrôler pour un sprint, courir à l’offensive. |
| riders | chaque partant, avec un rôle | Leader, alternative, protection, rouleur de poursuite, coureur libre, lanceur, équipier. L’ordre des alternatives est l’ordre de relève. |
| fallback | switch · wait · release | Si le leader décroche : basculer sur l’alternative, l’attendre, ou libérer les coureurs. |
| maxChasers | entier de 1 à 4 | Équipiers engagés au maximum dans une poursuite. |
| attackZones | plages de distance | Zones propices aux attaques du leader et des alternatives. |
Le moteur valide le plan et ne produit que des codes ; les libellés viennent du texte narratif. Un plan sans leader est permis : l’équipe ne poursuit alors pour personne.
Le plan par défaut du staff est celui de chaque équipe adverse et le brouillon proposé au joueur. Il ne lit que la réputation publique et la lecture du parcours : doctrine offensive pour une équipe qui ne prétend pas à la victoire, sinon sprint sur une course plate et finale ailleurs ; zones d’attaque posées sur les montées de la finale, et sur les secteurs pavés les plus durs d’une classique.
Cette lecture du parcours est elle aussi du code. Le moteur classe une course en flat, hilly, mountain, cobbles ou gravel ; il repère les montées, leurs difficultés et, depuis peu, les murs (200 m à 6 % ou plus) ; et il détermine la finale, qui démarre 30 km avant l’arrivée (plus tôt sur les classiques pavées et le gravier), avancée au pied de la montée ou du secteur qu’elle chevauche.
Qui roule : cinq règles collectives
Chaque tick, l’IA évalue pour chaque équipe et chaque groupe qui doit rouler et à quelle intensité. Cinq règles se partagent la tâche : l’échappée et les groupes de tête, la poursuite contrôlée, la défense en finale, le tempo en côte et le train du sprint. La plus parlante est la poursuite, où l’équipe d’un leader piégé derrière vise un écart cible qui rétrécit à mesure que l’arrivée approche : G*(D) = min(240 s, max(0, (D − Dcatch) · 4 s/km)). Les 4 secondes par kilomètre sont ce qu’une poursuite organisée peut réellement reprendre avec les abris de la section 04. L’écart réel à cette cible choisit alors le niveau d’effort :
| Niveau | Condition | Équipe menante | Autres équipes intéressées |
|---|---|---|---|
| 0 · laisser filer | e < −30 s | 1 relayeur à 0,65 | — |
| 1 | −30 ≤ e < 0 s | 2 relayeurs à 0,78 | — |
| 2 | 0 ≤ e < 30 s | 3 relayeurs à 0,85 | 1 relayeur à 0,85 |
| 3 | e ≥ 30 s, ou coup dangereux | 4 relayeurs à 0,93 | 2 relayeurs à 0,93 |
Les intensités sont des fractions de la puissance critique effective du relayeur. Un « coup dangereux » est un groupe de tête qui contient un favori, ou plus de six coureurs.
Ce que décide chaque coureur
Au-dessus de ces règles collectives, chaque coureur a sa propre liste de priorités, évaluée dans cet ordre :
- Sprint lancé : il continue jusqu’à la ligne.
- Lancer le sprint, sauf s’il travaille pour un leader présent dans son groupe. La distance de lancement dépend de ce que son W′ lui permet de tenir, et le coureur tacticien se trompe moins.
- Attaque engagée : elle continue 120 secondes au plus, tant que W′ ≥ 35 % et qu’elle n’est ni neutralisée ni dégagée.
- Nouvelle attaque : un tirage, selon le cas (voir ci-dessous).
- Consigne collective : relayer à l’intensité demandée.
- Rentrer : dans un groupe derrière le peloton, à 0,72.
- Sinon, suivre.
Une attaque n’est jamais déclenchée par un script : c’est un taux par minute converti en probabilité par tick, p = 1 − e^(−λ·Δt/60), tiré dans le flux aléatoire propre au coureur, et seulement quand ses conditions sont remplies. Un coureur d’agressivité 0,8, leader dans une zone d’attaque de son plan avec assez de W′ et un timing de 1, a un taux de 0,5 · (0,5 + 0,8) = 0,65 par minute, soit environ 5 % de chances par tick de lancer l’attaque. Elle démarrera à 130 % de sa puissance critique, bornée par ce qu’il peut produire.
| Cas | Qui, quand | W′ min | Taux (par minute) | Intensité |
|---|---|---|---|---|
| Échappée | Coureur libre dans le peloton, porte de l’échappée ouverte, moins de 5 coureurs devant. | 80 % | 0,2 · (0,5 + aggr) | 1,25 |
| Zone | Leader ou alternative, dans une zone d’attaque du plan. | 70 % | 0,5 · (0,5 + aggr) · t | 1,30 |
| Finale d’échappée | Groupe de tête devant de 2 à 12 coureurs, à 20 km ou moins. | 80 % | 0,4 · (0,5 + aggr) | 1,20 |
| Contre en finale | Coureur libre, ou équipier d’une équipe offensive, entre 3 et 20 km. | 80 % | 0,02 · aggr | 1,20 |
| Marquage | Leader ou alternative quand un adversaire menaçant attaque, en finale. | 40 % | p = 0,3 + 0,5 · composure, par tick | 1,30 |
Le timing t vaut 2 dans la dernière zone du plan ; ailleurs 0,4 pour un coureur tacticien (il attend), 1 sinon.
Ce que chaque équipe voit de la course
Le moteur sait tout. Les équipes, non. Entre l’état exact et la politique qui décide, il y a une couche de perception, identique pour tous. Chaque équipe connaît la course par deux sources.
Ce que l’équipe voit
Les groupes qui contiennent un de ses coureurs, et ceux dont l’espace avec l’un de ces groupes est d’au plus 250 m. Pour ceux-là, tout est exact au tick courant : composition, vitesse, qui attaque. Les coureurs d’une équipe partagent ce qu’ils voient par l’oreillette, sans délai.
Le pointage public
Un pointage par minute (tous les 12 ticks), identique pour toutes les équipes. Il annonce les groupes dans l’ordre réel avec un écart bruité : round(g + N(0, 2 + 0,03 · g)) secondes, forcé croissant d’un groupe au suivant.
| Écart réel g | Écart type | Lecture |
|---|---|---|
| 30 s | 2,9 s | L’annonce est quasi exacte. |
| 120 s | 5,6 s | Quelques secondes d’erreur. |
| 300 s | 11 s | Une dizaine de secondes d’incertitude sur cinq minutes. |
Valeurs calculées avec la formule ci-dessus. Un groupe connu seulement par le pointage est ensuite placé à sa position annoncée plus sa vitesse multipliée par l’âge de l’information.
Un groupe connu seulement par le pointage est donc estimé : on projette sa position avec le temps écoulé. Un coureur que le pointage plaçait dans un groupe aujourd’hui vu, qui n’y est plus et qu’on ne voit nulle part, a un groupe inconnu jusqu’au pointage suivant. Les arrivées et les abandons, eux, sont publics.
Et vous, directeur ? Vous recevez une projection encore plus pauvre : des groupes avec leur source et leur âge, et pour vos coureurs, des sensations en mots rapportées toutes les trois minutes, décalées d’un coureur à l’autre. Jamais une réserve, une puissance ou une vitesse, et un test vérifie que ces champs n’existent pas dans la projection.
| Mot | Quand le moteur le choisit |
|---|---|
good | W′ ≥ 90 % et glycogène ≥ 60 %. |
ok | Tout le reste. |
hard | W′ < 50 % ou glycogène < 35 %. |
empty | Glycogène < 20 %, ou coureur lâché. |
Les coureurs, eux, connaissent leurs jambes exactes : la politique lit leurs réserves réelles. C’est vous qui n’en recevez que des mots.
La perception parfaite (perfect: true) donne à chaque équipe la vue exacte. Ce n’est pas un mode de jeu : c’est une référence. Avec elle, la course du ticket précédent est reproduite à l’octet près, ce qui prouve que la couche de perception ne change rien tant qu’on ne la déforme pas. Mesurée ensuite, elle ne dérèglait pas la calibration : 44,1 km/h de moyenne sur la classique plate dans les deux cas.
La radio : dire n’est pas faire
Vos seules actions en course sont des consignes radio. Une consigne comprend des destinataires, une intention (aider la poursuite, se préserver, protéger le leader, attaquer dans une zone, surveiller un adversaire, changer de leader ou de doctrine, reprendre le plan) et une condition de fin (jusqu’à nouvel ordre, jusqu’à un point, jusqu’à un écart). Seules les erreurs structurelles la refusent : une tactique discutable est acceptée, puis éventuellement rapportée comme impossible.
Au pire, dans un gros peloton, l’ordre atteint le coureur 20 s après l’envoi, et vous ne le savez que 10 s plus tard.
À la réception, trois choses peuvent se passer. Si une consigne plus récente du même emplacement est déjà arrivée, celle-ci arrive trop tard et est écartée. Si c’est un sacrifice (poursuivre, protéger, se préserver) adressé à un leader, à une alternative ou à un coureur libre, le coureur peut la refuser, selon son caractère. Sinon, elle remplace la précédente sur le même emplacement seulement : surveiller un adversaire tout en se préservant reste possible, parce que ce sont deux emplacements distincts.
La probabilité de refus vaut clamp((ambition − (loyauté + esprit d’équipe)/2) / 100, 0, 0,5). Avec une personnalité moyenne (50, 50, 50), elle vaut 0. Pour un coureur d’ambition 80, de loyauté 30 et d’esprit d’équipe 40, le calcul donne (80 − 35) / 100 = 0,45. Un équipier, lui, ne refuse jamais.
Enfin, répéter un ordre ne donne aucun bonus. Un destinataire qui a déjà la même consigne en transit ou en vigueur est retiré de l’envoi ; si plus personne ne reste, la consigne est refusée comme doublon. Répéter ne relance aucun délai.
| État | Sens |
|---|---|
pending | Envoyée, pas encore reçue, ou reçue sans que la voiture le sache. |
received | Consigne d’équipe reçue, en attente du reste de l’équipe. |
active | Reçue et en cours d’exécution. |
impossible | Reçue mais inexécutable pour l’instant, avec le motif ; redevient active si la situation change. |
done | Condition de fin atteinte, ou coureur arrivé ou abandonné. |
superseded | Remplacée par une consigne plus récente du même emplacement. |
refused | Refusée par le coureur, à cause de son caractère. |
cancelled | Annulée à votre demande, par le même chemin radio, donc avec le même délai. |
cancelRequested | Côté directeur seulement : annulation demandée, issue pas encore rapportée. |
Une annulation n’est pas un retour en arrière : l’ancienne consigne peut encore être reçue ou exécutée pendant que l’annulation voyage.
Vent, pluie, crevaisons
La météo du jour est une donnée de la course, pas un tirage du moteur : vent (vitesse et direction), pluie ou non, constante toute la course et publique. Le vent de face entre dans le terme aérodynamique de la section 02. Le vent de côté ne change pas la physique : il fabrique des bordures.
Quand le vent de côté dépasse 3 m/s, une bordure se forme. Sa force vaut s = clamp((vent de côté − 3) / (7 − 3), 0, 1). Dans un groupe de plus de 12 coureurs, c’est la largeur de la route : les 12 premiers gardent leur abri, les suivants roulent « dans le caniveau », presque à découvert, dépensent davantage et finissent par décrocher. Le groupe se casse. L’ordre dans la bordure revient d’abord aux relayeurs, puis au score placement + bonus d’équipe + un peu de chance. L’IA le sait : une équipe prétendante fait relayer deux coureurs à 0,9 pour glisser son leader dans la bonne bordure.
« Hors top 40 » : le vainqueur n’est pas parmi les 40 meilleures aptitudes au profil de la course. Le vent d’est et d’ouest soufflent de côté sur les tronçons nord–sud du parcours ; le peloton s’y brise en bordures (les barres jaunes). Par vent du nord, il reste groupé mais la course dure bien plus longtemps.
Les résultats disent quelque chose de sportif. Par temps calme, les incidents ne changent ni la vitesse ni la hiérarchie : un coureur arrêté rentre le plus souvent derrière les voitures. La pluie multiplie les chutes et fait gagner des vainqueurs surprises. Le vent de côté casse le peloton en bordures et favorise les rouleurs. Et par vent fort, les meilleurs sprinteurs arrivent à court de glycogène et perdent le sprint contre des coureurs plus frais : vingt vainqueurs sur trente hors du top 40 par vent du nord, malgré trente arrivées groupées.
La malchance est tirée, jamais décidée
À chaque tick, chaque coureur qui roule fait un tirage : il a un incident avec la probabilité 1 − exp(−λ · d), d étant la distance parcourue au tick précédent en kilomètres, et un second tirage choisit la nature. Tous ces tirages se font dans un flux aléatoire à part (engine.incidents).
| Incident | Taux | Conséquence |
|---|---|---|
| Crevaison | 1 pour 5 000 km sur asphalte, 1 pour 400 km sur pavés | Arrêt de 15 à 35 s. |
| Ennui mécanique | 1 pour 10 000 km, trois fois plus sur pavés et gravier | Arrêt de 10 à 45 s. |
| Chute | Selon la taille du groupe, la technicité, le revêtement et la finale (× 1,5 dans les 20 derniers km, × 2 dans les 5 derniers) ; aussi en descente, même seul. | Les coureurs suivants tombent à la suite avec une probabilité de 0,55 (groupe de 20 ou plus) ou 0,3, jusqu’à 8 à terre. Abandon dans 10 % des cas, sinon arrêt de 15 à 60 s et blessure légère. |
Après un incident, le coureur profite de l’abri des voitures (facteur 0,55), pendant dix minutes au plus et tant qu’il n’a pas rejoint un groupe de plus de 5 coureurs. C’est ce qui lui permet, le plus souvent, de revenir.
Le terrain a son mot à dire
Le moteur de base a grandi par couches, et chacune a ajouté une règle sans en casser une autre. Ce billet ne les détaille pas, mais voici ce qu’elles apportent.
Pavés
Le roulement monte avec les étoiles du secteur et l’attribut cobbles (de 0,0075 à 0,0315). Les vibrations usent la puissance critique, jusqu’à 20 %. L’abri perd une part de son effet et, comme dans une bordure, seuls les premiers du groupe le gardent : c’est l’accordéon.
Gravier
Roulement de 0,0054 à 0,0143 selon les étoiles, l’adresse du coureur et la pluie. En montée, une part de la puissance ne propulse plus le coureur : elle patine.
Altitude
Au-dessus de 1 500 m, la puissance critique baisse de 7 % par tranche de 1 000 m. À 3 000 m, le modèle donne −10,5 %. Les courses qui ne dépassent pas 1 500 m ne changent pas d’un bit.
Contre-la-montre
Une journée a un genre (route, individuel, par équipes ou prologue) et une IA dédiée règle l’allure sur le parcours. Une course en ligne ne change pas d’un bit.
Finales de montagne
La finale est avancée au pied de l’avant-dernier col s’il commence à 70 km ou moins de l’arrivée : tempo, zones d’attaque et défense valent alors sur les deux derniers cols.
Murs
Une montée courte compte comme une vraie montée si elle fait au moins 200 m à 6 % de moyenne. Le Paterberg (360 m à 12,9 %) entre ainsi dans la lecture du parcours, avec son poids dans les plans.
Même graine, même course
Le déterminisme est le pilier qui coûte le plus cher et rapporte le plus. Sans lui, impossible de reproduire un bug, de comparer deux versions, de sauvegarder une course en cours ou de calibrer quoi que ce soit. Il repose sur quatre choses.
Un générateur précis
xoshiro128** sur quatre entiers de 32 bits, amorcé par splitmix32. Arithmétique 32 bits via Math.imul : le résultat est identique sur tout moteur JavaScript conforme.
Des flux nommés
Chaque sous-système tire dans son propre flux, dérivé de la graine et d’un hachage du nom : ai.rider.<id>, engine.incidents, perception.radioTour, radio.<équipe>… Ajouter des tirages dans l’un ne décale pas les autres.
Des maths portées à la main
ECMAScript laisse exp, log, sin, pow « approchés par l’implémentation ». Le moteur embarque donc ses propres versions, portées de fdlibm 5.3 en JavaScript pur. ESLint interdit les autres.
Un journal, pas un instantané
Une sauvegarde de course est la liste des requêtes qui l’ont changée, avec un point de contrôle. Reprendre, c’est préparer la course et rejouer le journal.
« Node 26 et Electron 44 rendaient des résultats différents d’un ulp sur une part des valeurs, et une carrière divergeait en deuxième saison. »
Constat de T39, 3 octobre 2026Cette phrase est la raison d’être du troisième point. Les laboratoires de test tournaient sous Node, l’application sous Electron, et leurs fonctions mathématiques ne rendaient pas exactement le même bit. Un écart d’un ulp sur une forme, et la course de la saison suivante changeait. Le correctif est un port de fdlibm 5.3, vérifié sur 30 millions de valeurs identiques bit à bit à la bibliothèque C d’origine, et un test qui fait tourner une même carrière sous Node et sous Electron puis compare l’empreinte de l’état complet.
Le journal protège aussi le pilier 6. Le contrôleur qui lit la course prend ses décisions d’arrêt tick par tick : découper la lecture autrement ne change ni la course, ni le fil, ni les arrêts, et un test le vérifie. La présentation ne peut donc pas modifier la simulation. En contrepartie, une sauvegarde porte la version de chaque modèle (physique, moteur, IA, perception, radio, tirage aléatoire) : si l’un d’eux a changé, elle est refusée, avec un message qui nomme le modèle et ses deux versions, plutôt que rejouée de travers.
Le banc de calibration
Un moteur déterministe garantit qu’une course se rejoue, pas qu’elle ressemble à du vélo. Pour ça, il y a directeur lab : il déroule des centaines de courses sans consigne, avec les plans du staff, dans la vraie session (perception, radio, incidents, forme du jour), et mesure ce qui en sort. Il lit l’état exact du moteur : c’est un outil de diagnostic, jamais une lecture pour le joueur.
Sept cibles disent à quoi doit ressembler un peloton. Une cible n’est pas jugée sous 20 courses du terrain, chaque mesure porte son intervalle de confiance à 95 %, et un écart n’est significatif que si tout l’intervalle est hors de la cible. Le plafond de 35 % pour le vainqueur le plus fréquent était d’abord fixé à 25 % sans mesure, puis a été révisé en cours de route.
| Cible | Plage | Mesure |
|---|---|---|
| Vitesse sur le plat | 40 à 45 km/h | 43,8 km/h (IC95 43,5 à 44,2) |
| Échappées victorieuses | 10 à 25 % | 11 % (IC95 8 à 14 %) |
| Arrivées groupées sur le plat | au moins 50 % | 84 % |
| Les grimpeurs gagnent en montagne | au moins 80 % | 91 % |
| Favoris souvent, pas toujours | 40 à 80 % | 57 % · 76 % · 82 % (plat, vallonné, montagne) |
| Pas de vainqueur systématique | au plus 35 % | 29 % · 30 % · 30 % |
| Personne n’est dominant partout | moins de 5 % sur son pire terrain | 1 % |
À la mesure, les favoris gagnaient 82 % des courses de montagne, un peu au-dessus de la plage, mais l’écart n’était pas statistiquement significatif : le rapport le signale sans le compter.
Les cibles ont dicté dix réglages du premier passage. Quatre racontent bien le travail :
| Défaut observé | Correction |
|---|---|
| Un coureur de 57 kg gagnait 36 à 38 % des courses vallonnées et de montagne. | W′, glycogène et durabilité rapportés à la masse. |
| Tout le peloton arrivait en finale au bord de la fringale. | Abri de 0,5 dans les roues d’un peloton (la file de relais reste inchangée). |
| 67 % d’arrivées groupées au sommet d’un col hors catégorie. | Allure en montée imposée par le plus fort relayeur. |
| L’échappée de montagne était toujours reprise avant le pied du dernier col. | Point de jonction visé à 8 km en montagne, 15 km en vallonné, 6 km pour un sprint. |
Le banc tourne aussi en suite de tests : 100 graines par course, météo tirée, échec sur tout écart significatif, environ 45 secondes sur neuf fils au moment de T10. Et comme il est déterministe, ses résultats ne dépendent ni du nombre de fils ni de l’horloge : un test le vérifie.
Ce qui n’est pas encore juste
Les nombres sportifs du moteur sont des hypothèses de calibration, pas des vérités validées, et nous préférons le dire d’emblée. Voici ce que nous savons ne pas encore bien faire.
- Le vallonné restait trop groupé à la mesure de T10. Le peloton arrivait presque entier au pied du mur final : 98 % des courses finissaient avec au moins 20 coureurs à 5 s ou moins, et les échappées n’y gagnaient presque jamais (1 %). Des tickets de calibration ont repris la question depuis, mais c’est le type de course où l’on reste vigilant.
- Le vent fort sur le plat est à surveiller. À 7 m/s ou plus (21 courses sur 200 à la mesure de T10), 43 % des vainqueurs étaient des favoris et 38 % venaient de hors du top 40 : plus de surprises que sur le reste du plat. C’est un point de calibration ouvert.
- La physique est quasi statique. L’inertie est négligée à l’échelle de 5 secondes, et la densité de l’air est constante à 1,225 kg/m³ partout, y compris en altitude. Quand l’altitude a été ajoutée (T66), la baisse de puissance critique était modélisée mais pas l’acclimatation.
- Hors carrière, la connaissance des rôles reste exacte et commune. En course libre et au banc, chaque équipe lit les mêmes aptitudes exactes ; c’est en carrière seulement que chacune lit ses coureurs dans son dossier et les autres dans la réputation publique.