Skip to content

Instantly share code, notes, and snippets.

@einarwh
Last active December 15, 2023 08:23
Show Gist options
  • Save einarwh/13aefaa68f6505e769548fd0fe916275 to your computer and use it in GitHub Desktop.
Save einarwh/13aefaa68f6505e769548fd0fe916275 to your computer and use it in GitHub Desktop.
Advent of Code 2023 - Day 15: Lens Library - F# version
// Advent of Code 2023. Day 15: Lens Library
// dotnet fsi aoc15.fsx
open System.IO
type Op =
| Insert of (string * int)
| Remove of string
let readText fileName =
let text = File.ReadAllText fileName
text.TrimEnd()
let parseOp (s : string) =
if s.EndsWith('-') then
let label = s.Substring(0, s.Length - 1)
Remove label
else
let ss = s.Split("=")
let label = ss[0]
let focal = int ss[1]
Insert (label, focal)
let parseAllOps (s : string) =
s.Split(",") |> Array.toList |> List.map parseOp
let getHash s =
let folder current ch = ((current + int ch) * 17) % 256
s |> Seq.toList |> List.fold folder 0
let part1 (input : string) =
input.Split(",") |> Array.sumBy getHash
let executeOp hashmap op =
let contains label =
List.exists (fun (l, _) -> l = label)
let remove label =
List.filter (fun (l, _) -> l <> label)
let replace label focal =
List.map (fun (l, f) -> if l = label then (l, focal) else (l, f))
let append label focal =
(@) [label, focal]
match op with
| Remove label ->
let tryRemove = Option.map (remove label)
let hash = getHash label
hashmap |> Map.change hash tryRemove
| Insert (label, focal) ->
let insert maybe =
match maybe with
| Some lenses ->
if lenses |> contains label then
lenses |> replace label focal |> Some
else
lenses |> append label focal |> Some
| None -> Some [label, focal]
let hash = getHash label
hashmap |> Map.change hash insert
let rec execute ops hashmap =
match ops with
| [] -> hashmap
| op :: rest ->
(executeOp hashmap op) |> execute rest
let part2 input =
let calculate (boxNo, lenses) =
lenses |> List.map snd |> List.mapi (fun i focal -> (boxNo + 1) * (i + 1) * focal)
let ops = input |> parseAllOps
Map.empty
|> execute ops
|> Map.toList
|> List.collect calculate
|> List.sum
let run fileName =
let input = readText fileName
input |> part1 |> printfn "%d"
input |> part2 |> printfn "%d"
"input" |> run
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment