← Aktualności

Jak rzucamy kości — i dlaczego jest to uczciwe

Czy kości w backgammonie online są ustawione? Oto jak nasz serwer generuje rzuty: kryptograficznie, bez obciążenia, z szansami jak u kości fizycznych.

technical 18 czerwca 2026

Zacznijmy od pytania, które przynajmniej raz przeszło przez głowę każdemu graczowi w backgammona online — zwykle tuż po wyrzuceniu 6-1, gdy potrzebował czegokolwiek innego: czy kości są ustawione?

To uzasadniony powód do podejrzeń. Dlatego zamiast mówić „zaufaj nam”, pokażemy Ci dokładnie, jak działają nasze kości — prostym językiem dla wszystkich oraz z prawdziwym kodem dla sceptyków, którzy zawodowo piszą oprogramowanie. Na koniec będziesz wiedzieć więcej o naszych kościach niż o tych drewnianych w swojej szafie.

Kości są rzucane na serwerze, a nie na Twoim telefonie

Gdy stukasz, by rzucić, Twoje urządzenie o niczym nie decyduje. Wysyła żądanie do naszego serwera, serwer generuje kości i odsyła wynik z powrotem. Rezultat jest ustalony w chwili, gdy powstaje.

Na pierwszy rzut oka brzmi to mniej godnie zaufania — „chwila, to wy rzucacie kośćmi?” — ale jest na odwrót. Gdyby kości były generowane na Twoim telefonie albo w przeglądarce, zmodyfikowana aplikacja mogłaby po prostu wyrzucać, co chce. Dublety w każdej turze. Centralizując rzuty na serwerze, który kontrolujemy i możemy audytować, żaden uczestnik nie może wpłynąć na kości — ani Ty, ani Twój przeciwnik, ani my w trakcie gry.

Przewidywalna losowość kontra losowość kryptograficzna

Tu właśnie większość „losowych” generatorów po cichu zawodzi.

Wiele języków programowania dostarcza domyślną funkcję losującą, która jest szybka, ale przewidywalna. Startuje od jednej liczby („ziarna”) i wytwarza od niej ustaloną sekwencję. Każdy, kto pozna ziarno — albo po prostu obejrzy wystarczająco dużo rzutów — może zacząć przewidywać, co będzie dalej. W grze rywalizacyjnej, gdzie w grę wchodzą punkty i duma, to niedopuszczalne.

Nie używamy takiego generatora. Korzystamy z crypto/rand w Go — tej samej klasy losowości, której używa się do generowania kluczy szyfrujących chroniących ruch bankowy. Czerpie ją z puli entropii systemu operacyjnego, nie da się jej zaszczepić ziarnem ani przewidzieć na podstawie poprzednich rzutów. Nie ma ukrytej sekwencji do odtworzenia metodą inżynierii wstecznej, bo żadnej sekwencji nie ma.

Kilka szczegółów dla inżynierów, którzy to czytają, aktualnych na Go 1.26 (język, na którym działa nasz backend):

  • Źródła losowości nie da się po cichu podmienić na słabsze. Od Go 1.26 zawsze używane jest bezpieczne źródło oparte na systemie operacyjnym; nic w naszym kodzie ani w zależnościach nie może go po cichu osłabić.
  • Nie ma awaryjnego przejścia na łatwe do odgadnięcia wartości. Gdyby źródło entropii systemu operacyjnego kiedykolwiek zawiodło — co praktycznie niemożliwe — program po prostu się wykrzacza, zamiast kuleć z kiepską losowością. W najgorszym razie gra się zatrzymuje, nigdy nie oszukuje.

Subtelna pułapka: obciążenie modulo

To część, o której większość ludzi nigdy nie słyszy, a właśnie stąd biorą się „prawie uczciwe” kości.

Komputery wytwarzają losowość jako surowe bajty — liczby od 0 do 255. Naiwny sposób zamiany tego na rzut kością to wzięcie reszty z dzielenia przez 6 („modulo 6”). Wygląda poprawnie. Nie jest. Zakres 0–255 nie dzieli się równo na sześć grup, więc kilka ścianek wypada nieco częściej niż pozostałe. To maleńkie, trwałe, niewidoczne obciążenie — ale na przestrzeni milionów rzutów staje się statystycznie realne. To różnica między kośćmi uczciwymi a subtelnie obciążonymi.

Unikamy tego całkowicie. Zamiast skrótu z resztą losujemy jedną równomierną liczbę spośród wszystkich 36 możliwych kombinacji kości za pomocą crypto/rand.Int. Pod spodem używa to próbkowania z odrzuceniem (rejection sampling): po cichu odrzuca „resztkowe” wartości, które wypaczyłyby wynik, więc to, co zostaje, jest matematycznie równomierne. Każdy z 36 wyników jest dokładnie tak samo prawdopodobny. Bez reszty, bez obciążenia.

Prawdziwy kod

Nie prosimy, byś wierzył nam na słowo. Oto rzeczywisty mechanizm (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}
}

Dla ciekawych: big.NewInt(36) to pełna przestrzeń 6 × 6 wyników, a i/6 + 1 oraz i%6 + 1 rozdzielają tę jedną liczbę z powrotem na dwie ścianki od 1 do 6.

Dublety działają dokładnie jak kości fizyczne

Rzut to dwie kości. Gdy się zgadzają — dublet — backgammon daje Ci cztery ruchy o tej wartości, więc funkcja zwraca cztery wpisy. Szanse są identyczne jak przy prawdziwej parze kości: dowolny dublet wypada 1 na 6, a konkretny dublet (powiedzmy podwójne 5) 1 na 36. Nie robimy dubletów rzadszymi, by spowolnić grę, ani częstszymi, by ją przyspieszyć. Wypadają dokładnie tak często, jak każe fizyka.

Czego rzut celowo nie robi

To sedno podejrzeń o „ustawienie”, więc powiedzmy wprost. Funkcja kości:

  • nie odczytuje wyniku, stanu meczu ani tego, kto za chwilę zrzuca pionki z planszy;
  • nie zna stawki, nie wie, kim jesteś ani z kim grasz;
  • nie ma logiki dogonienia, krzywej trudności ani nudgu sprzyjającego kasynu.

Jej jedynym wejściem jest losowość. Jej jedynym wyjściem są dwie uczciwe kości. Kości naprawdę nie wiedzą — i nie mogą wiedzieć — że potrzebowałeś 6-1, a zamiast tego dostałeś 2-1.

Zaufanie się zdobywa, a nie deklaruje

Mogliśmy po prostu napisać „nasze kości są uczciwe” i przejść dalej. Wolimy podać Ci mechanizm i kod, i pozwolić sprawdzić naszą pracę. O to właśnie chodzi w tym wpisie: przejrzystość, którą możesz zweryfikować, bije zapewnienia, które musisz przełknąć.

Jeśli kiedykolwiek przysięgałeś, że kości się na Ciebie uwzięły, jesteś w dobrym towarzystwie — każdy gracz w backgammona to przeżył. Różnica polega na tym, że teraz możesz przeczytać dokładnie, jak są tworzone.

Zagraj partię i przekonaj się sam →

Wolisz aplikację? Pobierz ją w App Store lub Google Play.

Gotowy do gry?

Graj teraz
Graj teraz