Advent of Code F# – Day 17

Yan Cui

I help clients go faster for less using serverless technologies.

ps. look out for all my other solutions for Advent of Code challenges here.

 

Day 17

See details of the challenge here.

First, let’s add a hash function (that returns the MD5 as a hexadecimal string as we have done so often this year).

open System.Text
open System.Security.Cryptography
let input = "udskfozm"
let width, height = 4, 4
let md5 = CryptoConfig.CreateFromName("MD5") :?> HashAlgorithm
let hash (input : string) =
let bytes = input |> Encoding.UTF8.GetBytes |> md5.ComputeHash
BitConverter.ToString(bytes).Replace("-", "").ToLower()
view raw Day17_hash.fsx hosted with ❤ by GitHub

Then, add a step function that’ll take a (x, y) position and the path (eg. “hijklDU”) leading up to it and returns the a tuple of new position and path if we’re not going to move off grid. We can then use this to construct the more useful functions to take a step in the up, down, left and right directions.

let inline between low hi x = x >= 0 && x < hi
let step direction (dx, dy) (x, y) path =
if x + dx |> between 0 width && y + dy |> between 0 height
then Some((x+dx, y+dy), path + direction)
else None
let up = step "U" (0, -1)
let down = step "D" (0, 1)
let left = step "L" (-1, 0)
let right = step "R" (1, 0)
view raw Day17_step.fsx hosted with ❤ by GitHub

Now we can put everything together and write a function to find all the paths from (0, 0) to (3, 3) in the grid.

let findPaths input =
[| ((0, 0), input) |]
|> Seq.unfold (fun paths ->
paths
|> Array.filter (fun (pos, _) -> pos <> (3, 3))
|> Array.collect (fun (pos, path) ->
let hashVals = hash path |> Seq.take 4
hashVals
|> Seq.zip [| up; down; left; right |]
|> Seq.choose (fun (f, hashVal) ->
if hashVal > 'a' then f pos path else None)
|> Seq.toArray)
|> function
| [||] -> None
| next -> Some(next, next))
|> Seq.collect id
|> Seq.choose (function
| (3, 3), path -> Some <| path.Substring(input.Length)
| _ -> None)

One minor detail you might have noticed on ln 5 above is that we’re short-circuiting paths that have reached the target, this is in accordance with the further details revealed in part 2 below.

For each of the positions (and the path that lead to it), we use the aforementioned up, down, left, and right functions to find the next positions we can reach from here (provided the right doors are open as per determined by the MD5 hash value).

And yes, it’s the Level Order Tree Traveral problem again! Funny we see different reincarnations of this particular problem over and over during this year’s AOC event.

One more detail to look out for in the code snippet above – that it’s possible for there to not be a path (as per the example in the description of the problem). Hence why we terminate the Seq.unfold when none of the current positions yields a possible next move.

With this, we can now answer part 1 really easily.

let part1 = findPaths input |> Seq.tryHead
view raw Day17_Part1.fsx hosted with ❤ by GitHub

 

Part 2

You’re curious how robust this security solution really is, and so you decide to
find longer and longer paths which still provide access to the vault. You
remember that paths always end the first time they reach the bottom-right room
(that is, they can never pass through it, only end in it).

For example:

If your passcode were ihgpwlah, the longest path would take 370 steps.
With kglvqrro, the longest path would be 492 steps long.
With ulqzkmiv, the longest path would be 830 steps long.
What is the length of the longest path that reaches the vault?

let part2 = findPaths input |> Seq.map String.length |> Seq.max
view raw Day17_Part2.fsx hosted with ❤ by GitHub

 

Links

Whenever you’re ready, here are 3 ways I can help you:

  1. Production-Ready Serverless: Join 20+ AWS Heroes & Community Builders and 1000+ other students in levelling up your serverless game. This is your one-stop shop for quickly levelling up your serverless skills.
  2. I help clients launch product ideas, improve their development processes and upskill their teams. If you’d like to work together, then let’s get in touch.
  3. Join my community on Discord, ask questions, and join the discussion on all things AWS and Serverless.

2 thoughts on “Advent of Code F# – Day 17”

  1. Pingback: Advent of Code F# – Day 18 | theburningmonk.com

  2. Pingback: F# Weekly #52, 2016 – Sergey Tihon's Blog

Leave a Comment

Your email address will not be published. Required fields are marked *