Skip to content

Instantly share code, notes, and snippets.

@einarwh
Last active December 19, 2020 23:51
Show Gist options
  • Save einarwh/47fb514cd4de73f06718c28d18067357 to your computer and use it in GitHub Desktop.
Save einarwh/47fb514cd4de73f06718c28d18067357 to your computer and use it in GitHub Desktop.
Advent of code 2020. Day 19. F# version.
open System.IO
open System.Text.RegularExpressions
let parseLine (s : string) : (int * string) =
match s.Split(": ") with
| [|s1; s2|] -> (int s1, s2)
| _ -> failwith <| sprintf "malformed line %s" s
let rec parse (ruleNo : int) (resolved : Map<int, string>) (textMap : Map<int, string>)
: (string * Map<int, string>) =
match resolved |> Map.tryFind ruleNo with
| Some s -> (s, resolved)
| None ->
let folder (ruleStr, ruleMap) (s : string) : (string * Map<int, string>) =
let (s, map) =
match s with
| "\"a\"" -> ("a", ruleMap)
| "\"b\"" -> ("b", ruleMap)
| "|" -> ("|", ruleMap)
| _ -> parse (int s) ruleMap textMap
(ruleStr + s, map)
let ruleText = textMap |> Map.find ruleNo
let (ruleStr, ruleMap) =
ruleText.Split(" ") |> Array.fold folder ("", resolved)
let rule = if ruleStr.Contains("|") then sprintf "(%s)" ruleStr else ruleStr
let ruleMap' = ruleMap |> Map.add ruleNo rule
(rule, ruleMap')
let check (pattern : string) (msg : string) =
if Regex.IsMatch(msg, pattern) then Some msg else None
let read path =
let parts = File.ReadAllText(path).Replace("\r", "").Split("\n\n")
(parts.[0].Split("\n"), parts.[1].Split("\n"))
let rule0PatternForPart1 textMap =
let (rule0, _) = parse 0 Map.empty textMap
sprintf "^%s$" rule0
let rule0PatternForPart2 textMap =
let map0 = Map.empty
let (rule42, map1) = parse 42 map0 textMap
let (rule31, map2) = parse 31 map1 textMap
let rule8 = sprintf "(%s)+" rule42
let rule11 = sprintf "(?<rule>%s)+(?<-rule>%s)+" rule42 rule31
let map = map2 |> Map.add 8 rule8 |> Map.add 11 rule11
let (rule0, _) = parse 0 map textMap
sprintf "^%s$" rule0
let run messages pattern =
messages |> Array.choose (check pattern) |> Array.length |> printfn "%d"
[<EntryPoint>]
let main argv =
let (ruleLines, messages) = read argv.[0]
let textMap = ruleLines |> Array.map parseLine |> Map.ofArray
rule0PatternForPart1 textMap |> run messages
rule0PatternForPart2 textMap |> run messages
0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment