Решение на Шеста задача от Христо Банчев

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

Към профила на Христо Банчев

Резултати

  • 5 точки от тестове
  • 0 бонус точки
  • 5 точки общо
  • 16 успешни тест(а)
  • 2 неуспешни тест(а)

Код

module GameOfLife
class Board
include Enumerable
attr_writer :cells
def initialize *cells
@cells = Hash.new false
cells.each { |x| @cells[x] = true }
@mutator = CellMutator.new(@cells)
end
def each
@cells.keys.each { |key| yield key }
end
def [] x, y
@cells[[x,y]] == true
end
def count
@cells.select { |k, v| v == true }.size
end
def next_generation
next_generation = Board.new
next_generation.cells = @mutator.mutate
next_generation
end
end
class AliveNeighbourCounter
def initialize cells
@cells = cells
end
def count cell
neighbour_coordinates(cell).inject(0) { |sum, neighbour| @cells[neighbour] ? sum + 1 : sum }
end
def dead_neighbours cell
neighbour_coordinates(cell).select { |neighbour| @cells[neighbour] == false }
end
private
def neighbour_coordinates cell
x, y = cell
[[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
end
class CellMutator
def initialize cells
@old_generation = cells.dup
@new_generation = cells.dup
@alive_counter = AliveNeighbourCounter.new(@old_generation)
end
def mutate
kill_loners_and_stars
breed_new_cells
@new_generation
end
private
def kill_loners_and_stars
should_die = @old_generation.keys.select do |cell|
neighbours = @alive_counter.count(cell)
neighbours < 2 or neighbours > 3
end
should_die.each { |cell| @new_generation.delete cell }
end
def breed_new_cells
keys = @old_generation.keys
for_testing = keys.inject([]) { |all, cell| all | @alive_counter.dead_neighbours(cell) }
should_breed = for_testing.select { |cell| @alive_counter.count(cell) == 3 }
should_breed.each { |cell| @new_generation[cell] = true }
end
end
end

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

................FF

Failures:

  1) GameOfLife::Board GameOfLife::Board evolution rules oscilates the oscilators
     Failure/Error: board.count.should eq cells.count
       
       expected: 3
            got: 0
       
       (compared using ==)
     # /tmp/d20111221-3114-ombuzi/spec.rb:172:in `expect_generation_in'
     # /tmp/d20111221-3114-ombuzi/spec.rb:145:in `block (5 levels) in <top (required)>'
     # /tmp/d20111221-3114-ombuzi/spec.rb:142:in `times'
     # /tmp/d20111221-3114-ombuzi/spec.rb:142:in `block (4 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  2) GameOfLife::Board GameOfLife::Board evolution rules keeps stable formations stable
     Failure/Error: board.count.should eq cells.count
       
       expected: 4
            got: 0
       
       (compared using ==)
     # /tmp/d20111221-3114-ombuzi/spec.rb:172:in `expect_generation_in'
     # /tmp/d20111221-3114-ombuzi/spec.rb:160:in `block (6 levels) in <top (required)>'
     # /tmp/d20111221-3114-ombuzi/spec.rb:158:in `times'
     # /tmp/d20111221-3114-ombuzi/spec.rb:158:in `block (5 levels) in <top (required)>'
     # /tmp/d20111221-3114-ombuzi/spec.rb:155:in `each'
     # /tmp/d20111221-3114-ombuzi/spec.rb:155:in `block (4 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

Finished in 0.33297 seconds
18 examples, 2 failures

Failed examples:

rspec /tmp/d20111221-3114-ombuzi/spec.rb:139 # GameOfLife::Board GameOfLife::Board evolution rules oscilates the oscilators
rspec /tmp/d20111221-3114-ombuzi/spec.rb:151 # GameOfLife::Board GameOfLife::Board evolution rules keeps stable formations stable

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

Христо обнови решението на 20.12.2011 22:55 (преди над 8 години)

+module GameOfLife
+ class Board
+ include Enumerable
+
+ attr_writer :cells
+
+ def initialize *cells
+ @cells = Hash.new false
+ cells.each { |x| @cells[x] = true }
+ @mutator = CellMutator.new(@cells)
+ end
+
+ def each
+ @cells.keys.each { |key| yield key }
+ end
+
+ def [] x, y
+ @cells[[x,y]] == true
+ end
+
+ def count
+ @cells.select { |k, v| v == true }.size
+ end
+
+ def next_generation
+ next_generation = Board.new
+ next_generation.cells = @mutator.mutate
+ next_generation
+ end
+ end
+
+ class AliveNeighbourCounter
+ def initialize cells
+ @cells = cells
+ end
+
+ def count cell
+ neighbour_coordinates(cell).inject(0) { |sum, neighbour| @cells[neighbour] ? sum + 1 : sum }
+ end
+
+ def dead_neighbours cell
+ neighbour_coordinates(cell).select { |neighbour| @cells[neighbour] == false }
+ end
+
+ private
+
+ def neighbour_coordinates cell
+ x, y = cell
+ [[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
+ end
+
+ class CellMutator
+ def initialize cells
+ @old_generation = cells.dup
+ @new_generation = cells.dup
+ @alive_counter = AliveNeighbourCounter.new(@old_generation)
+ end
+
+ def mutate
+ kill_loners_and_stars
+ breed_new_cells
+ @new_generation
+ end
+
+ private
+
+ def kill_loners_and_stars
+ should_die = @old_generation.keys.select do |cell|
+ neighbours = @alive_counter.count(cell)
+ neighbours < 2 or neighbours > 3
+ end
+ should_die.each { |cell| @new_generation.delete cell }
+ end
+
+ def breed_new_cells
+ keys = @old_generation.keys
+ for_testing = keys.inject([]) { |all, cell| all | @alive_counter.dead_neighbours(cell) }
+ should_breed = for_testing.select { |cell| @alive_counter.count(cell) == 3 }
+ should_breed.each { |cell| @new_generation[cell] = true }
+ end
+ end
+end

Здравейте, много бих се радвал ако счетете една малка промяна в кода, получена от ненавременна оптимизация:

Ако в първоначално публикувания код в метода Board#new_generation се замени редът next_generation.cells = @mutator.generate с next_generation.cells = @mutator.mutate ще работи нормално.

Явно оптимизациите в последния момент могат да счупят цялата програма... :)

Поздрави! Христо