-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday19_part01.fs
136 lines (113 loc) · 3.82 KB
/
day19_part01.fs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
module day19_part01
open System
open FSharp.Text.RegexProvider
open FSharp.Text.RegexExtensions
open FSharp.Collections.ParallelSeq
open AdventOfCode_2020.Modules
type RuleRegex = Regex< @"(?<Number>\d+):\s(?<Rule>.+)">
type LetterRegex = Regex< "\"(?<Letter>\w)\"">
type OptionRegex = Regex<"(?<Left>.+)\|(?<Right>.+)">
type BinaryRegex = Regex<"(?<Left>\d+)\s+(?<Right>\d+)">
type TrinaryRegex = Regex<"(?<Left>\d+)\s+(?<Center>\d+)\s+(?<Right>\d+)">
type ReferenceRegex = Regex<"\s*(?<Number>\d+)\s*">
let (|Letter|Binary|Option|Reference|Trinary|) (rule: string) =
if LetterRegex().IsMatch rule then
Letter rule
elif OptionRegex().IsMatch rule then
Option rule
elif TrinaryRegex().IsMatch rule then
Trinary rule
elif BinaryRegex().IsMatch rule then
Binary rule
elif ReferenceRegex().IsMatch rule then
Reference rule
else
printfn "RULE: %A" rule
failwith "not there yet"
let extractRule rule =
let m = RuleRegex().TypedMatch rule
(m.Number.AsInt, m.Rule.Value)
let parseRules rules =
rules
|> Array.map extractRule
|> Map.ofArray
let rec letterMatch rule (text: string[]) =
let text =
text
|> Array.filter (String.IsNullOrEmpty >> not)
|> Array.map (fun s ->
let m = LetterRegex().TypedMatch(rule).Letter.AsChar
m = s.[0], s.[1..])
|> Array.filter (fst)
|> Array.map snd
if Array.isEmpty text then
false, [||]
else
true, text
and binaryMatch rules rule text =
let m = BinaryRegex().TypedMatch rule
let left = m.Left.AsInt
let right = m.Right.AsInt
let leftRule = Map.find left rules
let rightRule = Map.find right rules
match matches rules leftRule text with
| false, _ -> false, text
| true, remaining ->
matches rules rightRule remaining
and trinaryMatch rules rule text =
let m = TrinaryRegex().TypedMatch rule
let left = m.Left.AsInt
let center = m.Center.AsInt
let right = m.Right.AsInt
let leftRule = Map.find left rules
let centerRule = Map.find center rules
let rightRule = Map.find right rules
match matches rules leftRule text with
| false, _ -> false, text
| true, remaining ->
match matches rules centerRule remaining with
| false, _ -> false, text
| true, rem -> matches rules rightRule rem
and optionMatch rules rule text =
let m = OptionRegex().TypedMatch rule
let left = m.Left.Value
let right = m.Right.Value
match matches rules left text, matches rules right text with
| (false, _), (false, _) -> false, text
| (true, lr), (true, rr) -> true, (Array.append lr rr)
| (true, lr), _ -> true, lr
| _, (true, rr) -> true, rr
and referenceMatch rules rule text =
let m = ReferenceRegex().TypedMatch rule
let number = m.Number.AsInt
let r = Map.find number rules
matches rules r text
and matches rules rule (text: string []) =
match rule with
| Letter r -> letterMatch r text
| Option r -> optionMatch rules r text
| Trinary r -> trinaryMatch rules r text
| Binary r -> binaryMatch rules r text
| Reference r -> referenceMatch rules r text
let parseContent(lines: string array) =
lines
|> Array.partition (RuleRegex().IsMatch)
let execute =
let path = "day19/day19_input.txt"
let lines = LocalHelper.GetLinesFromFile path
let content = parseContent lines
let rules =
content
|> fst
|> parseRules
let zero = Map.find 0 rules
let messages =
content
|> snd
|> Array.tail
let matchesZero = matches rules zero
messages
|> PSeq.map (Array.singleton >> matchesZero)
|> PSeq.filter fst
|> PSeq.filter (snd >> (Array.exists String.IsNullOrEmpty))
|> PSeq.length