Opprette todimensjonale matriser i Ruby
Gabriele Cirulli
Følgende artikkel er en del av en serie. For flere artikler i denne serien, se Cloning the Game 2048 i Ruby. For den fullstendige og endelige koden, se kjernen.
Nå som vi vet hvordan algoritmen vil fungere, er det på tide å tenke på dataene denne algoritmen vil fungere på. Det er to hovedvalg her: en leilighet array av noe slag, eller en todimensjonal matrise. Hver har sine fordeler, men før vi tar en avgjørelse, må vi ta noe i betraktning.
TØRRE puslespill
En vanlig teknikk i å jobbe med rutenettbaserte puslespill hvor du må se etter mønstre som dette er å skrive én versjon av algoritmen som fungerer på puslespillet fra venstre til høyre og deretter rotere hele puslespillet rundt fire ganger. På denne måten må algoritmen bare skrives én gang, og den må bare fungere fra venstre til høyre. Dette reduserer kompleksiteten og størrelsen dramatisk av den vanskeligste delen av dette prosjektet.
Siden vi skal jobbe med puslespillet fra venstre til høyre, er det fornuftig å ha radene representert av matriser. Når du lager en todimensjonal matrise i Rubin (eller, mer nøyaktig, hvordan du vil at det skal adresseres og hva dataene faktisk betyr), må du bestemme om du vil ha en stabel med rader (hvor hver rad i rutenettet er representert av en matrise) eller en stabel med kolonner (hvor hver kolonne er en matrise). Siden vi jobber med rader, velger vi rader.
Hvordan denne 2D-matrisen roteres, kommer vi til etter at vi faktisk har konstruert en slik matrise.
Konstruere todimensjonale matriser
Array.new-metoden kan ta et argument som definerer størrelsen på matrisen du ønsker. For eksempel, Array.new(5) vil lage en rekke med 5 null objekter. Det andre argumentet gir deg en standardverdi, så Array.new(5, 0) vil gi deg matrisen [0,0,0,0,0] . Så hvordan lager du en todimensjonal matrise?
Feil måte, og måten jeg ser folk ofte prøver på er å si Array.new( 4, Array.new(4, 0) ) . Med andre ord, en matrise med 4 rader, hver rad er en matrise med 4 nuller. Og dette ser ut til å fungere med det første. Kjør imidlertid følgende kode:
Det ser enkelt ut. Lag en 4x4-gruppe med nuller, sett elementet øverst til venstre til 1. Men skriv det ut og vi får...
Det satte hele den første kolonnen til 1, hva gir? Når vi laget matrisene, kalles det innerste kallet til Array.new først, og det blir en enkelt rad. En enkelt referanse til denne raden dupliseres deretter 4 ganger for å fylle den ytterste matrisen. Hver rad refererer da til den samme matrisen. Endre en, endre dem alle.
I stedet må vi bruke tredje måte å lage en matrise på i Ruby. I stedet for å sende en verdi til Array.new-metoden, sender vi en blokk. Blokken utføres hver gang Array.new-metoden trenger en ny verdi. Så hvis du skulle si Array.new(5) { gets.chomp } , vil Ruby stoppe og be om innspill 5 ganger. Så alt vi trenger å gjøre er å lage en ny matrise inne i denne blokken. Så vi ender opp med Array.new(4) { Array.new(4,0) } . La oss nå prøve den testsaken igjen.
Og det gjør akkurat som du forventer.
Så selv om Ruby ikke har støtte for todimensjonale arrays, kan vi fortsatt gjøre det vi trenger. Bare husk at matrisen på øverste nivå holder referanser til undermatrisene, og hver undermatrise skal referere til en annen verdigruppe.
Hva denne matrisen representerer er opp til deg. I vårt tilfelle er denne matrisen lagt ut som rader. Den første indeksen er raden vi indekserer, fra topp til bunn. For å indeksere den øverste raden i puslespillet, bruker vi a[0] , for å indeksere neste rad ned vi bruker a[1] . For å indeksere en bestemt flis i den andre raden, bruker vi a[1][n] . Men hvis vi hadde bestemt oss for kolonner... ville det vært det samme. Ruby har ingen anelse om hva vi gjør med disse dataene, og siden de ikke teknisk støtter todimensjonale arrays, er det vi gjør her et hack. Få tilgang til det kun ved konvensjon, og alt vil holde sammen. Glem hva dataene under skal gjøre, og alt kan falle fra hverandre veldig raskt.