Quick Tips: Hvordan tilfeldig Shuffle en Array i AS3

Quick Tips: Hvordan tilfeldig Shuffle en Array i AS3
4
Del
en
Share < .no> Dette Cyber ​​mandag Envato Tuts + kurs vil bli redusert til bare $ 3. Ikke gå glipp av

Noen ganger har du et sett av elementer -. Kan være Strings, kan være tall, kan være objekter, uansett - hvis ordre du vil randomise. Dette er spesielt nyttig for spørrekonkurranser og pengespill, men kommer godt med i alle slags andre programmer. Den enkleste metoden jeg har funnet for å gjøre dette er å holde alle elementene i en matrise og deretter shuffle det som en kortstokk. Men hvordan kan vi gjøre det ...


Som et enkelt eksempel, vil vi bruke bokstavene i alfabetet:?
Var bokstaver: Array = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N "," O "," P "," Q "," R "," S "," T "," U "," V "," W "," X "," Y "," Z "];

Det er ulike tilnærminger vi kan ta for å faktisk sortering denne matrisen



Den Naive Approach

Vi kan lage en ny array, og kopiere hvert element i den første inn. tilfeldig posisjon i det andre:

Koden for som kan se slik ut (se denne Quick Tips på å få et tilfeldig heltall innenfor et bestemt område for mer informasjon):
Var bokstaver: Array = [" A "," B "," C "," D "," E "," F "," G "," H "," I "," J "," K "," L "," M " , "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", " Z "]; Var shuffledLetters: Array = new Array (letters.length); Var randomPos: int = 0; for (var i: int = 0; i < letters.length; i ++) {randomPos = int (Math.random () * letters.length); shuffledLetters [randomPos] = bokstaver [i];}

Men det er ett stort problem. Hva om tilfeldig posisjon plukket for C er seks så vel?

Her, A blir overskrevet, og vil derfor ikke være i stokket array. Det er ikke det vi ønsker, så vi må sjekke at sporet er tom før du kopierer brevet over, og velge et annet spor hvis det ikke:
Var bokstaver: Array = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O "," P "," Q "," R "," S "," T "," U "," V "," W "," X "," Y "," Z "]; Var shuffledLetters: Array = new Array (letters.length); Var randomPos: int = 0; for (var i: int = 0; i < letters.length; i ++) {randomPos = int (Math.random () * letters.length); while (! shuffledLetters [randomPos] = null) //gjenta så lenge sporet er ikke tom {randomPos = int (Math.random () * letters.length); //plukke forskjellige spille} shuffledLetters [randomPos] = bokstaver [i];}

Som fungerer. Problemet er at det er ineffektivt. Se, er bokstaven A garantert til å passe inn i sporet plukket, fordi det er den første bokstaven valgt, slik at alle sporene vil være tom. Med B, det er en 25 i 26 sjanse for at det første sporet plukket vil være tom. Når vi er halvveis gjennom alfabetet, faller denne sjansen til 50/50. Etter den tid vi nå V, det er en 50/50 sjanse for at vi ikke vil finne et tomt spor til fjerde
forsøk.

Dette betyr at vi er svært sannsynlig å kalle Math .random () wayyyyy mer enn 26 ganger. Og Math.random () er en relativt langsom funksjon. Hva er en annen tilnærming kan vi ta?



Midt-Man Approach

Hva om vi lagret en liste over alle de ledige plassene i et tredje
utvalg, som ville krympe som vi gikk gjennom dem?

... og så videre, og repeter til rekken av tomme plasser inneholder ingen elementer. Koden for det ville se slik ut:
Var bokstaver: Array = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U "," V "," W "," X "," Y "," Z "]; Var shuffledLetters: Array = new Array (letters.length); Var emptySlots: Array = new Array (); for (var n : int = 0; n < letters.length; n ++) {emptySlots.push (n);} Var randomPos: Antall = 0; Var actualSlot: Antall = 0; for (var i: int = 0, jeg < bokstaver .length; i ++) {randomPos = int (Math.random () * emptySlots.length); //notat emptySlots.length ikke letters.length actualSlot = emptySlots [randomPos]; shuffledLetters [actualSlot] = bokstaver [i]; emptySlots.splice (randomPos, 1);}

Her bruker vi Array.splice () metode for å fjerne en enkelt element fra listen over ledige plassene. Dette fjerner faktisk element, i stedet for bare å sette verdien til null; så, etter skjøting første sporet, vil emptySlots.length være 25 i stedet for 26.

Dette spleise () -funksjonen er stor; vi kan bruke det for en tredje tilnærming til shuffling som kutter ut dette midt mann array.



spleise Approach

I stedet for å fjerne elementer fra tabellen over tomme plasser når vi er ferdig med dem, kunne vi fjerne dem fra den opprinnelige, unshuffled rekke

