require_relative 'util' # --- Day 20: Firewall Rules --- # You'd like to set up a small hidden computer here so you can use it # to get back into the network later. However, the corporate firewall # only allows communication with certain external IP addresses. # You've retrieved the list of blocked IPs from the firewall, but the # list seems to be messy and poorly maintained, and it's not clear # which IPs are allowed. Also, rather than being written in # dot-decimal notation, they are written as plain 32-bit integers, # which can have any value from 0 through 4294967295, inclusive. # For example, suppose only the values 0 through 9 were valid, and # that you retrieved the following blacklist: # 5-8 # 0-2 # 4-7 # The blacklist specifies ranges of IPs (inclusive of both the start # and end value) that are not allowed. Then, the only IPs that this # firewall allows are 3 and 9, since those are the only numbers not in # any range. # Given the list of blocked IPs you retrieved from the firewall (your # puzzle input), what is the lowest-valued IP that is not blocked? input = File.open('20.txt', &:readlines).map(&:chomp) def parse(line) start, stop = line.split('-').map(&:to_i) Range.new(start, stop) end def intersection?(a, b) a.include?(b.begin) end def intersection(a, b) Range.new([a.begin, b.begin].min, [a.end, b.end].max) end def sort_ranges(ranges) ranges.sort { |a, b| a.begin <=> b.begin } end def merge_ranges(ranges) result = [ranges.shift] ranges.each do |range| if intersection?(result[-1], range) result[-1] = intersection(result[-1], range) else result << range end end result end def preprocess(lines) ranges = lines.map { |line| parse(line) } merge_ranges(sort_ranges(ranges)) end def easy(input) ranges = preprocess(input) ip = 0 loop do range = ranges.shift return ip unless range.include?(ip) ip = range.end + 1 end end assert(easy(['5-8', '0-2', '4-7']) == 3) puts "easy(input): #{easy(input)}" # --- Part Two --- # How many IPs are allowed by the blacklist? def hard(input) ranges = preprocess(input) 2**32 - ranges.map(&:size).sum end puts "hard(input): #{hard(input)}"