Created
December 19, 2020 16:13
-
-
Save Karamell/9939a2c876958f91bb5e8a55eef5834b to your computer and use it in GitHub Desktop.
Advent of Code 2020 day 19 in F#
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
| #time "on" | |
| let txt = System.IO.File.ReadAllText( __SOURCE_DIRECTORY__ + "/input.txt").Trim() | |
| type Rule = A | B | Rules of int list | OrRules of (int list) * (int list) | |
| module Rule = | |
| let parse (s:string) = | |
| let [|number; r|] = s.Split(":") | |
| let rule = | |
| match r.Trim() with | |
| | "\"a\"" -> A | |
| | "\"b\"" -> B | |
| | s when s.Contains("|") |> not -> s.Split(" ") |> Array.map int |> List.ofArray |> Rules | |
| | s -> | |
| s.Split("|") |> Array.map (fun ss -> | |
| ss.Trim().Split(" ") |> Array.map int |> Array.toList) | |
| |> fun ([|r1;r2|]) -> OrRules (r1, r2) | |
| | p -> failwith p | |
| int number, rule | |
| let runmessage (rules:Rule array) (s:string) = | |
| let rnd = System.Random() // Hoho | |
| let rec run (no:int) (s:char list) = | |
| let runlist l = | |
| l |> List.fold(fun acc i -> acc |> Option.bind(fun is -> | |
| if is |> List.isEmpty then | |
| None | |
| else run i is)) (Some s) | |
| match rules.[no] with | |
| | A -> match s with | 'a'::t -> Some t | _ -> None | |
| | B -> match s with | 'b'::t -> Some t | _ -> None | |
| | Rules l -> runlist l | |
| | OrRules (l1, l2) -> | |
| let l1, l2 = if rnd.NextDouble() > 0.5 then l1, l2 else l2, l1 | |
| match runlist l1 with | |
| | Some r -> Some r | |
| | None -> runlist l2 | |
| s |> Seq.toList |> run 0 | |
| let runMessages rules messages = | |
| messages |> Seq.map (runmessage rules) | |
| |> Seq.choose id |> Seq.filter (List.isEmpty) |> Seq.length | |
| let rules, messages = | |
| let t = txt | |
| t.Split("\n\n").[0].Split("\n") |> Array.map Rule.parse |> Array.sortBy fst |> Array.map snd | |
| ,t.Split("\n\n").[1].Split("\n") | |
| Rule.runMessages rules messages |> printfn "part 1: %d" | |
| let rules' = | |
| let a = rules |> Seq.toArray | |
| Rule.parse "8: 42 | 42 8" |> (fun (n, r) -> a.[n] <- r) | |
| Rule.parse "11: 42 31 | 42 11 31" |> (fun (n, r) -> a.[n] <- r) | |
| a | |
| let smash messages = | |
| messages |> Seq.map (fun s -> | |
| Seq.init 1_000 (fun _ -> Rule.runmessage rules' s) | |
| |> Seq.skipWhile(fun r -> r <> Some []) | |
| |> Seq.tryHead |> Option.flatten) | |
| |> Seq.filter(Option.isSome) | |
| |> Seq.length | |
| smash messages |> printfn "part 2: %d (probably)" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment