Kako bacamo kockice — i zašto je to pošteno
Da li su kockice u bekgemonu online nameštene? Evo kako naš server generiše bacanja: kriptografski, bez pristrasnosti, sa istim šansama kao fizičke kockice.
Počnimo sa pitanjem koje je svaki igrač bekgemona online pomislio bar jednom, obično odmah nakon što baci 6-1 kada mu je trebalo bilo šta drugo: da li su kockice nameštene?
Sumnjati u to je sasvim opravdano. Zato, umesto da vam kažemo „verujte nam”, pokazaćemo vam tačno kako naše kockice rade — jednostavnim jezikom za sve i sa stvarnim kodom za skeptike koji softver pišu za hleb. Do kraja ćete znati više o našim kockicama nego o onim drvenim u vašem ormaru.
Kockice se bacaju na serveru, a ne na vašem telefonu
Kada dodirnete da biste bacili, vaš uređaj ne odlučuje ništa. On šalje zahtev našem serveru, server generiše kockice i šalje rezultat nazad. Ishod je fiksiran u trenutku kada nastane.
To na prvi pogled zvuči manje pouzdano — „čekajte, vi bacate kockice?” — ali je upravo suprotno. Kada bi se kockice generisale na vašem telefonu ili u pregledaču, izmenjena aplikacija bi mogla jednostavno da baci šta god poželi. Duple u svakom potezu. Centralizovanjem bacanja na serveru koji kontrolišemo i možemo da nadgledamo, nijedan učesnik ne može da utiče na kockice — ni vi, ni vaš protivnik, ni mi tokom partije.
Predvidiva slučajnost naspram kriptografske slučajnosti
Evo gde većina „nasumičnih” generatora tiho greši.
Mnogi programski jezici dolaze sa podrazumevanom nasumičnom funkcijom koja je brza, ali predvidiva. Ona kreće od jednog broja („seed-a”) i odatle proizvodi fiksni niz. Svako ko sazna seed — ili jednostavno posmatra dovoljno bacanja — može da počne da predviđa šta sledi. Za takmičarsku igru, gde su poeni i ponos na kocki, to je neprihvatljivo.
Mi ne koristimo takvu vrstu generatora. Koristimo Go-ov crypto/rand — istu klasu slučajnosti koja se koristi za generisanje ključeva za šifrovanje koji štite bankarski saobraćaj. Crpi se iz entropijskog bazena operativnog sistema, ne može da se posadi seed-om i ne može da se predvidi iz prošlih bacanja. Nema skrivenog niza koji bi se obrnuto inženjerski razotkrio, jer niza i nema.
Nekoliko detalja za inženjere koji čitaju, tačnih od Go 1.26 (jezika na kojem radi naš backend):
- Izvor slučajnosti ne može tiho da se zameni slabijim. Od Go 1.26 uvek se koristi siguran izvor podržan od strane operativnog sistema; ništa u našem kodu ni u našim zavisnostima ne može tiho da ga oslabi.
- Nema povratka na pogodive vrednosti. Ako bi entropijski izvor operativnog sistema ikada otkazao — praktično nemoguće — program se odmah ruši umesto da nastavi sa lošom slučajnošću. Najgori slučaj je da se igra zaustavi, nikada da vara.
Suptilna zamka: modulo pristrasnost
Ovo je deo o kome većina ljudi nikada ne čuje, a baš odatle dolaze „skoro poštene” kockice.
Računari proizvode slučajnost kao sirove bajtove — brojeve od 0 do 255. Naivan način da se to pretvori u bacanje kockice jeste da se uzme ostatak nakon deljenja sa 6 („modulo 6”). Deluje ispravno. Nije. Opseg 0–255 ne deli se ravnomerno na šest grupa, pa par strana ispada malo češće od ostalih. To je sićušna, trajna, nevidljiva pristrasnost — ali kroz milione bacanja postaje statistički stvarna. To je razlika između poštenih kockica i suptilno nameštenih.
Mi to potpuno izbegavamo. Umesto prečice sa ostatkom, izvlačimo jedan ujednačen broj preko svih 36 mogućih kombinacija kockica koristeći crypto/rand.Int. Ispod haube to koristi odbacivanje uzoraka (rejection sampling): tiho odbacuje „preostale” vrednosti koje bi iskrivile rezultat, tako da je ono što ostane matematički ujednačeno. Svaki od 36 ishoda je tačno jednako verovatan. Bez ostatka, bez pristrasnosti.
Pravi kod
Ne tražimo da nam verujete na reč. Ovo je pravi mehanizam (Go 1.26):
package dice
import (
"crypto/rand"
"math/big"
)
// cryptoRoll returns the dice for a single backgammon roll.
// Each of the 36 combinations is exactly equally likely, with no modulo bias.
// Doubles return four moves; a normal roll returns two.
func cryptoRoll() []int {
// One unbiased draw over all 36 combinations [0, 36).
// rand.Int uses crypto/rand (secure, OS-backed) and rejects the
// leftover values internally, so every outcome is equally likely.
// On Go 1.24+, rand.Int cannot return an error here, so discarding
// it is safe: crypto/rand.Read never errors and crashes the process
// irrecoverably on the (practically impossible) entropy failure.
n, _ := rand.Int(rand.Reader, big.NewInt(36))
i := int(n.Int64())
d1, d2 := i/6+1, i%6+1
if d1 == d2 {
return []int{d1, d1, d1, d1} // doubles → 4 moves
}
return []int{d1, d2}
}
Za radoznale: big.NewInt(36) je ceo prostor od 6 × 6 ishoda, a i/6 + 1 i i%6 + 1 dele taj jedan broj nazad na dve strane od 1 do 6.
Dupli rade tačno kao fizičke kockice
Bacanje su dve kockice. Kada se poklope — dupli — bekgemon vam daje četiri poteza te vrednosti, pa funkcija vraća četiri stavke. Šanse su identične pravom paru kockica: bilo koji dupli ispada 1 od 6, a određeni dupli (recimo dupla petica) je 1 od 36. Ne pravimo duple ređima da bismo usporili igru, niti češćima da bismo je ubrzali. Padaju tačno onoliko često koliko fizika nalaže.
Šta bacanje namerno ne radi
Ovo je srž sumnje da je „nameštено”, pa budimo direktni. Funkcija za kockice:
- ne čita rezultat, stanje meča ili ko samo što ne iznosi figure;
- ne zna ulog, ni ko ste, ni protiv koga igrate;
- nema logiku za nadoknadu, krivu težine, niti guranje u korist kuće.
Njen jedini ulaz je slučajnost. Njen jedini izlaz su dve poštene kockice. Kockice zaista ne znaju — i ne mogu da znaju — da vam je trebalo 6-1, a da ste umesto toga dobili 2-1.
Poverenje se zaslužuje, ne tvrdi
Mogli smo jednostavno da napišemo „naše kockice su poštene” i da nastavimo dalje. Radije vam predajemo mehanizam i kod i puštamo vas da proverite naš rad. To je čitava poenta ovog teksta: transparentnost koju možete da proverite bolja je od uveravanja koje morate da progutate.
Ako ste ikada bili sigurni da su kockice protiv vas, niste sami — svaki igrač bekgemona je to pomislio. Razlika je u tome što sada možete da pročitate tačno kako su napravljene.
Odigrajte partiju i uverite se sami →
Više volite aplikaciju? Preuzmite je sa App Store ili Google Play.
Spreman za igru?
Igraj odmah