Решение на Шеста задача от Ивайло Петров

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

Към профила на Ивайло Петров

Резултати

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

Код

require 'set'
module GameOfLife
class Board
include Enumerable
def initialize *live_cells
@live_cells = live_cells.to_set
end
def each &block
@live_cells.each(&block)
end
def [] x, y
@live_cells.include? [x, y]
end
def next_generation
new_cells = []
each do |x, y|
new_cells += next_generation_neighbours(x, y)
end
Board.new *new_cells
end
def neighbours_count x, y
valid_neighbours = neighbours(x, y).map do |neighbour_x, neighbour_y|
# I would rather use if, but I can not affort three lines of code and I don't
# want another method for this, so I'll stick with this not so beautiful line
(neighbour_x != x or neighbour_y != y and self[neighbour_x, neighbour_y]) ? 1 : 0
end
valid_neighbours.inject(&:+)
end
def neighbours x, y
[*-1..1].product([*-1..1]).map { |move_x, move_y| [move_x + x, move_y + y] }
end
def next_generation_neighbours x, y
neighbours(x, y).select do |neighbour_x, neighbour_y|
count = neighbours_count(neighbour_x, neighbour_y)
count == 2 and self[neighbour_x, neighbour_y] or count == 3
end
end
end
end

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

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

Finished in 0.43881 seconds
18 examples, 0 failures

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

Ивайло обнови решението на 15.12.2011 02:15 (преди над 8 години)

+require 'set'
+
+module GameOfLife
+ class Board
+ include Enumerable
+
+ def initialize *live_cells
+ @live_cells = live_cells.to_set
+ end
+
+ def each &block
+ @live_cells.each(&block)
+ end
+
+ def [] x, y
+ @live_cells.include? [x, y]
+ end
+
+ def next_generation
+ new_cells = []
+
+ each do |x, y|
+ new_cells += next_generation_neighbours(x, y)
+ end
+
+ Board.new *new_cells
+ end
+
+ def neighbours_count x, y
+ valid_neighbours = neighbours(x, y).map do |neighbour_x, neighbour_y|
+ # I would rather use if, but I can not affort three lines of code and I don't
+ # want another method for this, so I'll stick with this not so beautiful line
+ (neighbour_x != x or neighbour_y != y and self[neighbour_x, neighbour_y]) ? 1 : 0
+ end
+
+ valid_neighbours.inject(&:+)
+ end
+
+ def neighbours x, y
+ [*-1..1].product([*-1..1]).map { |move_x, move_y| [move_x + x, move_y + y] }
+ end
+
+ def next_generation_neighbours x, y
+ neighbours(x, y).select do |neighbour_x, neighbour_y|
+ count = neighbours_count(neighbour_x, neighbour_y)
+
+ count == 2 and self[neighbour_x, neighbour_y] or count == 3
+ end
+ end
+ end
+end

Няколко дребни коментара:

  • Set е добър избор
  • initialize: ... { @live_cells << pair }, понеже надали ще променяш тези двойки впоследствие. Още повече, че може направо @live_cells = args.to_set :) Ако args се очаква да съдържа консистентен тип неща, преименувай го на нещо по-смислено.
  • Стига си dup-вал :) Добра практика е да се внимава, но обикновено който приема аргумента, се грижи да не го модифицира (и да dup-ва, ако трбява); с други думи, подавай спокойно не-dup-нати неща на други функции.
  • Дефинирал си neighbours по забавен начин :)

Като за 3 часа през нощта, толкова коментари :)