require_relative 'util' # --- Day 7: Internet Protocol Version 7 --- # While snooping around the local network of EBHQ, you compile a list # of IP addresses (they're IPv7, of course; IPv6 is much too # limited). You'd like to figure out which IPs support TLS # (transport-layer snooping). # An IP supports TLS if it has an Autonomous Bridge Bypass Annotation, # or ABBA. An ABBA is any four-character sequence which consists of a # pair of two different characters followed by the reverse of that # pair, such as `xyyx` or `abba`. However, the IP also must not have # an ABBA within any hypernet sequences, which are contained by square # brackets. # For example: # - `abba[mnop]qrst` supports TLS (`abba` outside square brackets). # - `abcd[bddb]xyyx` does not support TLS (`bddb` is within square # brackets, even though `xyyx` is outside square brackets). # - `aaaa[qwer]tyui` does not support TLS (`aaaa` is invalid; the # interior characters must be different). # - `ioxxoj[asdfgh]zxcvbn` supports TLS (`oxxo` is outside square # brackets, even though it's within a larger string). # How many IPs in your puzzle input support TLS? input = File.open('07.txt') { |f| f.readlines.map(&:chomp) } def abba?(string) string[/(.)(.)\2\1/] && $1 != $2 end assert(abba?('xyyx')) assert(abba?('abba')) def supports_tls?(address) parts = address.chars.slice_when { |x, y| x == '[' || y == ']' }.map(&:join) segments, sequences = parts.partition { |p| p[0] == ']' || p[-1] == '[' } sequences.none? { |s| abba?(s) } && segments.any? { |s| abba?(s) } end assert(supports_tls?('abba[mnop]qrst')) assert(!supports_tls?('abcd[bddb]xyyx')) assert(!supports_tls?('aaaa[qwer]tyui')) assert(supports_tls?('ioxxoj[asdfgh]zxcvbn')) def easy(input) input.count { |line| supports_tls?(line) } end puts "easy(input): #{easy(input)}" # --- Part Two --- # You would also like to know which IPs support SSL (super-secret # listening). # An IP supports SSL if it has an Area-Broadcast Accessor, or ABA, # anywhere in the supernet sequences (outside any square bracketed # sections), and a corresponding Byte Allocation Block, or BAB, # anywhere in the hypernet sequences. An ABA is any three-character # sequence which consists of the same character twice with a different # character between them, such as xyx or aba. A corresponding BAB is # the same characters but in reversed positions: yxy and bab, # respectively. # For example: # - `aba[bab]xyz` supports SSL (`aba` outside square brackets with # corresponding bab within square brackets). # - `xyx[xyx]xyx` does not support SSL (`xyx`, but no corresponding # `yxy`). # - `aaa[kek]eke` supports SSL (`eke` in supernet with corresponding # `kek` in hypernet; the `aaa` sequence is not related, because the # interior character must be different). # - `zazbz[bzb]cdb` supports SSL (`zaz` has no corresponding `aza`, # but `zbz` has a corresponding `bzb`, even though `zaz` and `zbz` # overlap). # How many IPs in your puzzle input support SSL? def abas(string) string.chars.each_cons(3).select { |x, y, z| x == z && x != y }.map(&:join) end def bab?(string, aba) bab = aba[1] + aba[0] + aba[1] string.include?(bab) end assert(!abas('xyx').empty?) assert(!abas('aba').empty?) assert(bab?('yxy', abas('xyx')[0])) assert(bab?('bab', abas('aba')[0])) def supports_ssl?(address) parts = address.chars.slice_when { |x, y| x == '[' || y == ']' }.map(&:join) segments, sequences = parts.partition { |p| p[0] == ']' || p[-1] == '[' } abas = sequences.flat_map { |seq| abas(seq) } segments.any? { |seg| abas.any? { |aba| bab?(seg, aba) } } end assert(supports_ssl?('aba[bab]xyz')) assert(!supports_ssl?('xyx[xyx]xyx')) assert(supports_ssl?('aaa[kek]eke')) assert(supports_ssl?('zazbz[bzb]cdb')) def hard(input) input.count { |line| supports_ssl?(line) } end puts "hard(input): #{hard(input)}"