# Advent of Code 2016, Day 20: Firewall Rules

#ruby #advent of code 2016

## Part A

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.

## Part B

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
``````