[2020][ruby][11.x] refactor
diff --git a/2020/ruby/day_11.rb b/2020/ruby/day_11.rb
index 1328360..9930129 100644
--- a/2020/ruby/day_11.rb
+++ b/2020/ruby/day_11.rb
@@ -1,72 +1,90 @@
-layout = ARGF.read.split("\n").map(&:chars)
-Y_MAX = layout.size
-X_MAX = layout.first.size
+class Layout
+ def self.from(raw, &logic)
+ seats = Hash.new
+ raw.split("\n").each.with_index do |row,y|
+ row.chars.each.with_index do |pos,x|
+ seats[[y,x]] = false if pos == ?L
+ end
+ end
+ self.new(seats, &logic)
+ end
-# NEIGHBORS = (-1..1).flat_map {|y| (-1..1).map {|x| [y, x] }} - [[0, 0]]
+ attr_reader :seats, :y_max, :x_max
-# def tick(layout)
-# (0...Y_MAX).map {|y|
-# (0...X_MAX).map {|x|
-# occupied = NEIGHBORS
-# .map {|dy,dx| [y+dy, x+dx] }
-# .select {|y,x| (0...Y_MAX).cover?(y) && (0...X_MAX).cover?(x) }
-# .select {|y,x| layout[y][x] == ?# }
-# .count
-# case layout[y][x]
-# when ?.
-# ?.
-# when ?L
-# occupied == 0 ? ?# : ?L
-# when ?#
-# occupied >= 4 ? ?L : ?#
-# else
-# fail
-# end
-# }
-# }
-# end
+ def initialize(seats, &logic)
+ @seats, @logic = seats, logic
+ @y_max = @seats.keys.map(&:first).max
+ @x_max = @seats.keys.map(&:last).max
+ end
-DIRS = (-1..1).flat_map {|y| (-1..1).map {|x| [y, x] }} - [[0, 0]]
+ def [](yx)
+ @seats[yx]
+ end
-def tick(layout)
- (0...Y_MAX).map {|y|
- (0...X_MAX).map {|x|
- next ?. if layout[y][x] == ?.
- occupied = DIRS
- .map {|dy,dx|
- (1..)
- .lazy
- .map {|i| [dy*i+y, dx*i+x] }
- .map {|y,x|
- if (0...Y_MAX).cover?(y) && (0...X_MAX).cover?(x)
- layout[y][x]
- else
- nil
- end
- }
- .find {|s| s != ?. }
- }
- .select {|s| s == ?# }
- .count
- case occupied
- when 0
- ?#
- when (5..)
- ?L
- else
- layout[y][x]
- end
- }
- }
-end
+ def each
+ return enum_for(__method__) unless block_given?
-loop do
- next_layout = tick(layout)
- break if next_layout == layout
- layout = next_layout
+ loop do
+ yield self
+ seats = tick(&@logic)
+ break if seats == @seats
+ @seats = seats
+ end
+ end
- puts layout.map(&:join).join("\n")
- puts
+ def tick
+ @seats.keys.map {|yx|
+ [yx, @logic[self, yx]]
+ }.to_h
+ end
+
+ def to_s
+ (0..@y_max).map {|y|
+ (0..@x_max).map {|x|
+ case @seats[[y,x]]
+ when true then ?#
+ when false then ?L
+ when nil then ?.
+ else fail
+ end
+ }.join
+ }.join("\n")
+ end
end
-p layout.map {|row| row.count(?#) }.sum
+NEIGHBORS = (-1..1).flat_map {|y| (-1..1).map {|x| [y, x] }} - [[0, 0]]
+day1 = ->(layout, yx) {
+ y, x = yx
+ occupied_neighbors = NEIGHBORS.filter_map {|dy,dx| layout[[y+dy, x+dx]] }
+ if !layout[yx] && occupied_neighbors.empty?
+ true
+ elsif layout[yx] && occupied_neighbors.size >= 4
+ false
+ else
+ layout[yx]
+ end
+}
+
+day2 = ->(layout, yx) {
+ y, x = yx
+ occupied_neighbors = NEIGHBORS.filter_map {|dy,dx|
+ (1..).lazy
+ .map {|i| [y+dy*i, x+dx*i] }
+ .find {|y,x|
+ !(0..layout.y_max).cover?(y) ||
+ !(0..layout.x_max).cover?(x) ||
+ layout.seats.has_key?([y, x])
+ }
+ }.filter_map {|yx| layout[yx] }
+ if !layout[yx] && occupied_neighbors.empty?
+ true
+ elsif layout[yx] && occupied_neighbors.size >= 5
+ false
+ else
+ layout[yx]
+ end
+}
+
+layout = Layout.from(ARGF.read, &day2)
+layout.each.take_while(&:itself).last
+puts layout.seats.count(&:last)