Pokerni: żetony bez wartości pieniężnej, nie do kupienia, nie do wymiany, nie do przekazania; przeciwnicy AI oznaczeni odznaką. Skoro to dom dostarcza przeciwników, jesteśmy Ci winni pełną przejrzystość rozdania.
Obliczenie odbywa się w całości w Twojej przeglądarce; nic nie jest wysyłane na serwer. Ta przeglądarka zachowuje odcisk odebrany przed rozdaniem i ziarno odebrane po nim; jeśli jesteś zalogowany, sprawdzana jest też Twoja historia. Możesz również wkleić obie wartości samodzielnie: przy stole odcisk pojawia się po najechaniu na odznakę „Weryfikowalne rozdanie”.
Co dowodzi ta weryfikacja: że odcisk opublikowany przed pierwszą kartą jest rzeczywiście odciskiem ziarna ujawnionego po ostatniej. Talia była więc ustalona, zanim zobaczyłeś choć jedną kartę, i nikt nie mógł jej zmienić w trakcie rozdania.
Czego nie dowodzi: dokładnej kolejności 52 kart wynikającej z ziarna. To tasowanie używa generatora NumPy, którego przeglądarka nie potrafi odtworzyć; skrypt Pythona z wersji technicznej odtwarza ją karta po karcie.
Przeciwnicy AI stale noszą odznakę IA na swoim miejscu, wraz ze swoim poziomem. AI otrzymuje dokładnie te same informacje co gracz-człowiek siedzący na jej miejscu: swoje dwie karty, karty wspólne i publiczne zagrania; nigdy kart innych graczy ani kart, które dopiero nadejdą. Kod rozdania jest weryfikowalny, jak wyjaśniono powyżej. Trener to system zautomatyzowany: jego rady oblicza program, nigdy nie udziela ich osoba, wyłącznie na podstawie Twoich kart i publicznych zagrań.
Przed każdym rozdaniem serwer losuje 63-bitowe ziarno generatorem kryptograficznym systemu (secrets.randbits(63) w Pythonie, nieprzewidywalne, także dla nas). To ziarno zasila deterministyczną permutację 52 kart (numpy.random.default_rng(ziarno).permutation(52)). Dwie karty każdego gracza, a potem 5 kart wspólnych, są rozdawane w kolejności talii, bez kart spalonych.
Serwer nie może zmienić kart w trakcie rozdania i tego dowodzi:
1. Przed rozdaniem każdy komunikat stanu zawiera zobowiązanie: commit = SHA-256("selfpoker:" + ziarno). Odcisk ustala całą talię, nie zdradzając niczego.
2. Po rozdaniu komunikat końcowy (hand_end) ujawnia ziarno. Każdy może wtedy sprawdzić, że odcisk się zgadza, i odtworzyć całą talię, łącznie z kartami, które nie zostały rozdane.
import hashlib
import numpy as np
graine = 1234567890123456789 # pole "fairplay.seed" komunikatu hand_end
commit = "..." # pole "commit" komunikatów stanu
assert hashlib.sha256(f"selfpoker:{graine}".encode()).hexdigest() == commit
paquet = list(np.random.default_rng(graine).permutation(52))
# n graczy: karty 0..2n-1 = ręce (2 na gracza), 2n..2n+4 = karty wspólne
# wartość = karta // 4 (0=2 … 12=as), kolor = karta % 4 (♣♦♥♠)
Każde rozegrane rozdanie jest archiwizowane wraz z ziarnem: całą historię można odtworzyć identycznie.
Pytania? Kod serwera można obejrzeć na maszynie, która go hostuje: to prywatna strona, wśród ludzi, którzy sobie ufają.
Muzyka w tle: Jason Shaw, audionautix.com, licencja Creative Commons BY 4.0 (« Big Swing Band », « Closer To Jazz », « Dirt Road Traveler », « Nice And Easy », « Acoustic Rock », « Feel Good Rock »).