This puzzle was another easy one, especially for so late in the advent calendar. I don't have much to say about the puzzle or my solution, but it was a fun one.
I guess the one thing I should mention is that I did a thing you're definitely not supposed to do in Crystal. I think it's okay to add methods to an built-in class. This is done simply by "re-defining" the class, which actually "merges" the new methods and properties into the existing class. However, the Array class already has a hash
method, so I'm overriding that method with the new one I created. Instead of converting each array into some custom type, I can simply use built-in functions that return arrays, and call my custom hash method on them.
Here's my code:
input = File.read("input").strip
alias Lens = Tuple(String, Int32)
alias Boxes = Hash(Int32, Array(Lens))
steps = input.split(',')
class String
def hash
self.codepoints.reduce(0) do |hash, char|
(hash + char) * 17 % 256
end
end
end
part1 = steps.map(&.hash).sum
puts part1
part2 = begin
steps = steps.map(&.split(/(-|=)/))
boxes = (0...265).reduce(Boxes.new) do |boxes, box_num|
boxes.merge({box_num => [] of Lens})
end
lenses = Set(String).new
steps.each do |(label, op, value)|
lenses.add(label)
box_num = label.hash
existing = boxes[box_num].index { |x, _| x == label }
if op == "="
if existing.nil?
boxes[box_num].push({label, value.to_i})
else
boxes[box_num][existing] = {label, value.to_i}
end
else
if !existing.nil?
boxes[box_num].delete_at(existing)
end
end
end
lenses.reduce(0) do |sum, lens|
box = boxes[lens.hash]
slot = box.index { |(k, _)| k == lens }
slot.nil? ? sum : sum + ((lens.hash + 1) * (slot + 1) * box[slot][1])
end
end
puts part2
Top comments (0)