Advent of Code 2016, Day 7: Internet Protocol Version 7

#ruby #advent of code 2016

Part A

On Day 7 we have string parsing and verification again. Our input contains strings in the following format:

abba[mnop]qrst
abcd[bddb]xyyx
aaaa[qwer]tyui
ioxxoj[asdfgh]zxcvbn

Strings are valid only if they contain patterns such as abba, xyyx outside of brackets and don’t contain them within brackets.

Here is the solution:

data = File.readlines("7.txt", chomp: true)

def abba?(string)
  index = 0

  while index <= string.size - 4
    return true if string[index] != string[index + 1] && string[index] == string[index + 3] && string[index + 1] == string[index + 2]
    index += 1
  end

  false
end

def split(address)
  brackets = address.scan(/\[(.+?)\]/).map(&:first)
  non_brackets = address.gsub(/\[.+?\]/, " ").split(" ")

  {
    brackets: brackets,
    non_brackets: non_brackets
  }
end

def valid?(address)
  parts = split(address)

  parts[:brackets].all? { |part| !abba?(part) } && parts[:non_brackets].any? { |part| abba?(part) }
end

valid_addresses = data.select { |address| valid?(address) }

puts valid_addresses.size

abba? method checks if given string contains abba pattern by doing simple iteration. split method is splitting the string into parts within brackets and outside brackets. And finally valid? method is checking if the string is valid. All parts in brackets cannot contain any abba pattern and at least one part outside of brackets should contain it.

Part B

In second part we need to check for another pattern. This time it is aba outside of brackets and then there should be a corresponding bab pattern within brackets. For example you should have xyx outside and yxy within brackets.

Here is the code:

data = File.readlines("7.txt", chomp: true)

def abas(string)
  index = 0
  results = []

  while index <= string.size - 3
    results.push(string[index, 3]) if string[index] == string[index + 2] && string[index + 1] != string[index + 2]
    index += 1
  end

  results
end

def babs?(string, babs)
  index = 0

  while index <= string.size - 3
    return true if string[index] == string[index + 2] && string[index + 1] != string[index + 2] && babs.include?(string[index, 3])

    index += 1
  end

  false
end

def split(address)
  brackets = address.scan(/\[(.+?)\]/).map(&:first)
  non_brackets = address.gsub(/\[.+?\]/, " ").split(" ")

  {
    brackets: brackets,
    non_brackets: non_brackets
  }
end

def valid?(address)
  parts = split(address)

  babs = parts[:non_brackets].flat_map { |part| abas(part).map { |item| aba_to_bab(item) } }

  parts[:brackets].any? { |part| babs?(part, babs) }
end

def aba_to_bab(aba)
  a = aba[0]
  b = aba[1]

  "#{b}#{a}#{b}"
end

valid_addresses = data.select { |address| valid?(address) }

puts valid_addresses.size

We have more methods here. abas method is extracting all aba patterns from the string, babs? is checking if there are any corresponding bab patterns. We also have aba_to_bab to convert aba pattern into corresponding bab. The rest is basically the same.