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
|
open System.IO
open System.Text.RegularExpressions
let (|Regex|_|) pattern input =
let m = Regex.Matches(input, pattern)
if m.Count > 0 then Some(m)
else None
let lines = File.ReadLines "day7.txt"
let getSegments inputStr =
match inputStr with
| Regex "(?:[a-z]+)|(?:\[[a-z]+\])" matches -> matches |> Seq.map (fun x -> x.Value) |> Seq.toList
| _ -> []
// part 1
let containsABBA (segment: string): bool =
let isABBA (chars: char[]): bool =
let a1, b1, b2, a2 = chars[0], chars[1], chars[2], chars[3]
a1 = a2 && b1 = b2 && a1 <> b1
segment
|> Seq.windowed 4
|> Seq.map isABBA
|> Seq.fold (||) false
let ABBASegment (segment: string): bool =
not ((containsABBA segment) && (segment[0] = '['))
let TLSLine (line: string):bool=
let allValid = line
|> getSegments
|> Seq.map ABBASegment
|> Seq.fold (&&) true
allValid && containsABBA line
lines |> Seq.filter TLSLine |> Seq.length |> printfn "%d"
// part 2
let matchABA (pair: char[] * char[]): bool =
let aba, bab = pair
let a, b, c = aba[0], aba[1], aba[2]
let d, e, f = bab[0], bab[1], bab[2]
a = c && d = f && a = e && b = d
let ABAPairs (segments: list<string>) : list<char[] * char[]> =
let windows (group: bool * list<string>) =
let _, segments = group
seq {
for segment in segments do
yield! seq {
for window in Seq.windowed 3 (String.filter (fun x -> x <> '[' && x <> ']') segment) do
yield window
}
}
let cartesian xs ys =
xs |> List.collect (fun x -> ys |> List.map (fun y -> x, y))
let separated = segments |> List.groupBy (fun x -> x[0] = '[') |> List.map windows |> List.map Seq.toList
cartesian separated[0] separated[1]
let validABA =
getSegments
>> ABAPairs
>> Seq.map matchABA
>> Seq.fold (||) false
let ABACount : seq<string> -> int=
Seq.filter validABA >> Seq.length
ABACount lines |> printfn "%d"
|