Jocul nu construiește niciodată un puzzle de mână. Îl face să crească dintr-un singur număr, iar apoi joacă acel puzzle împotriva lui însuși, ca să se asigure că nu este nici banal, nici imposibil, înainte ca dumneavoastră să-l vedeți vreodată.
Scris și editat în limba engleză. Această versiune în română a fost produsă prin traducere automată; acolo unde precizia contează, originalul în engleză este autoritatea. Citiți originalul în engleză →
Un nivel din Contraption nu este stocat nicăieri. Nu există niciun fișier care să spună unde se află poarta sau cum sunt aranjate pervazurile. În schimb, întregul nivel, punctul de pornire al mingii, poziția porții, numărul și amplasarea pereților ficși, inventarul de piese care vi se înmânează, este calculat dintr-un singur număr de pornire, numit sămânță. Dați generatorului aceeași sămânță și obțineți, octet cu octet, același puzzle. 1
Acest lucru este posibil pentru că singura sursă de „aleatoriu” a generatorului este un mic generator determinist de numere pseudoaleatoare. Cel folosit de Contraption este mulberry32, un generator compact pe 32 de biți creat de Tommy Ettinger, pe care îl puteți recunoaște după constanta sa caracteristică, 0x6d2b79f5, adunată la stare la fiecare extragere. 2 Este rapid, încape în câteva rânduri și, lucru esențial, nu este deloc aleatoriu: este o secvență matematică fixă care doar pare amestecată. Dați-i un punct de pornire și va produce același șir de numere la nesfârșit. Generatorul citește apoi acel șir pentru a decide unde să pună fiecare lucru.
Modul Zilnic se sprijină pe acest determinism ca să facă ceva social. Sămânța lui nu este aleatorie, ci este fabricată din calendar. Jocul ia data de astăzi în timp universal, o scrie într-un șir scurt de forma „contraption:2026-7-28” și trece acel text printr-o funcție hash pentru a-l reduce la un singur număr pe 32 de biți. 1
Funcția hash este FNV-1a, un amestecător necriptografic binecunoscut: pornește de la un decalaj fix, numărul zecimal 2166136261, adică 0x811c9dc5, și pentru fiecare caracter încorporează litera printr-un SAU exclusiv, apoi înmulțește cu numărul prim FNV 16777619. 3 Rezultatul este un număr stabil pentru o zi dată și complet diferit de la o zi la alta, astfel încât o schimbare de un singur caracter în dată împrăștie sămânța cu totul. Pentru că același calendar este valabil pentru toată lumea, la fel este și sămânța, și la fel este și puzzle-ul. Doi străini de pe părți opuse ale lumii deschid modul Zilnic și dau peste exact același teren, ceea ce este tocmai ce face ca o comparație de scoruri să aibă sens.
Provocarea zilnică este corectă nu pentru că un server trimite tuturor același nivel, ci pentru că fiecare copie a jocului recalculează independent același nivel din aceeași dată.
Geometria aleatorie este ușor de făcut; geometria aleatorie bună nu este. Un generator care doar împrăștie o poartă și câteva pervazuri va produce uneori un nivel în care mingea, lăsată să cadă de sus, cade pur și simplu direct în poartă de una singură. Acela nu este un puzzle, ci o secvență cinematică. Așa că, înainte ca Contraption să accepte o lume candidată, rulează un test discret pe care codul îl numește preSolved: simulează nivelul cu zero piese plasate și verifică dacă mingea goală ajunge la poartă doar prin gravitație. Dacă ajunge, nivelul este aruncat, iar generatorul încearcă din nou. 1
Aceasta este o inversare subtilă a felului în care vă gândiți în mod normal la un motor de fizică. Aceeași funcție simulate() care pune în mișcare mașina dumneavoastră este întoarsă spre interior, în momentul generării, pentru a audita dificultatea nivelului însuși. Motorul este în același timp arbitrul soluției dumneavoastră și inspectorul de calitate al puzzle-ului.
Respingerea nivelului prea ușor este doar jumătate din treabă. Celălalt pericol este nivelul imposibil, o poartă ascunsă undeva unde niciun aranjament de piese nu poate ajunge. Contraption se apără de acest lucru cu un mic rezolvator prin forță brută numit plausiblySolvable. Nu gândește inteligent. Pur și simplu încearcă. 1
Mai exact, plimbă o singură rampă pe o grilă de poziții de pe teren și, în fiecare punct, o încearcă înclinată în patru feluri diferite. Pentru fiecare dintre aceste plasări de probă rulează simularea completă și întreabă: a dus acea rampă mingea acasă? În clipa în care oricare plasare reușește, nivelul este declarat rezolvabil și vă este livrat. Dacă niciuna nu funcționează după parcurgerea întregii grile, generatorul preferă să renunțe la nivel și să încerce o sămânță nouă.
| Parametru de căutare | Interval | Semnificație |
|---|---|---|
| Rampă X | 15 → 85, pas 14 | coloane de-a latul terenului |
| Rampă Y | 30 → 120, pas 18 | rânduri în josul terenului |
| Unghiuri încercate | 4 | ±0.45 și ±0.8 radiani |
| Test per plasare | 1 simulare completă | ajunge mingea la poartă? |
Merită să fim sinceri cu privire la ce anume dovedește acest lucru, pentru că și codul este sincer în această privință: comentariul îl numește o „verificare ieftină de plauzibilitate … nu exhaustivă”. Un nivel care trece are cu siguranță cel puțin o soluție rudimentară cu o singură rampă. Un nivel care pică ar putea totuși fi rezolvabil cu un ventilator, un angrenaj sau o rampă mai ingenioasă pe care grila nu a încercat-o niciodată, așa că generatorul nu tratează eșecul ca pe o dovadă de imposibilitate. Păstrează prima lume nebanală pe care a găsit-o ca rezervă și, dacă trec patruzeci de încercări fără o soluție curată cu o singură piesă, livrează acea rezervă în loc să se învârtă în buclă la nesfârșit. Rezultatul este o garanție pragmatică: niciodată o victorie gratuită, aproape întotdeauna o cale de acces autentică și niciodată o așteptare infinită după nivelul „perfect”. 1
Priviți de la distanță și generatorul de niveluri din Contraption este un exemplu curat al unui tipar de rezolvare a problemelor foarte vechi și foarte general: generează și testează. Propuneți un candidat la întâmplare; verificați-l față de cerințele dumneavoastră; păstrați-l dacă trece, aruncați-l și propuneți altul dacă pică. Este bucla din spatele conținutului procedural din nenumărate jocuri, din spatele unei mari părți a calculului evolutiv și, cu puțină îngăduință, din spatele selecției naturale înseși: mutația propune, mediul testează, supraviețuitorii persistă. 4
Ceea ce face varianta din Contraption elegantă este că testul nu este un substitut ieftin al jucabilității, ci este jucabilitatea. Generatorul nu estimează dacă un nivel este corect numărând pervazurile sau măsurând distanțele. El joacă nivelul la propriu, de două ori: o dată gol, ca să se asigure că nu este un cadou, și o dată cu o rampă de sondare, ca să se asigure că există o cale. Aceeași fizică deterministă care vă va judeca soluția este fizica ce a verificat puzzle-ul. Nu există un „validator de niveluri” separat care s-ar putea desincroniza de regulile reale, pentru că există un singur set de reguli, folosit pentru tot.
Și pentru că totul este determinist, auditul este lipsit de noroc în ambele direcții. Sămânța zilnică nu poate conspira să-i dea unui jucător un teren mai ușor decât altuia și nu poate da nimănui unul nedrept, pentru că, înainte de a fi o provocare, nivelul a supraviețuit deja jucării, de către joc, împotriva lui însuși.