Last active
December 4, 2018 20:32
-
-
Save tariknz/b90ac2288ffc6ae6c17a154031f806f0 to your computer and use it in GitHub Desktop.
This file contains hidden or 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.IO | |
| open System | |
| open System.Text.RegularExpressions | |
| let input = File.ReadLines("day-4.txt") | |
| type ActionType = | |
| | Sleep | |
| | Awake | |
| | Begin | |
| type LogEntry = { guardId: string; action: ActionType; timestamp: DateTime } | |
| let (|Regex|_|) pattern input = // snippet to make a regex function and return capturing groups | |
| let m = Regex.Match(input, pattern) | |
| if m.Success then Some(List.tail [ for g in m.Groups -> g.Value ]) | |
| else None | |
| let logParser line = | |
| match line with | |
| | Regex "^\[([\S ]+)\][ ]+(?:Guard (?:#([\d]+)))?[ ]?([\S ]+)$" [ date; guardId; action] -> | |
| Some ({ | |
| guardId = guardId | |
| timestamp = DateTime.Parse(date) | |
| action = | |
| match action with | |
| | "falls asleep" -> Sleep | |
| | "wakes up" -> Awake | |
| | _ -> Begin | |
| }) | |
| | _ -> None | |
| // sets guard id for the other actions | |
| let logFixer logs = | |
| let guards = | |
| logs | |
| |> Seq.indexed | |
| |> Seq.filter (fun (_, log) -> log.action = Begin) | |
| |> Seq.map (fun (index, log) -> index, log.guardId) | |
| guards | |
| |> Seq.map (fun indexedGuard -> | |
| logs | |
| |> Seq.skip (fst indexedGuard + 1) // skips past the index of the guard begin shift action | |
| |> Seq.takeWhile (fun log -> log.guardId = "") | |
| |> Seq.map (fun log -> { log with guardId = (snd indexedGuard); })) | |
| |> Seq.fold Seq.append Seq.empty | |
| let logs = | |
| input | |
| |> Seq.choose logParser | |
| |> Seq.sortBy (fun log -> log.timestamp) | |
| |> List.ofSeq | |
| |> logFixer | |
| // part 1 | |
| let longestSleeper = | |
| logs | |
| |> Seq.pairwise // pair sleep and awakes | |
| |> Seq.filter (fun (sleepLog, _) -> sleepLog.action = Sleep) // only get pairs that start with sleep | |
| |> Seq.map (fun (sleepLog, awakeLog) -> sleepLog.guardId, (awakeLog.timestamp - sleepLog.timestamp).Minutes) // length of sleep between sleep/awake | |
| |> Seq.groupBy fst | |
| |> Seq.map (fun (guardId, group) -> guardId, group |> Seq.sumBy (fun (_, sleepingTime) -> sleepingTime)) | |
| |> Seq.sortByDescending snd | |
| |> Seq.head | |
| printfn "Longest Sleeper Guard #%s; slept for: %d minutes" (fst longestSleeper) (snd longestSleeper) | |
| let sleepLengths logs = | |
| logs | |
| |> Seq.pairwise // pair sleep and awakes | |
| |> Seq.filter (fun (sleepLog, _) -> sleepLog.action = Sleep) // only get pairs that start with sleep | |
| |> Seq.map (fun (sleepLog, awakeLog) -> [sleepLog.timestamp.Minute .. awakeLog.timestamp.Minute - 1]) | |
| |> Seq.fold Seq.append Seq.empty | |
| |> Seq.countBy id | |
| |> Seq.sortByDescending snd | |
| logs | |
| |> Seq.filter (fun log -> log.guardId = fst longestSleeper) | |
| |> sleepLengths | |
| |> Seq.head | |
| |> fun (minute, count) -> printfn "Longest sleep sleeps most often on minute %d (%d times)" minute count | |
| //part 2 | |
| logs | |
| |> Seq.groupBy (fun log -> log.guardId) | |
| |> Seq.map (fun (guardId, group) -> (guardId, sleepLengths group |> Seq.head)) | |
| |> Seq.sortByDescending (fun (_, sleepMinute) -> snd sleepMinute) | |
| |> Seq.head | |
| |> fun (guardId, (minute, count)) -> printfn "Guard #%s sleeps the most often on minute %d (%d times)" guardId minute count |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment