קישור לחידה המקורית:
https://adventofcode.com/2018/day/11
פיתרון בשפת רובי:
require 'thread/pool'
GRID_SERIAL_NUMBER = ARGV[0]&.to_i || 1955
class FuelCell
attr_accessor :x, :y
def initialize(x, y)
@x = x
@y = y
@sums = {}
end
def print_square(grid, size)
y.upto(y + size - 1) do |yy|
x.upto(x + size - 1) do |xx|
next unless grid.key?([xx, yy])
print " #{grid[[xx, yy]].power} "
end
puts
end
end
def sum_square(grid, size)
return @sums[size] if @sums[size]
@sums[size] = 0
y.upto(y + size - 1) do |yy|
x.upto(x + size - 1) do |xx|
next unless grid.key?([xx, yy])
@sums[size] += grid[[xx, yy]].power
end
end
@sums[size]
end
def power
return @power unless @power.nil?
rack_id = x + 10
@power = rack_id * y
@power += GRID_SERIAL_NUMBER
@power *= rack_id
@power = (power / 100) % 10
@power -= 5
end
def to_s
"#{x},#{y} [#{power}]"
end
end
class Window
attr_accessor :grid, :x, :y, :size, :sum_cols
def initialize(grid, x, y, size)
@grid, @x, @y, @size = grid, x, y, size
@sum_cols = {}
end
def sums
Enumerator.new do |yielder|
loop do
if @x + size >= 300
@y += 1
@x = 1
@sum_cols = @sum_cols.map do |col, v|
[x, v - grid[[col, @y - 1]].power]
end.to_h
end
if @y + size >= 300
break
end
yielder.yield [@x, @y, size, sum]
@x += 1
end
end
end
def sum
(x..(x + size - 1)).reduce(0) {|acc, x| acc + sum_col(x) }
end
def sum_col(col)
return @sum_cols[col] if @sum_cols.key?(col)
@sum_cols[col] = (y..(y + size - 1)).
map {|y| grid[[col, y]] }.
reduce(0) {|acc, cell| acc + cell.power }
end
end
class FuelGrid
attr_reader :grid
def initialize
@grid = {}
1.upto(300) do |y|
1.upto(300) do |x|
@grid[[x, y]] = FuelCell.new(x, y)
end
end
end
def max(size)
cell = @grid.max_by {|k, v| v.sum_square(grid, size) }[1]
res = cell.sum_square(grid, size)
"#{cell} / #{res}"
end
end
pool = Thread.pool(4)
grid = FuelGrid.new
(1..300).each do |size|
pool.process do
w = Window.new(grid.grid, 1, 1, size)
puts w.sums.max_by {|x, y, size, sum| sum }.inspect
end
end
pool.shutdown
כשישבתי בלילה השבוע על התרגיל הזה היתה לי הרגשה שהכל מתחבר והנה תכף מגיעים לסוף, אבל אז הרצתי וגיליתי שהעניין יותר מסובך ממה שנראה במבט ראשון. לקח עוד כמה ימים עד שהיה לי זמן לחזור לזה ולנסות שוב. הפיתרון בגדול משתמש בטכניקה שנקראת חלון צף ואפשר לקרוא עליה קצת כאן: