Следващата статия е част от поредица. За още статии от тази поредица вижте Клониране на играта 2048 в Ruby. За пълния и окончателен код вижте същността.
Сега, когато знаем как ще работи алгоритъмът, е време да помислим за данните, по които ще работи този алгоритъм. Тук има два основни избора: апартамент масив от някакъв вид или двуизмерен масив. Всеки има своите предимства, но преди да вземем решение, трябва да вземем нещо под внимание.
СУХИ пъзели
Често срещана техника в работата с пъзели, базирани на решетка, където трябва да търсите модели като този е да напишете такъв версия на алгоритъма, която работи върху пъзела отляво надясно и след това завъртете целия пъзел около четири пъти. По този начин алгоритъмът трябва да бъде написан само веднъж и той трябва да работи само отляво надясно. Това драстично намалява сложността и размера на най-трудната част от този проект.
Тъй като ще работим върху пъзела отляво надясно, има смисъл редовете да бъдат представени от масиви. Когато правите двумерен масив в
рубин (или по-точно как искате да бъде адресирано и какво всъщност означават данните), трябва да решите дали искате стек от редове (където всеки ред от решетката е представен от масив) или стек от колони (където всяка колона е масив). Тъй като работим с редове, ще изберем редове.Как се завърта този 2D масив, ще стигнем, след като всъщност конструираме такъв масив.
Конструиране на двумерни масиви
Методът Array.new може да вземе аргумент, определящ размера на масива, който искате. Например, Array.new (5) ще създаде масив от 5 нулеви обекта. Вторият аргумент ви дава стойност по подразбиране, така че Array.new (5, 0) ще ви даде масива [0,0,0,0,0]. И така, как да създадете двуизмерен масив?
Грешен начин и начинът, по който виждам хората да се опитват често, е да кажа Array.new (4, Array.new (4, 0)). С други думи, масив от 4 реда, всеки ред представлява масив от 4 нули. И това изглежда работи в началото. Изпълнете следния код:
Изглежда просто. Направете 4х4 масив от нули, задайте горния ляв елемент на 1. Но го отпечатайте и ние получаваме ...
Тя задава цялата първа колона на 1, какво дава? Когато направихме масивите, първо се обажда най-вътрешното повикване към Array.new, което прави един ред. След това единична препратка към този ред се дублира 4 пъти, за да запълни най-външния масив. След това всеки ред препраща към един и същ масив. Променете един, променете ги всички.
Вместо това трябва да използваме трета начин за създаване на масив в Ruby. Вместо да предадем стойност на метода Array.new, предаваме блок. Блокът се изпълнява всеки път, когато методът Array.new се нуждае от нова стойност. Така че, ако искате да кажете Array.new (5) {get.chomp}, Ruby ще спре и ще поиска въвеждане 5 пъти. Така че всичко, което трябва да направим, е просто да създадем нов масив вътре в този блок. Така завършваме с Array.new (4) {Array.new (4,0)}. Сега нека опитаме отново този тестов случай.
И става точно както бихте очаквали.
Така че въпреки че Ruby няма поддръжка за двумерни масиви, все пак можем да направим това, което ни е необходимо. Само не забравяйте, че масивът от най-високо ниво е в сила препратки към подмасивите и всеки подмасив трябва да се отнася до различен масив от стойности.
Какво представлява този масив зависи от вас. В нашия случай този масив е разположен като редове. Първият индекс е редът, който индексираме, отгоре надолу. За да индексираме горния ред на пъзела, използваме на [0], за да индексираме следващия ред надолу, който използваме на [1]. За да индексираме конкретна плочка във втория ред, използваме на [1] [п]. Въпреки това, ако бяхме решили колони... щеше да бъде същото. Ruby няма идея какво правим с тези данни и тъй като технически не поддържа двумерни масиви, това, което правим тук, е хак. Достъп до него само чрез конвенция и всичко ще се държи заедно. Забравете какво трябва да правят данните под тях и всичко може да се разпадне наистина бързо.