Dette høres ikke veldig nyttig først -. men hva om vi plukket elementer fra opprinnelige
rekke tilfeldig I stedet for å plukke sin velsen
tilfeldig?

... og så videre, helt til den første matrisen inneholder ingen elementer.

I motsetning til de to andre tilnærminger, ender vi opp uten den opprinnelige matrisen. Hvorvidt dette er et problem eller ikke, avhenger av dette prosjektet

Koden kan se slik ut:.
Var bokstaver: Array = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q "," R "," S "," T "," U "," V "," W "," X "," Y "," Z "]; Var shuffledLetters: Array = new Array (letters.length ); Var randomPos: Antall = 0; for (var i: int = 0; i < shuffledLetters.length; i ++) //bruke shuffledLetters.length fordi spleise () vil endre letters.length {randomPos = int (Math.random () * letters.length); shuffledLetters [i] = bokstaver [randomPos]; //merk dette den andre veien rundt til naiv tilnærming letters.splice (randomPos, 1);}

Faktisk, siden spleise () returnerer en matrise av alle elementene du er spleising, vi kunne forenkle koden litt :
Var bokstaver: Array = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W "," X "," Y "," Z "]; Var shuffledLetters: Array = new Array (letters.length); Var randomPos: Antall = 0; for (var i: int = 0; i < shuffledLetters.length; i ++) {randomPos = int (Math.random () * letters.length); shuffledLetters [i] = letters.splice (randomPos, 1) [0]; //siden spleise () returnerer en matrise, må vi presisere at vi ønsker den første (bare) element}

Det er penere. Jeg har fått en mer tilnærming til å dele; dette er veldig annerledes enn de andre vi har brukt så langt.



Den Sortering Approach

Arrays har en metode, sort () som standard ordner alle elementene i matrisen i stigende alfabetisk rekkefølge, som så:
Var mixedLetters: Array = ["G", "B", "P", "M", "F"]; mixedLetters.sort (); //mixedLetters er nå ["B", "F", "G", "M", "P"]

Du kan passere alternativer til denne metoden, som Array.DESCENDING, som reverserer rekkefølgen av den typen:
Var mixedLetters: Array = ["G", "B", "P", "M", "F"]; mixedLetters.sort (Array.DESCENDING); //mixedLetters er nå ["P", "M", " G "," F "," B "]

(Det finnes andre alternativer, og du kan sende så mange av dem som du vil.)

Du kan også sende en henvisning til en . funksjon
, som forteller Flash hvordan du skal bestemme hvilken rekkefølge eventuelle to elementene hører hjemme i for eksempel, kan denne funksjonen brukes for numerisk sortering:
funksjon numericalSort (a: Antall, b: Number): Antall {if ( en < b) returnerer -1; if (a == b) return 0; if (a > b) retur 1;}

Flash ser på hvert par av tilstøtende elementer i rekken, og ordner dem i henhold til denne funksjonen: den bytter dem hvis verdien 1 er tilbake, og etterlater dem alene ellers. (Med mindre du passerer Array.DESCENDING samt funksjon, i så fall bytter det dem hvis verdien -1 returneres, og etterlater dem alene ellers.) Flash gjentar dette over hel rekke om og om igjen før alle parene returnere 0 eller -1 (0 eller 1 hvis du bruker Array.DESCENDING).

Vi kan rote med dette. I stedet for å gi det en reell grunn til at noen to elementer skal byttes, kan vi bare fortelle det å bytte dem tilfeldig, bruker en sorteringsfunksjon som dette:
funksjonen randomSort (a: *, b: *): Antall //* all slags innspill {if (Math.random () < 0,5) retur 1; ellers retur 1;}

Easy! Nå kan vi bruke det i vår kode slik:
funksjon randomSort (a: *, b: *): Antall {if (Math.random () < 0,5) retur 1; ellers går tilbake 1;} Var bokstaver: Array = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J" , "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", " W "," X "," Y "," Z "]; letters.sort (randomSort); //(ikke behov for shuffledLetters [] Array)

Vær oppmerksom på at den resulterende matrisen vil ikke være så tilfeldig stokket som de andre tilnærminger vi har brukt - i denne tilnærmingen, er det ikke en enda 1 tjueseksdel sjanse for at alle
gitt brevet vil ende opp i alle
gitt slot. Dette er fordi vi bare bytte tilstøtende par av elementer, og gjør ikke mer enn det. Likevel, det er en ryddig metode :)

Det er nok av andre metoder, vet jeg. Har du noe du liker bedre enn disse

Edit: Her er en flott innlegg med noen veldig kule visualiseringer, forklarer Fisher-Yates shuffle, som arbeider på plass. Jeg anbefaler det! Anmeldelser