summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--day14.fsx56
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"