Hyvä random-funktio

Olen tekemässä roolipeliä johon tarvitsisin vähän paremman random-funktion kuin tuon tavallisen. Semmoisen joka antaa vähän tasaisemmin noita arvoja esim. jos halutaan satunnaisesti joko arvoa 0 tai 1, niin pitkällä aikavälillä keskiarvo on siinä 0,5... sitten ois myös käyttöä semmoiselle randomille, jolla voi painottaa tiettyjä arvovälejä, eli jos halutaan satunnaisluku välille 0-50, niin voidaan määrittää vaikka väli 0-10 tulemaan kaksi kertaa todennäköisemmin ja väli 11-30 kolme kertaa todennäköisemmin kuin loput 31-50, miksikä tällaista kutsutaan?
81117
Äänestä

Muut lukivat myös

Vastaukset 8

Vanhimmat

Algoritmi riittää...

Äänestä
  • Taulukkoon {0.1, 0.2, 0.3,...}

    Sitten vaihtelet satunnaisesti arvoja keskenään tarpeeksi monta kertaa:

    {0.3, 0.1, 0.2,...}

    Äänestä

  • Normaali random functio laskee aina edellisen luvun perusteella seuraavan luvun. Nyt voitaisiin tehdä suurehko taulukko, johon tallennetaan lukuja. itse tein joskus lottogeneraattorin, jossa minulla oli ihan tavallinen taulukko ja generaattorin arpoma luku toimi indeksinä taulukkoon.

    Jos teet näin niin laitat taulukkoon lukuja. Painotus toimii jos laitat taulukkoon joitain lukuja enemmän.

    Nyt siis random function tuottamalla luvulla ei ole sinällään merkitystä, koska sen perusteella haetaan taulukosta tieto. Ja nyt kun meillä on painotetu tiettyjä lukuja niin tilaston perusteella pitäisi tulla painotettuja lukuja.

    Äänestä

  • teuro kirjoitti:

    Normaali random functio laskee aina edellisen luvun perusteella seuraavan luvun. Nyt voitaisiin tehdä suurehko taulukko, johon tallennetaan lukuja. itse tein joskus lottogeneraattorin, jossa minulla oli ihan tavallinen taulukko ja generaattorin arpoma luku toimi indeksinä taulukkoon.

    Jos teet näin niin laitat taulukkoon lukuja. Painotus toimii jos laitat taulukkoon joitain lukuja enemmän.

    Nyt siis random function tuottamalla luvulla ei ole sinällään merkitystä, koska sen perusteella haetaan taulukosta tieto. Ja nyt kun meillä on painotetu tiettyjä lukuja niin tilaston perusteella pitäisi tulla painotettuja lukuja.

    "Nyt siis random function tuottamalla luvulla ei ole sinällään merkitystä, koska sen perusteella haetaan taulukosta tieto."

    Jos samalla luvulla löytyy aina sama tieto, ei tällä taulukolla ole merkitystä.

    "Normaali random functio laskee aina edellisen luvun perusteella seuraavan luvun."

    Silloinhan se riippuu luvun tarkkuudesta: 16 bittinen kokonaisluku tuottaa korkeintaan 64 tuhatta "satunnaislukua" kunnes se alkaa taas alusta.

    Äänestä

"Hyvä random-funktio Peliä varten..."

Tuo "Peliä varten" saattaa olla avainsana tässä jutussa.

Riippuu hieman, millä välineellä ja mihin käyttöjärjestelmään / ympäristöön olet tekemässä peliäsi.

Määritelläänpä aluksi 2 asiaa:

1. Primäärisatunnaisluku

Satunnainen kokonaisluku väliltä 0 .. N-1


2. Sekundäärisatunnaisluku

Täysin omien kriteeriesi mukainen satunnaisluku, joka voi vaihdella arvoalueeltaan, ja voi olla painotettu niin, että jotkut arvot ovat muita todennäköisempiä.

Tuon sekundäärisatunnaisluvun tuittamiseen primäärisatunnaisluvun perusteella oletkin jo saanut hyviä vinkkejä muilta vastaajilta.

Keskityn siksi tuon primäärisatunnaisluvun generointiin.

esim. moderneista CPU:sta löytyy konekielikäsky RDTSC, joka palauttaa 64-bittisen arvon rekisteriparissa EDX:EAX

esim. Delphi -funktioksi tuon voi ottaa käyttöön näin:

function GetCycleCount : int64; assembler;
{This is minimally invasive and accurate down to about 40 cycles.}

asm

