Created
December 6, 2016 14:40
-
-
Save prGmtc/b62bf2f3ac5289d2d2f643aa2c196f5c to your computer and use it in GitHub Desktop.
Advent of Code 2016 - Day 6 part 2 - F#
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
open System | |
open System.Security.Cryptography | |
let hasher = MD5.Create() | |
let hash (word : string) = | |
let bytes = System.Text.Encoding.ASCII.GetBytes(word) | |
let hash = hasher.ComputeHash(bytes) | |
BitConverter.ToString(hash).Replace("-", "") | |
let indexes = | |
Seq.initInfinite id | |
let appendTo word suffix = | |
word + suffix | |
let startsWith prefix (word : string) = | |
word.StartsWith(prefix) | |
let interestingHashes doorID = | |
indexes | |
|> Seq.map (string >> appendTo doorID >> hash) | |
|> Seq.filter (startsWith "00000") | |
let nth n (word : string) = | |
word.[n - 1] | |
let parseHexStringToInt (hex : string) = | |
let hexBase = 16 | |
Convert.ToInt32(hex, hexBase) | |
let indexAndRelevantCharacter hash = | |
let idx = | |
nth 6 hash | |
|> string | |
|> parseHexStringToInt | |
let theCharacter = nth 7 hash | |
(idx, theCharacter) | |
let validIndexWithUpperLimit max index = | |
index >= 0 && index < max | |
let accumulateFirstHits accumulator (index, crackedChar) = | |
if accumulator |> Map.containsKey index then | |
accumulator | |
else | |
accumulator |> Map.add index crackedChar | |
let crack passwordLength candidates = | |
candidates | |
|> Seq.scan accumulateFirstHits Map.empty | |
|> Seq.find (fun acc -> acc |> Seq.length = passwordLength) | |
let indexesWithCharactersToString indexesWithCharacters = | |
indexesWithCharacters | |
|> Seq.sortBy fst | |
|> Seq.map (snd >> string) | |
|> String.concat "" | |
let toLower (text : string) = | |
text.ToLower() | |
let findCode doorID = | |
let length = Seq.length doorID | |
doorID | |
|> interestingHashes | |
|> Seq.map indexAndRelevantCharacter | |
|> Seq.filter (fst >> validIndexWithUpperLimit length) | |
|> crack length | |
|> Map.toSeq | |
|> indexesWithCharactersToString | |
|> toLower | |
let secret = "reyedfim" | |
printfn "Here we go!" | |
let sw = System.Diagnostics.Stopwatch.StartNew() | |
let solution = findCode secret | |
printfn "It took me %A seconds to find %s" sw.Elapsed.TotalSeconds solution // 100s :( |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
a little F# trick, when you're in a script, you can use the
#time
directive to turn on timing, so you don't need to use a stopwatch yourself, it also gives you info on gen0 and gen1 GCs too