Chciałbym się upewnić, czy faktycznie to będą prawdziwie losowe liczby, a jak nie, to dlaczego? Jakiś czas temu rzuciłem taki pomysł na forum elektronicznym w kontekście jakiegoś komputerka 8-bitowego i został podniesiony zarzut, że to nie jest dobry pomysł na liczby losowe, ale bez uzasadnienia (na pewno nie chodzi o udział użytkownika ani ryzyko konieczności wielokrotnego naciskania klawisza, chodziło o samą jakość losowania).
Załóżmy, że chcemy losować liczby od 1 do 6 (rzut kostką). O ile na PC, czy nawet Raspberry PI, czy smartfonie, to żaden problem, to na prostych urządzeniach (mikrokontrolery, systemy wbudowane) to już może być problem. Na PC jest pełno algorytmów pseudolosowych, które generują ciągi udające losowe w stopniu wystarczającym w 99% projektów.
Oczywiście, nic nie stoi na przeszkodzie, żeby na PC zastosować opisany niżej pomysł.
Pomysły są dwa, oba mają następujące wspólne cechy:
- Program czeka na naciśnięcie klawisza, moment naciśnięcia klawisza decyduje o wylosowanej liczbie.
- Przy naciśnięciu klawisza możliwe jest trafienie poza zakresem, program sygnalizuje o tym fakcie i potrzebne jest powtórne przeprowadzenie losowania, czyli kolejne naciśnięcie klawisza. Teoretycznie takich powtórek może być nieskończenie wiele, ale prawdopodobieństwo konieczności jest mniejsze niż 50%.
- Maksymalny zakres losowania to od 0 do 9, czyli 10 różnych możliwości.
- Liczba losowanych liczb to najwyżej 5.
Pomysł 1 - system zawierający zegar czasu rzeczywistego z możliwością odczytu setnych sekundy:
Number = -1;
while (Number < 0)
{
CzekajNaNacisniecieKlawisza;
T = BiezacaGodzina;
Digit = PobierzCyfreZSetnejSekundyGodziny(T);
if ((Digit >= 1) && (Dogot <= 6))
{
Number = Digit;
}
}
// Poprawnie wylosowana cyfra to od 1 do 6, prawdopodobieństwo poprawnego losowania to 60% (6 poprawnych cyfr na 10 możliwych).
Inspiracja: W drugiej połowie lat 90. XX wieku miałem elektroniczny zegarek ze stoperem, który teoretycznie odmierzał czas z dokładnością do 1/100 sekundy, uruchamianie i zatrzymywanie następowało poprzez wciśnięcie przycisku. W praktyce, czas 1/10 sekundy jest tak krótki, że ręcznie nie da się zmierzyć czasu zdarzenia z dokładnością do 1/100 sekundy. Również, jak się wymyśli jakąś cyfrę, to nigdy nie udało mi się otrzymać tej cyfry na pozycji setnych. Okazuje się, że można powiedzieć, że jak zatrzymam stoper, to cyfra na pozycji 1/100 będzie przypadkowa, szczególnie, gdy nie patrzy się na wyświetlacz ani nie mierzy się czasu jakiegoś zdarzenia.
Pomysł 2 - system, który nie zawiera zegara czasu rzeczywistego:
Number = -1;
Digit = 0;
while (Number < 0)
{
if (KlawiszNacisniety)
{
if ((Digit >= 1) && (Digit <= 6))
{
Number = Digit;
}
while (KlawiszNacisniety)
{
}
}
Digit = Digit + 1;
if (Digit == 8)
{
Digit = 0;
}
}
// W tym kodzie cyfra może przybrać stan od 0 do 7, skrajne stany nie są ważne (wymuszają ponowne losowanie) po to.
// żeby wyeliminować wpływ zawijania inkrementacji na prawdopodobieństwo trafienia poszczególnych cyfr.
// Poprawnie wylosowana cyfra to od 1 do 6, prawdopodobieństwo poprawnego losowania to 75% (6 poprawnych cyfr na 8 możliwych).
Inspiracja: W latach 90. XX wieku i na początku XXI wieku nieraz brałem udział w zabawie polegającej na wylosowaniu litery i zapisaniu na kartce nazw na tą literę (państwo, miasto, roślina, zwierzę itp). Losowanie przebiega w taki sposób, że jedna osoba wyobraża kolejne litery, a druga osoba mówi "stop", wtedy pierwsza osoba wypowiada wyobrażaną w tym momencie literę. W komputerze, cały alfabet można przejść w ułamku sekundy, a w chwili naciśnięcia klawisza pojawi się litera, która w tym właśnie momencie była w pamięci.
To samo podejście jest w tej grze od miejsca 2:20 do końca nagrania:
Bardzo szybko zmieniają się liczby, liczba przestaje się zmieniać w momencie naciśnięcia przycisku przez gracza.
Inna gra to w momentach 1:38, 2:56, 4:10:
W tej grze, jak na górze jest pokazany rysunek gamepada, to gracz musi nacisnąć przycisk. Łatwo się domyślić, po co to jest (ta konsola nie ma RTC i ma powolny 8-bitowy procesor).
W tym miejscu nie rozważamy realizacji losowania w zakresie większym niż od 0 do 9 ani mniejszym niż od 0 do 5. Chodzi o sam sposób losowania z udziałem użytkownika. Tutaj to użytkownik losuje, a nie komputer jakimś wymyślnym algorytmem.
Czy tak realizowane losowanie da prawdziwie losowe liczby przy założeniu, że jeden cykl (wszystkie możliwe stany) trwa najwyżej 1/10 sekundy?