PlayPendium
Contraption · Matière à réflexion

Un niveau qui prouve lui-même qu'il est soluble

Le jeu n'écrit jamais un casse-tête à la main. Il en fait pousser un à partir d'un seul nombre, puis il joue ce casse-tête contre lui-même pour s'assurer qu'il n'est ni trivial ni impossible avant même que vous le voyiez.

La date du jour 1 nombre, haché en une graine
devient
Le casse-tête quotidien 1 terrain identique pour tous

Rédigé et édité en anglais. Cette version française a été produite par traduction automatique ; en cas de doute sur un point précis, l'original anglais fait foi. Lire l'original en anglais →

01 · Tout à partir d'un seul nombre

Tout un monde replié dans une graine

Un niveau de Contraption n'est stocké nulle part. Aucun fichier n'indique où se trouve le but ni comment les rebords sont disposés. À la place, le niveau tout entier — le point de départ de la balle, la position du but, le nombre et l'emplacement des murs fixes, l'inventaire des pièces qu'on vous remet — est calculé à partir d'un seul nombre de départ appelé graine. Donnez la même graine au générateur et vous obtenez, octet pour octet, le même casse-tête. 1

C'est possible parce que la seule source de « hasard » du générateur est un petit générateur de nombres pseudo-aléatoires déterministe. Celui qu'utilise Contraption est mulberry32, un générateur 32 bits compact écrit par Tommy Ettinger ; on le reconnaît à sa constante caractéristique, 0x6d2b79f5, ajoutée à l'état à chaque tirage. 2 Il est rapide, il tient en quelques lignes et, surtout, il n'a rien d'aléatoire : c'est une suite mathématique fixe qui a simplement l'air mélangée. Donnez-lui un point de départ et il produit à jamais le même flux de nombres. Le générateur lit ensuite ce flux pour décider où placer chaque chose.

02 · Le casse-tête quotidien

Comment une date devient un défi partagé

Le mode Daily s'appuie sur ce déterminisme pour faire quelque chose de social. Sa graine n'est pas aléatoire, elle est fabriquée à partir du calendrier. Le jeu prend la date du jour en temps universel, l'écrit dans une courte chaîne comme « contraption:2026-7-28 », puis passe ce texte dans une fonction de hachage pour le réduire à un seul nombre de 32 bits. 1

Le hachage est FNV-1a, un mélangeur non cryptographique bien connu : il part d'un décalage fixe, le décimal 2166136261, soit 0x811c9dc5, et, pour chaque caractère, incorpore la lettre par un ou exclusif avant de multiplier par le nombre premier FNV 16777619. 3 Il en sort un nombre stable pour un jour donné et radicalement différent d'un jour à l'autre : changer un seul caractère de la date disperse complètement la graine. Puisque le calendrier est le même pour tout le monde, la graine l'est aussi, et le casse-tête également. Deux inconnus aux antipodes l'un de l'autre ouvrent Daily et affrontent exactement le même terrain, ce qui est précisément ce qui donne un sens à la comparaison des scores.

Le défi quotidien est équitable non pas parce qu'un serveur envoie le même niveau à tout le monde, mais parce que la copie de chacun recalcule indépendamment le même niveau à partir de la même date.

03 · Le générateur se remet en question

Rejeter le casse-tête qui se résout tout seul

Une géométrie aléatoire, c'est facile ; une bonne géométrie aléatoire, non. Un générateur qui se contente d'éparpiller un but et quelques rebords produira parfois un niveau où la balle, lâchée depuis le haut, tombe tout simplement droit dans le but, toute seule. Ce n'est pas un casse-tête, c'est une cinématique. Aussi, avant d'accepter un monde candidat, Contraption effectue un test discret que le code appelle preSolved : il simule le niveau sans aucune pièce posée et vérifie si la balle nue atteint le but par la seule gravité. Si c'est le cas, le niveau est jeté et le générateur recommence. 1

C'est une inversion subtile de la façon dont on se représente d'habitude un moteur physique. La même fonction simulate() qui fait tourner votre machine est retournée vers l'intérieur, au moment de la génération, pour auditer la difficulté du niveau lui-même. Le moteur est à la fois l'arbitre de votre solution et le contrôleur qualité du casse-tête.

04 · Un petit solveur intégré

« Est-ce faisable avec une seule pièce ? »

Rejeter le niveau trop facile n'est que la moitié du travail. L'autre danger, c'est le niveau impossible, un but niché à un endroit qu'aucun agencement de pièces ne peut atteindre. Contraption s'en prémunit avec un petit solveur par force brute nommé plausiblySolvable. Il ne cherche pas à être malin. Il essaie, c'est tout. 1

Concrètement, il balaie le terrain avec une seule rampe le long d'une grille de positions et, à chaque emplacement, l'essaie inclinée de quatre façons différentes. Pour chacun de ces placements d'essai, il lance la simulation complète et pose la question : cette unique rampe a-t-elle conduit la balle à destination ? Dès qu'un placement réussit, le niveau est déclaré soluble et vous est livré. Si aucun ne fonctionne au terme du balayage complet, le générateur préfère écarter le niveau et essayer une nouvelle graine.