dw $310F {Clock to edx:eax}

end;

Kannattaa ensin hieman tutkia tuon käyttäytymistä: kasvaako se kahdella peräkkäisellä kutsukerralla jollain vakiolla, jos, niin kannattaa tulos joko jakaa tai shr ( C/C++ -koodareille >> ) vakiolla, jolla tuo otetaan huomioon.

Sitten esim. aina, kun näppäin vapautetaan, kutstuaan tuota RDTSC ja laitetaan tulos taulukkoon; tuolta taulukostahan niitä satunnaislukuja sitten saa, kunhan sieltä ei yritä ottaa enemmän kuin sinne on kertynyt.

Tuo näppäimen vapautus on liipaisimena parempi kuin painallus, näin vältät näppimen automaattitoiston aiheuttamat tasavälein tulevat keskeytykset / viestit.

siis esim Delphissä formille näin:

procedure WMKeyUp(Msg : TMessage); message WM_KeyUp;

ja jos laittaa formille niin KeyPreView := True;

Delphisäs tuo aiheuttaisi sen, että formin metodia WMKeyUp kutsutaan aina, kun näpopäin vapautetaan, joten tuossa metodissa sitten vain kutsutaan RDTSC:tä.

Toinen vaihtoehto voisi olla erillinen säie pyörittämään silmukkaa, jossa arvoa kasvatetaan yhdellä, ja nollataan, jos tuli liian suureksi; toki voi tehdä toisinpäin eli asetetaan alkuarvoon, kun on pienennetty 0:ksi (tai negatiiviseksi).

Jos kyse on windows -pelistä, niin myös pääviestisilmukan GetMessage:n korvaus PeekMessagella luo tuollaisen jatkuvasti pyörivän silmukan.

HUOM: Jos teet tuon, niin windowsissa laita ehto, että jos ei ole viestejä käsiteltäväksi, niin sleep(1);

tuo "nukuttaa" ohjelman pääsäikeen 1 ms ajaksi; tuo tuhannesosasekunti on niin lyhyt aika, ettei taatusti häiritse hidastamalla peliä, mutta jos ajat peliäsi varsinkin kannettavassa tietokoneessa, joissa usein on termostaattiohjattu CPU -tuuletin, niin tuo PeekMessage -(peli)silmukan käyttö ilman tuota sleep(1) -kutsua nostaa CPU -käytön koko pelin ajaksi 100%:iin, jolloin CPU lämpenee ja CPU-tuuletin joutuu pyörimään jatkuvasti täysillä.

Sensijaan Sleep(1) -käyttämällä CPU -kulutus putoaa varsin kohtuullisiin lukemiin, nykyisillä nopeilla prosessoreilla jopa alle 1% silloin, kun ei ole muuta raskasta tehtävää.

em. Sleep(1) -kutsun unohtaminen on muuten yksi yleisimmistä peliohjelmoijien tekemistä virheistä, ehkä siksi, että jokin vuosien takainen peliohjelmointiopas ei huomauta asiasta, mutta se mikä oli ok 4,77 MHz ikivanhalla 8086:lla, ei aina ole hyvä idea modernilla yli 1 GHz CPU:lla.

Jos taas koodaat Linuxilla, niin tuon sleep:in sijaan koodaa itse SleepMs -funktio käyttämällä apuna nanosleep -funktiota.

Windowsissa kun Sleep(1000) nukuuisi sekunnin, mutta Linuxissa Sleep(1000) nukkuu 1000 s eli 16 min 40 sek.

Eli siis toisistaan riippumattomat ajalliset tapahtumat tarjoavat hyvän ratkaisun, jos satunnaislukuja tarvitaan vain kohtuullinen määrä:

1. Näppäimenvapautukset (em. syistä parempi kuin -painallukset)

2. Säikeessä pyörivä silmukka; tähänkin pätee tuo sleep -funktion käyttö

3. Viestisilmukka PeekMessagella (Windows); linuxissa tuohon varmasti on myös omat keinonsa, mutta linuxissa käyttöliitymän käsittely on varsin poikkeavaa windowsiin verrattuna.

selaimessa toimivat JavaScript -pelit ovat sitten ihan oma lukunsa.

Äänestä
  • Linuxissa ja Unixeissa on C:ssä usleep, nanosleep ja sleep-funktiot. Mikrosekunteja usleep, nanosekunteja nanosleep ja sekunteja sleep.

    Äänestä

