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) : list = let windows (group: bool * list) = 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 -> int= Seq.filter validABA >> Seq.length ABACount lines |> printfn "%d"