aboutsummaryrefslogtreecommitdiff
path: root/aoc-2022-dotnet/Day13/Program.fs
diff options
context:
space:
mode:
Diffstat (limited to 'aoc-2022-dotnet/Day13/Program.fs')
-rw-r--r--aoc-2022-dotnet/Day13/Program.fs73
1 files changed, 73 insertions, 0 deletions
diff --git a/aoc-2022-dotnet/Day13/Program.fs b/aoc-2022-dotnet/Day13/Program.fs
new file mode 100644
index 0000000..2ff8b8d
--- /dev/null
+++ b/aoc-2022-dotnet/Day13/Program.fs
@@ -0,0 +1,73 @@
+module Day13
+
+#nowarn "0342"
+
+open System
+open System.IO
+open FParsec
+open Common
+
+[<StructuralEquality; CustomComparison>]
+type Packet =
+ | Integer of int
+ | List of Packet list
+
+ static member dividers =
+ [ Packet.parse "[[2]]"
+ Packet.parse "[[6]]" ]
+
+ interface IComparable with
+ member this.CompareTo other =
+ match other with
+ | :? Packet as p -> (this :> IComparable<_>).CompareTo p
+ | _ -> failwith "Can only compare packets with other packets!"
+
+ interface IComparable<Packet> with
+ member this.CompareTo other =
+ match (this, other) with
+ | Integer l, Integer r -> compare l r
+ | List l, List r -> compare l r
+ | (Integer _ as l), (List _ as r) -> compare (List [ l ]) r
+ | (List _ as l), (Integer _ as r) -> compare l (List [ r ])
+
+ static member parse =
+ let ppacket, ppacketImpl = createParserForwardedToRef ()
+ let pinteger = pint32 |>> Integer
+
+ let plist =
+ between (pchar '[') (pchar ']') (sepBy ppacket (pchar ','))
+ |>> List
+
+ ppacketImpl.Value <- pinteger <|> plist
+
+ Util.parse ppacket
+
+let solution (transform, predicate, reducer) =
+ Seq.filter (not << String.IsNullOrWhiteSpace)
+ >> Seq.map Packet.parse
+ >> transform
+ >> Seq.indexed
+ >> Seq.choose (fun (i, p) ->
+ match predicate p with
+ | true -> Some(i + 1)
+ | false -> None)
+ >> Seq.reduce reducer
+
+let part1 =
+ (Seq.chunkBySize 2
+ >> Seq.map (function
+ | [| l; r |] -> compare l r
+ | _ -> failwith "Invalid packet groupings!"),
+ (>=) 0,
+ (+))
+
+let part2 =
+ (Seq.append Packet.dividers >> Seq.sort, (fun p -> List.contains p Packet.dividers), (*))
+
+let test = File.ReadLines("test.txt")
+assert (solution part1 test = 13)
+assert (solution part2 test = 140)
+
+let input = File.ReadLines("input.txt")
+printfn "%d" <| solution part1 input
+printfn "%d" <| solution part2 input