Heti kivikauden jälkeen satunnaislukujen laatua parannettiin yhdistämällä ne sopivalla funktiolla kellon lukemaan.
Systeemi johtui siitä, ettei silloin windowsissa saanut oikeita satunnaislukuja, koska satunnaislukua tuottava käsky vain nouti jostain taulukosta aina seuraavan arvon. Ongelma oli se, että lista oli aina sama ja alkoi alusta kun ohjelman käynnisti uudelleen.
Väittävät että joku voitti jollain pelilaitteella runsaasti rahaa, kun oli tajunnut miten ohjelma toimi.

Ratkaisu oli käyttää apuna kelloa lisäämässä satunnaisuutta.

Äänestä

Mersenne Twister on hyvä, jos et tarvitse kryptografiaan satunnaislukujasi. Siihen se ei riitä, mutta peliisi on varmasti hyvä. Googlaa se, on esimerkkikoodia eri kielillä. Siinä on tosi pitkä periodi ja se läpäisee hyvin esim. diehard-testit, joten pseudosatunnaisluvuilla tuskin paljon parempaa onkaan.

Ihan oikeita satunnaislukuja saat random.org:ista tai jostain hardwaren kautta. Lieneekö järkevää mennä niin pitkälle.

http://www.random.org/

"sitten ois myös käyttöä semmoiselle randomille, jolla voi painottaa tiettyjä arvovälejä"

Tätä varten sinun täytyy hieman opiskella matematiikkaa. Täällä on palsta, (Tiede > Matematiikka) jolla auttavat, jos ei heti lähde luistamaan. Todennäköisyysmatematiikassa tutkitaan näitä ongelmia, ja sieltä löytyy monenlaista todennäköisyysjakaumaa, joilla voi mallintaa erilaisia tapahtumia kivasti. Parasta siis kysyä asiantuntijalta tästä, koska asiat on jo mietitty aika pitkälle.

Yleinen idea on, että jos saat helposti aikaan sen tasaisen jakauman, minkä vaikka tuo MT antaa, niin kuvaamalla sen sopivien funktioiden läpi saat jonkin muun jakauman. Sopivan funktion keksiminen on vaikeaa, mutta kuten sanoin, siihen on monia tuttuja ratkaisuja.

Probability distribution on englanninkielinen hakusana. Tässä kaikki tällä erää.

Äänestä

Kommentoi aloitusta


Peliä varten kirjoitti:

Olen tekemässä roolipeliä johon tarvitsisin vähän paremman random-funktion kuin tuon tavallisen. Semmoisen joka antaa vähän tasaisemmin noita arvoja esim. jos halutaan satunnaisesti joko arvoa 0 tai 1, niin pitkällä aikavälillä keskiarvo on siinä 0,5... sitten ois myös käyttöä semmoiselle randomille, jolla voi painottaa tiettyjä arvovälejä, eli jos halutaan satunnaisluku välille 0-50, niin voidaan määrittää vaikka väli 0-10 tulemaan kaksi kertaa todennäköisemmin ja väli 11-30 kolme kertaa todennäköisemmin kuin loput 31-50, miksikä tällaista kutsutaan?

Anonyymi
5000

Ilmoita asiaton sisältö

  • Sisältää materiaalia, joka on loukkaavaa, herjaavaa, rasistista, uhkailevaa tai ahdistelevaa.

  • Materiaali sisältää nimiä, yhteystietoja tai muita henkilökohtaisia tietoja. Julkisuuden henkilöistä, julkisissa viroissa toimivista ihmisistä sekä yritysten vastuuhenkilöistä saa keskustella työhön liittyen. Myös yksityiselämään liittyvistä asioista voi keskustella siltä osin, kuin niistä on julkisesti kerrottu.

  • Sisältää lapsille haitallista tai heiltä kiellettyä materiaalia. Seksuaalinen sisältö on sallittua aiheeseen tarkoitetuilla palstoilla, joiden ikäraja on 18 vuotta.

  • Lainvastaista sisältöä voi olla mm. yksityiselämää loukkaavan tiedon levitys, kiihottaminen kansanryhmää vastaan, laiton uhkaaminen, alaikäisiin liittyvä seksuaalinen sisältö/grooming, petokset, identiteettivarkaudet, kunnianloukkaukset ja tekijänoikeusrikkomukset.

  • Sisältö ei liity palstan tai keskusteluketjun aiheeseen.

  • Viesti ei ole suomea tai ruotsia (pl. International Forums), se sisältää mainontaa, se sisältää tekijänoikeuksin suojattua materiaalia, se on massapostitus tai jokin muu syy.

Jaa keskustelu