[2020][ruby][11.x] refactor
change ykwtmvowtpxkwtpsuoumnrrmvkzpvvxn
commit 618c99d83feca59cec56f0611f641ddec10cfe50
author Alpha Chen <alpha@kejadlen.dev>
date
parent vzwnqqqm
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)