summary refs log tree commit diff stats
path: root/day7.fsx
blob: 950d98dc2b05bdb9b92ce971fa952abddc82ce06 (plain) (blame)
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"