diff options
-rw-r--r-- | day14.fsx | 56 |
1 files changed, 56 insertions, 0 deletions
diff --git a/day14.fsx b/day14.fsx new file mode 100644 index 0000000..0232ff8 --- /dev/null +++ b/day14.fsx @@ -0,0 +1,56 @@ +#r "nuget: FSharpx.Collections, 3.0.1" +open System.Security.Cryptography +open System.Text +open FSharpx.Collections + +let salt = "yjdafjpo" +let md5 (data: string): string = + use md5 = MD5.Create() + (StringBuilder (), md5.ComputeHash(Encoding.ASCII.GetBytes data)) + ||> Array.fold (fun sb b -> sb.Append(b.ToString("x2"))) + |> string + +// returns Some char being repeated for n many times in input hash, otherwise None if no repetitions +let getSameChar (n: int) (hash: string) : char option = + let sameChar (window: char array): char = + Array.reduce (fun x y -> if x = y then y else char 0) window + hash + |> Seq.windowed n + |> Seq.map sameChar + |> Seq.filter (fun x -> x <> char 0) + |> Seq.toArray + |> fun x -> if x.Length > 0 then Some x[0] else None + +// returns true if any of the hashes contain ch repeated 5 times +let hashRepeats (ch: char) (hashes: Deque<string>): bool = + Seq.map (getSameChar 5) hashes + |> Seq.filter (function | Some x -> x = ch | None -> false) + |> fun x -> Seq.length x > 0 + +// hashes contains hash of salt + index, plus the next 1000 hashes +let rec getPadKey (currInd: int) (indices: int list) (hashes: Deque<string>) (hashfunc: string -> string) = + if indices.Length = 64 then indices.Head + else + let current, rest = hashes.Uncons + let hasMatch = + match getSameChar 3 current with + | Some x -> hashRepeats x rest + | None -> false + + let newHashes = rest.Conj <| hashfunc (salt + string (currInd + 1001)) + if hasMatch then + getPadKey (currInd + 1) (currInd::indices) newHashes hashfunc + else + getPadKey (currInd + 1) indices newHashes hashfunc + +let part1hash = md5 +let part2hash = + seq { for n in 0..2016 do yield md5 } + |> Seq.reduce (>>) + +// part 1 +let p1first1000 = Deque.ofList [ for i in 0..1000 do yield part1hash (salt + string i) ] +getPadKey 0 [] p1first1000 part1hash |> printfn "%d" +// part 2 +let p2first1000 = Deque.ofList [ for i in 0..1000 do yield part2hash (salt + string i) ] +getPadKey 0 [] p2first1000 part2hash |> printfn "%d" |