Problem statement on the Advent of Code website.
Code for this post can be found on GitHub.
On Day 7, we will figure out which of the EBHQ's computers use encryption on the network.
For Part 1, we need to find the IP addresses (aka computers) that support the TLS (transport-layer snooping) protocol.
We determine this by parsing the IP address and checking for certain patterns.
When I read the problem description, Day 7 sounded very similar, at least in form, to the Day 4 problem.
The problem has multiple parts:
The first part of the problem is understanding the format of the IP address. IP addresses are strings of characters alternating between being outside and inside square brackets. Here are some examples of IP addresses:
This solution, just like the Day 4 solution, stretched and expanded my regular expression skills. I would like to thank Will Boyd for the Regex Storm Regex Tester. This site made it much faster and easier to quickly test a regular expression (and its expected results) against a corpus of test data.
After a number of attempts, I ended up with two sets of regular expressions.
For supernet strings (whose proper name I did not know until Part 2), I used the following strategy:
let outerStrings = Regex.Replace (str, @"\[\w+\]", " ") |> fun s -> s.Split ([|' '|])
For hypernet strings, I used the following strategy:
let hypernetStrings = Regex.Matches (str, @"\[\w+\]") |> Seq.cast |> Seq.map (fun (m:Match) -> Regex.Match(m.Value, @"\w+")) |> Seq.cast<Match> |> Seq.map (fun x -> x.Value)
An ABBA (Autonomous Bridge Bypass Annotation) pattern is a palindrome of exactly 4 characters within a string of length 4 or more.
let isABBA (str:string) = str |> Seq.windowed 4 |> Seq.exists (fun s -> s. = s. && s. = s. && s. <> s.)
For Part 1, we have two primary requirements.
The check for this is a one-liner.
(Seq.exists isABBA outerStrings) && (Seq.exists isABBA hypernetStrings |> not)
The final function that puts it all together is responsible for the following.
let day7part1 filename = File.ReadAllLines filename |> Seq.filter supportsTLS |> Seq.length
When you run this function, you get
105, which is the correct number of IP addresses that support TLS.
In Part 2, we have to determine which IP addresses support the SSL (super-secret listening) protocol.
The problem for Part 2 keeps the concept of supernet and hypernet sequences, but it changes the checks we need to perform on them. Instead of checking for ABBAs, we have to now check for ABAs and their dependent BABs.
Part 2 introduces two new types of patterns in IP addresses:
The requirements are as follows.
My strategy for the Part 2 solution has slightly different steps.
Extracting the supernet and hypernet sequences from an IP address follows exactly the same logic as the Part 1 problem. I extracted this code into two new functions and refactored the Part 1 code to use these new functions.
/// Extract supernet sequences from an IP address. let supernetSeq ip = Regex.Replace (ip, @"\[\w+\]", " ") |> fun s -> s.Split ([|' '|]) /// Extract hypernet sequences from an IP address. let hypernetSeq ip = Regex.Matches (ip, @"\[\w+\]") |> Seq.cast<Match> |> Seq.map (fun m -> Regex.Match(m.Value, @"\w+")) |> Seq.cast<Match> |> Seq.map (fun x -> x.Value)
hasABA takes a
string of any length and tries to find at least one 3-character substring which matches the ABA pattern, which is:
let hasABA (str:string) = str |> Seq.windowed 3 |> Seq.exists (fun x -> x. = x. && x. <> x.)
To check if a hypernet sequence contains a BAB, I decided to use the
Set collection. My overall strategy is as follows.
First (and third), here is the code to get ABAs (or BABs) from IP addresses.
let getABAs (str:string) = str |> Seq.windowed 3 |> Seq.map (System.String) |> Seq.filter hasABA
Second, here is the code to flip an ABA.
let flipABA (str:string) = sprintf "%c%c%c" str. str. str.
Finally, I connected these pieces in the
let hasBAB abas hnStr = let babs = hnStr |> getABAs |> Set.ofSeq abas |> Set.ofSeq |> Set.map flipABA |> Set.intersect babs |> (Set.isEmpty >> not)
supportsSSL is responsible for ensuring that the supernet sequences contains at least one ABA and that the hypernet sequences contain at least one BAB.
let supportsSSL line = let abas = supernetSeq line |> Seq.collect getABAs (supernetSeq line |> Seq.exists hasABA) && (hypernetSeq line |> Seq.exists (hasBAB abas))
The last function,
day7part2, is responsible for linking the input file to
supportsSSL and for calculating the final answer (i.e. the number of IP addresses that support SSL).
let day7part2 filename = File.ReadAllLines filename |> Seq.filter supportsSSL |> Seq.length
Thanks to Day 7 being a relatively simple problem, my goal here was to expand my knowledge of testing.
ints) other than through rather rudimentary methods.
See you next time!