La recherche du solveur à une seule pièce : une grille grossière, quatre inclinaisons à chaque point
Paramètre de balayagePlageSignification
Rampe X15 → 85, pas de 14colonnes en travers du terrain
Rampe Y30 → 120, pas de 18lignes de haut en bas du terrain
Angles essayés4±0.45 et ±0.8 radians
Test par placement1 simulation complètela balle atteint-elle le but ?

Il vaut la peine d'être honnête sur ce que cela prouve, car le code l'est aussi : le commentaire parle d'une « vérification de plausibilité peu coûteuse… non exhaustive ». Un niveau qui passe possède assurément au moins une solution grossière à une seule rampe. Un niveau qui échoue peut malgré tout être soluble avec un ventilateur, un engrenage ou une rampe plus astucieuse que la grille n'a jamais essayée ; le générateur ne traite donc pas l'échec comme une preuve d'impossibilité. Il conserve le premier monde non trivial qu'il a trouvé comme solution de repli, et si quarante tentatives passent sans solution propre à une seule pièce, il livre ce repli plutôt que de boucler indéfiniment. Le résultat est une garantie pragmatique : jamais de victoire gratuite, presque toujours un vrai chemin vers le but, et jamais une attente infinie du niveau « parfait ». 1

05 · L'idée de fond

Générer et tester, la forme la plus humble de l'intelligence

Prenez du recul et le fabricant de niveaux de Contraption apparaît comme un exemple limpide d'un schéma de résolution de problèmes très ancien et très général : générer et tester. Proposez un candidat au hasard ; confrontez-le à vos exigences ; gardez-le s'il passe, jetez-le et proposez-en un autre s'il échoue. C'est la boucle derrière le contenu procédural d'innombrables jeux, derrière une grande part du calcul évolutionnaire et, pour peu qu'on plisse les yeux, derrière la sélection naturelle elle-même : la mutation propose, l'environnement teste, les survivants persistent. 4

Ce qui rend la version de Contraption élégante, c'est que le test n'est pas une approximation bon marché de la jouabilité : il est la jouabilité. Le générateur n'estime pas l'équité d'un niveau en comptant les rebords ou en mesurant des distances. Il joue littéralement le niveau, deux fois : une fois à vide pour s'assurer que ce n'est pas un cadeau, et une fois avec une rampe exploratoire pour s'assurer qu'un chemin existe. La même physique déterministe qui jugera votre solution est celle qui a validé le casse-tête. Il n'existe pas de « validateur de niveau » distinct qui pourrait se désynchroniser des vraies règles, car il n'y a qu'un seul jeu de règles, utilisé pour tout.

Et parce que tout est déterministe, l'audit est exempt de chance dans les deux sens. La graine du jour ne peut pas comploter pour offrir à un joueur un terrain plus facile qu'à un autre, et elle ne peut en offrir un injuste à personne, car avant d'être un défi, le niveau a déjà survécu à une partie jouée par le jeu contre lui-même.

Sources & notes
  1. Seed-to-level generation, the preSolved rejection test, the plausiblySolvable one-ramp solver (grid ranges, four angles, up to 40 attempts, fallback world), and the daily-seed date string are all read directly from Contraption's own game engine and random-number code. Grounded in the game's code, not invented.
  2. mulberry32 is a compact 32-bit pseudo-random generator by Tommy Ettinger; it advances its state with the constant 0x6d2b79f5 and has a period of 2³². Author's reference gist (with his own later caveats on its equidistribution). gist.github.com/tommyettinger/46a874533244883189143505d203312c
  3. "Fowler–Noll–Vo hash function." Wikipedia, the 32-bit FNV offset basis is 2166136261 (0x811c9dc5) and the FNV prime is 16777619 (0x01000193); FNV-1a XORs each byte into the hash first and then multiplies by the prime. en.wikipedia.org/wiki/Fowler–Noll–Vo_hash_function
  4. On generate-and-test / "generation followed by evaluation" as a general search and problem-solving strategy, and its kinship with procedural generation and evolutionary methods. See "Procedural generation," Wikipedia. en.wikipedia.org/wiki/Procedural_generation
  5. Further reading on Procedural generation, [2410.15644] Procedural Content Generation in Games: A Survey with Insights on Emerging LLM Integration. arxiv.org.
  6. Further reading on Procedural generation, Procedural Content Generation in Games: A Survey with Insights on Emerging LLM Integration. doi.org.
  7. Further reading on Procedural generation, "Procedural City Generation with Combined Architectures for Real-time V" by Gr. open.clemson.edu.
Was this worth reading?
← Back to Contraption
PlayPendium · About · Contact · Privacy · Terms · Cookies · Accessibility · Copyright · Browse all games · Inspirations · © 2026