open System.IO open System.Text.RegularExpressions open System let lines = File.ReadLines "day4.txt" |> Seq.toList let (|Regex|_|) pattern input = let m = Regex.Match(input, pattern) if m.Success then Some(List.tail [for g in m.Groups -> g.Value]) else None let validChecksum (info: string * int * string) = let (name, idNum, checksum) = info let counts = name |> String.filter ((<>) '-') |> Seq.toList |> List.countBy id |> List.sortBy fst |> List.sortBy (snd >> fun x -> -x) let topFive = (List.map fst counts)[0..4] |> Seq.map string|> String.concat "" if topFive = checksum then idNum else 0 let getInfo string = match string with | Regex "([a-z\-]*)-(\d+)\[([a-z]{5})\]" [name; id; checksum] -> (name, int id, checksum) | _ -> ("", 0, "") let totalChecksum = List.map (getInfo >> validChecksum) >> List.sum // part 1 totalChecksum lines |> printfn "%A" // part 2 let decrypt (offset: int) (letter: char) : string = match letter with | '-' -> " " | _ -> int letter |> fun x -> x - (int 'a') + offset |> fun x -> x % 26 |> ((+) (int 'a')) |> Convert.ToChar |> string let decryptValid (info: string * int * string) = let (name, idNum, checksum) = info Seq.toList name |> List.map (decrypt idNum) |> String.concat "", idNum let decrypted = List.map (getInfo >> decryptValid) >> List.filter (fst >> fun x -> x.Contains "north") decrypted lines |> printfn "%A"