Решение на Шеста задача от Михаил Стойков

Обратно към всички решения

Към профила на Михаил Стойков

Резултати

  • 6 точки от тестове
  • 0 бонус точки
  • 6 точки общо
  • 18 успешни тест(а)
  • 0 неуспешни тест(а)

Код

#TODO make it work for n
require 'set'
module GameOfLife
class Board
include Enumerable
def initialize(*generation)
@generation = Set.new generation
end
def next_generation
hash_map = map_neighbors.select do |cell, neighbors|
neighbors == 3 or ( neighbors == 2 and self[*cell] )
end
Board.new *hash_map.keys
end
def each
if (block_given?)
@generation.each { |cell| yield cell }
else
@generation.each
end
end
def [](x, y)
@generation.include? [x, y]
end
def size
@generation.size
end
private
def possible_neighbors(x, y)
[ [x - 1, y + 1], [x , y + 1], [x + 1, y + 1],
[x - 1, y ], [x + 1, y ],
[x - 1, y - 1], [x , y - 1], [x + 1, y - 1]]
end
def map_neighbors
hash = Hash.new 0
each do |cell|
possible_neighbors(*cell).each { |neighbor| hash[neighbor] += 1 }
end
hash
end
end
end

Лог от изпълнението

..................

Finished in 0.36551 seconds
18 examples, 0 failures

История (1 версия и 8 коментара)

Михаил обнови решението на 14.12.2011 19:28 (преди над 12 години)

+#TODO make it work for n
+
+require 'set'
+
+module GameOfLife
+ class Board
+ include Enumerable
+
+ def initialize(*generation)
+ @generation = Set.new generation
+ end
+
+ def next_generation
+ hash_map = map_neighbors.select do |cell, neighbors|
+ neighbors == 3 or ( neighbors == 2 and self[*cell] )
+ end
+ Board.new *hash_map.keys
+ end
+
+ def each
+ if (block_given?)
+ @generation.each { |cell| yield cell }
+ else
+ @generation.each
+ end
+ end
+
+ def [](x, y)
+ @generation.include? [x, y]
+ end
+
+ def size
+ @generation.size
+ end
+
+ private
+
+ def possible_neighbors(x, y)
+ [ [x - 1, y + 1], [x , y + 1], [x + 1, y + 1],
+ [x - 1, y ], [x + 1, y ],
+ [x - 1, y - 1], [x , y - 1], [x + 1, y - 1]]
+ end
+
+ def map_neighbors
+ hash = Hash.new 0
+ each do |cell|
+ possible_neighbors(*cell).each { |neighbor| hash[neighbor] += 1 }
+ end
+ hash
+ end
+ end
+end

Като цяло, решението ти е прилично и вероятно ще мине почти всички тестове :) Само няколко дребни неща:

  • Ако не гониш всяка микросекунда производителност, ползвай +=, вместо Array#concat
  • На втория ред от #next_generation може (трябва) да ползваш each, а не map
  • Би трябвало да получиш метода #count наготово от Enumerable
  • В eachне присвоявай блока на променлива; направо го викай с yield -- по-бързо е и се ползва по-често така; блока се присвоява на променлива само ако трябва да го подадеш на друга функция, която на свой ред евентуално да го вика

цц кои тестове няма да мина :P. Нали няма тестове за скорост защо съм убеден че сложноста е нещо от вида на O(n^5) и към 1000 (живи) клетки ще започне да мисли :). Иначе промених някои неща.

  • съгласен.
  • map е останал от предишното решение (което не работеше)
  • кой да се сети :)
  • реших че все пак ще го предавам на друга функция :)

Въпрос: Enumerable#count от each ли разбира че има n елемента ? защото ако е така ще го върна обратно че поне да не е толкова бавно :) не мисля че е особедно трудно да се разбере какво съм имал предвид и един ред :)

Не, няма тестове за скорост :)

Също така не съм пускал тестовете и не се наемам да кажа какво ще минеш и какво не :) Но това не е най-важното :)

Така за each е по-добре. Само def each(&block), след като слагаш скоби и около другите дефиниции на методи с аргументи (и без интервал преди отварящата скоба — possible_neighbors (... :)

Относно Enumerable#count, в документацията пише как брои. С две думи, ако имаш #size, ще ползва него, иначе ще ги обходи. Само че #count има и допълнителни фийчъри, като например "колко пъти се среща даден елемент" или "за колко елемента блокът, подаден на #count, връща истина`. Според мен, те винаги минават през обхождане.

вече нямам проблеми със скоростта. В случай че не може да ползваме set ще се забави около 5 пъти но няма да умре на 100 поколение :).

някакви други забележки и си търся другo име за possible_neighbors беше просто neighbors, но така next_generation изглежда малко ... странно

Ако ти харесва, пробвай да прекръстиш possible_neighbours на neighbours_of. На мен ми допадат този тип имена.

Това е гадно: if (block_given?). Тези скоби са абсолютно излишни. Нямам идея защо си ги сложил. Също нямам идея защо си усложнил така този each. each не би следвало да работи без блок, да се хвърли грешка в такъв случай би било окей, според мен.

Добре, но не смятам, че е необходимо. Задачата не е да направим нещо, което прилича на Array, а по-скоро на Enumerable. Там не се споменава нищо подобно и смятам, че може да се интерпретира и така, след като би опростило кода.

Иначе няма проблем да го оставиш и в твоя вариант. Аз бих предавал блок надолу, както беше го направил първоначално. Много малко по-бавно е.