-
Notifications
You must be signed in to change notification settings - Fork 0
/
Day15.fs
64 lines (47 loc) · 1.8 KB
/
Day15.fs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
module aoc23.Day15
let parse = StringEx.splitC ','
let hash (str: string) =
(0, str) ||> Seq.fold (fun acc next -> ((acc + (int next)) * 17) % 256)
let part1 str = parse str |> Seq.map hash |> Seq.sum
type LensBoxes() =
let lensBoxes = Array.create 256 List<(string * int)>.Empty
let mapAt label mapper =
let boxId = hash label
lensBoxes[boxId] <- mapper lensBoxes[boxId]
member x.removeAt label =
mapAt label (fun list ->
list
|> List.tryFindIndex (fst >> (=) label)
|> Option.map (fun index -> list |> List.removeAt index)
|> Option.defaultValue list)
member x.upsertAt label focalLength =
mapAt label (fun list ->
list
|> List.tryFindIndex (fst >> (=) label)
|> Option.map (fun index -> list |> List.updateAt index (label, focalLength))
|> Option.defaultValue (list @ [ (label, focalLength) ]))
member x.score =
lensBoxes
|> Array.mapi (fun boxId lenses ->
lenses
|> Seq.mapi (fun lensSlot (_, focalLength) -> (boxId + 1) * (lensSlot + 1) * focalLength)
|> Seq.sum)
|> Seq.sum
let part2 str =
let lensBoxes = LensBoxes()
str
|> parse
|> Seq.iter (function
| Regex @"([a-z]+)=(\d+)" [ label; focalLength ] -> lensBoxes.upsertAt label (int focalLength)
| Regex @"([a-z]+)-" [ label ] -> lensBoxes.removeAt label
| _ -> failwith "unknown operation")
lensBoxes.score
let run = runReadAllText part1 part2
module Tests =
open Xunit
open Swensen.Unquote
let example = "rn=1,cm-,qp=3,cm=2,qp-,pc=4,ot=9,ab=5,pc-,pc=6,ot=7"
[<Fact>]
let ``part 1 example`` () = part1 example =! 1320
[<Fact>]
let ``part 2 example`` () = part2 example =! 145