Today’s Advent of Code challenge had some similarities to yesterday’s. We have a series of “instructions”, which we need to apply one by one, and intermediate states are important. We’re also dealing with coordinates again so
int*int tuples are the obvious choice.
For this problem, we essentially can use
fold to apply each line of instructions and end up at the digit to be pressed, and then use
scan to apply each line at a time, keeping track of our current position.
Something I am slowly getting the hang of is that in F# we can declare
let bindings within
let bindings. So within the
solve function I declare a
lookup function which the
isValid function uses, which the
followInstruction function uses which the
followLine function uses. The
followInstruction function itself also declares some helper functions that it needs.
By scoping functions to just where they are needed, we make it very obvious that these are single-use helper functions, which makes our code more understandable. They can of course be moved elsewhere if it turns out they are more generally applicable.
Here’s my code (also available on GitHub), and as always, I welcome suggestions for improvement
let solve (keypad:string) startPos input = let lookup (x,y) = keypad.[y].[x] let isValid pos = lookup pos <> ' ' let followInstruction pos instruction = let addv (x,y) (i,j) = x+i,y+j let move = match instruction with | 'U' -> (0,-1) | 'D' -> (0,1) | 'R' -> (1,0) | 'L' -> (-1,0) | _ -> (0,0) let newPos = addv pos move if isValid newPos then newPos else pos let followLine = Seq.fold followInstruction input |> Seq.scan followLine startPos |> Seq.skip 1 |> Seq.map (lookup >> string) |> System.String.Concat |> printfn "Code: %s" let keypadA = [| " "; " 123 "; " 456 "; " 789 "; " " |] let keypadB = [| " "; " 1 "; " 234 "; " 56789 "; " ABC "; " D "; " " |] let testInput = [| "ULL "; "RRDDD"; "LURDL"; "UUUUD" |] let input = System.IO.File.ReadAllLines (__SOURCE_DIRECTORY__ + "\\input.txt") solve keypadA (2,2) testInput solve keypadA (2,2) input // part a solve keypadB (3,3) input // part b