Het spel maakt nooit met de hand een puzzel. Het laat er een groeien uit één enkel getal, en speelt die puzzel vervolgens tegen zichzelf om er zeker van te zijn dat hij triviaal noch onmogelijk is voordat jij hem ooit te zien krijgt.
In het Engels geschreven en geredigeerd. Deze Nederlandse versie is met machinevertaling gemaakt; waar precisie ertoe doet, is het Engelse origineel leidend. Lees het origineel in het Engels →
Een Contraption-level wordt nergens opgeslagen. Er is geen bestand dat vermeldt waar het doel zit of hoe de richels liggen. In plaats daarvan wordt het hele level, de startpositie van de bal, de plek van het doel, het aantal en de plaatsing van de vaste muren, de voorraad onderdelen die je krijgt, berekend uit één enkel startgetal dat een seed heet. Geef de generator dezelfde seed en je krijgt, byte voor byte, dezelfde puzzel. 1
Dat kan omdat de enige bron van "willekeur" van de generator een kleine deterministische pseudowillekeurige-getallengenerator is. Die van Contraption is mulberry32, een compacte 32-bits generator van de hand van Tommy Ettinger; je herkent hem aan zijn kenmerkende constante, 0x6d2b79f5, die bij elke trekking bij de toestand wordt opgeteld. 2 Hij is snel, hij past in een paar regels en, cruciaal, hij is helemaal niet willekeurig: het is een vaste wiskundige reeks die er alleen maar gehusseld uitziet. Geef hem een startpunt en hij produceert voor altijd dezelfde stroom getallen. De generator leest die stroom vervolgens om te bepalen waar alles komt te staan.
De modus Dagelijks leunt op dit determinisme om iets sociaals te doen. Zijn seed is niet willekeurig, hij wordt gefabriceerd uit de kalender. Het spel neemt de datum van vandaag in universele tijd, schrijft die in een korte tekenreeks zoals "contraption:2026-7-28" en haalt die tekst door een hashfunctie om hem in te dikken tot één 32-bits getal. 1
De hash is FNV-1a, een bekende niet-cryptografische mixer: hij begint bij een vaste offset, decimaal 2166136261, oftewel 0x811c9dc5, en vouwt voor elk teken de letter erin met een exclusieve-of, om daarna te vermenigvuldigen met het FNV-priemgetal 16777619. 3 Wat overblijft is een getal dat voor een gegeven dag stabiel is en van de ene dag op de andere wild verschilt, zodat een wijziging van één teken in de datum de seed volledig door elkaar gooit. Omdat de kalender voor iedereen dezelfde is, is de seed dat ook, en de puzzel dus ook. Twee vreemden aan weerszijden van de wereld openen Dagelijks en staan voor exact hetzelfde veld, en dat is precies wat het vergelijken van een score betekenisvol maakt.
De dagelijkse uitdaging is eerlijk, niet omdat een server iedereen hetzelfde level toestuurt, maar omdat ieders exemplaar onafhankelijk hetzelfde level opnieuw berekent uit dezelfde datum.
Willekeurige geometrie is makkelijk; goede willekeurige geometrie niet. Een generator die zomaar een doel en wat richels rondstrooit, levert soms een level op waarin de bal, losgelaten vanaf de bovenkant, gewoon uit zichzelf recht in het doel valt. Dat is geen puzzel, dat is een tussenfilmpje. Dus voordat Contraption een kandidaatwereld accepteert, draait het een stille test die de code preSolved noemt: het simuleert het level met nul geplaatste onderdelen en controleert of de kale bal het doel alleen door de zwaartekracht bereikt. Als dat zo is, wordt het level weggegooid en gooit de generator opnieuw. 1
Dit is een subtiele omkering van hoe je normaal over een natuurkunde-engine denkt. Dezelfde functie simulate() die jouw machine afspeelt, wordt naar binnen gekeerd, tijdens het genereren, om de moeilijkheid van het level zelf te keuren. De engine is zowel de scheidsrechter van jouw oplossing als de kwaliteitsinspecteur van de puzzel.
Het te makkelijke level afwijzen is maar het halve werk. Het andere gevaar is het onmogelijke level, een doel dat ergens is weggestopt waar geen enkele opstelling van onderdelen bij kan. Contraption wapent zich hiertegen met een kleine brute-force-oplosser genaamd plausiblySolvable. Die denkt niet slim na. Hij probeert gewoon. 1
Concreet schuift hij één helling over een raster van posities over het veld en probeert hem op elke plek in vier verschillende standen gekanteld. Voor elk van die proefplaatsingen draait hij de volledige simulatie en vraagt: heeft die ene helling de bal thuisgebracht? Zodra één plaatsing slaagt, wordt het level oplosbaar verklaard en naar jou verscheept. Als er na de hele doorloop geen enkele werkt, gooit de generator het level liever weg en probeert hij een nieuwe seed.
| Doorloopparameter | Bereik | Betekenis |
|---|---|---|
| Helling X | 15 → 85, stap 14 | kolommen over het veld |
| Helling Y | 30 → 120, stap 18 | rijen omlaag over het veld |
| Geprobeerde hoeken | 4 | ±0.45 en ±0.8 radialen |
| Test per plaatsing | 1 volledige simulatie | bereikt de bal het doel? |
Het is de moeite waard eerlijk te zijn over wat dit bewijst, want de code is er ook eerlijk over: het commentaar noemt het een "goedkope plausibiliteitscontrole … niet uitputtend". Een level dat slaagt, heeft zeker minstens één grove oplossing met één helling. Een level dat faalt, is misschien nog steeds oplosbaar met een ventilator, een tandwiel of een slimmere helling die het raster nooit heeft geprobeerd, dus de generator behandelt falen niet als bewijs van onmogelijkheid. Hij bewaart de eerste niet-triviale wereld die hij vond als terugvaloptie, en als er veertig pogingen voorbijgaan zonder een schone oplossing met één onderdeel, verscheept hij die terugvaloptie in plaats van eindeloos door te lussen. Het resultaat is een pragmatische garantie: nooit een gratis overwinning, bijna altijd een echte weg naar binnen, en nooit een oneindig wachten op het "perfecte" level. 1
Neem een stap terug en de levelmaker van Contraption is een schoolvoorbeeld van een heel oud en heel algemeen probleemoplossingspatroon: genereren en testen. Stel willekeurig een kandidaat voor; toets hem aan je eisen; houd hem als hij slaagt, verwerp hem en stel een nieuwe voor als hij faalt. Het is de lus achter procedurele content in talloze spellen, achter een groot deel van de evolutionaire berekening en, met een beetje goede wil, achter natuurlijke selectie zelf: mutatie stelt voor, de omgeving test, overlevers blijven. 4
Wat de versie van Contraption elegant maakt, is dat de test geen goedkope benadering van speelbaarheid is, hij is speelbaarheid. De generator schat niet of een level eerlijk is door richels te tellen of afstanden te meten. Hij speelt het level letterlijk, twee keer: één keer leeg om er zeker van te zijn dat het geen cadeautje is, en één keer met een aftastende helling om er zeker van te zijn dat er een pad bestaat. Dezelfde deterministische natuurkunde die jouw oplossing zal beoordelen, is de natuurkunde die de puzzel heeft gekeurd. Er is geen aparte "levelvalidator" die uit de pas kan gaan lopen met de echte regels, want er is maar één set regels, die voor alles wordt gebruikt.
En omdat het allemaal deterministisch is, is de keuring in beide richtingen vrij van geluk. De dagelijkse seed kan niet samenspannen om de ene speler een makkelijker veld te geven dan de andere, en hij kan niemand een oneerlijk veld geven, want voordat het level een uitdaging is, heeft het het al overleefd om gespeeld te worden, door het spel, tegen zichzelf.