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