Skip to content

Instantly share code, notes, and snippets.

@Karamell
Created December 19, 2020 16:13
Show Gist options
  • Select an option

  • Save Karamell/9939a2c876958f91bb5e8a55eef5834b to your computer and use it in GitHub Desktop.

Select an option

Save Karamell/9939a2c876958f91bb5e8a55eef5834b to your computer and use it in GitHub Desktop.
Advent of Code 2020 day 19 in F#
#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