Skip to content

Instantly share code, notes, and snippets.

@tariknz
Last active December 4, 2018 20:32
Show Gist options
  • Select an option

  • Save tariknz/b90ac2288ffc6ae6c17a154031f806f0 to your computer and use it in GitHub Desktop.

Select an option

Save tariknz/b90ac2288ffc6ae6c17a154031f806f0 to your computer and use it in GitHub Desktop.
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