On Day 15 we are dealing with a stack of spinning discs with slots. If we press a button then a capsule is dropped and it goes through the slots in those discs. If the discs are not aligned then the capsule bounces back. Our input looks like this:
Disc #1 has 5 positions; at time=0, it is at position 4.
Disc #2 has 2 positions; at time=0, it is at position 1.
We need find a time when we can press the button and get the capsule.
This task is a bit confusing. When I was writing this article I already forgot what is it about and then had to spend additional time to figure out what you need to do.
Let me try to explain in different words. We have those discs that are at a given position and they shift to the next position in each second. Then we have a capsule that drops and reaches each first disc at second 1, second disc at second 2, third disc at second 3 and so on. So when capsule will reach first disc it will move just once, second disc will move two times, third disc will move three times and so on.
So what we can do in the beginning is move each disc by that many times so it is in the position when capsule will reach it if we press button at time 0.
We move first disc one time, we move second disc two times etc. This is the final alignment if we press button at time 0. To get the capsule all discs must be at position 0. If that’s not the case we just need to move all discs one and check again. And repeat it until we reach a perfect alignment.
Here is the code:
@data = File.
readlines("15a.txt", chomp: true).
map do |line|
match = line.match(/Disc \#\d+ has (\d+) positions; at time=0, it is at position (\d+)\./)
[match[1].to_i, match[2].to_i]
end
def move_disc(disc)
@data[disc - 1][1] = (@data[disc - 1][1] + 1) % @data[disc - 1][0]
end
def aligned?
@data.all? { |disc| disc[1] == 0 }
end
def move_all
@data.size.times do |disc|
move_disc(disc)
end
end
@data.size.times do |i|
(i + 1).times { move_disc(i + 1) }
end
time = 0
while true
if aligned?
puts @data.inspect
puts "All discs are aligned at time #{time}"
break
end
move_all
time += 1
end
In Part B we have one more disc, so it takes a bit longer to calculate the answer. But the code is the same