On Day 20 we are working with overlapping ranges. Those ranges describe IP addresses that should be blocked. Our goal is to output lowest IP address that is not blocked by firewall.
Our input looks like this:
5-8
0-2
4-7
Here is my solution:
data = File.readlines("20.txt", chomp: true).map { |line| line.split("-").map(&:to_i) }
def overlap?(r1, r2)
(r1[0] <= r2[1] && r1[1] >= r2[0]) || (r1[1] == r2[0] - 1) || (r2[1] == r1[0])
end
data.sort! { |a, b| a[0] <=> b[0] }
index = 0
while index < data.size - 1
if overlap?(data[index], data[index + 1])
a = [data[index][0], data[index + 1][0]].min
b = [data[index][1], data[index + 1][1]].max
data[index] = [a, b]
data.delete_at(index + 1)
else
index += 1
end
end
data.each do |range|
puts range.inspect
end
puts "Lowest-valued IP is #{data[0][1] + 1}"
It is pretty simple. We read ranges from file, we sort them by starting point and then we try to merge neighboring ranges into larges ones. To check if two ranges overlap I used code straight from stack overflow here.
Please note that my solution is not 100% generic, because I am assuming that there is a range starting from one., but it was enough to get the right answer.
In second part we need to tell how many IP addresses are allowed in total. Here is my solution, only slightly modified:
data = File.readlines("20.txt", chomp: true).map { |line| line.split("-").map(&:to_i) }
def overlap?(r1, r2)
(r1[0] <= r2[1] && r1[1] >= r2[0]) || (r1[1] == r2[0] - 1) || (r2[1] == r1[0])
end
data.sort! { |a, b| a[0] <=> b[0] }
index = 0
while index < data.size - 1
if overlap?(data[index], data[index + 1])
a = [data[index][0], data[index + 1][0]].min
b = [data[index][1], data[index + 1][1]].max
data[index] = [a, b]
data.delete_at(index + 1)
else
index += 1
end
end
index = 0
count = 0
while index < data.size - 1
count += (data[index + 1][0] - data[index][1] - 1)
index += 1
end
puts count