{-# Language QuasiQuotes, BlockArguments #-}
{-|
Module      : Main
Description : Day 7 solution
Copyright   : (c) Eric Mertens, 2021
License     : ISC
Maintainer  : emertens@gmail.com

<https://adventofcode.com/2016/day/7>

-}
module Main where

import Advent (format)
import Control.Monad (guard)
import Data.List (isInfixOf, tails)

-- | >>> :main
-- 118
-- 260
main :: IO ()
IO ()
main =
 do [[[Char]]]
xs <- [format|2016 7 ((%a*)&(]|[)%n)*|]
    Int -> IO ()
forall a. Show a => a -> IO ()
print ([[[Char]]] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length (([[Char]] -> Bool) -> [[[Char]]] -> [[[Char]]]
forall a. (a -> Bool) -> [a] -> [a]
filter [[Char]] -> Bool
supportsTLS [[[Char]]]
xs))
    Int -> IO ()
forall a. Show a => a -> IO ()
print ([[[Char]]] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length (([[Char]] -> Bool) -> [[[Char]]] -> [[[Char]]]
forall a. (a -> Bool) -> [a] -> [a]
filter [[Char]] -> Bool
supportsSSL [[[Char]]]
xs))

split :: [String] -> ([String], [String])
split :: [[Char]] -> ([[Char]], [[Char]])
split [] = ([],[])
split [[Char]
x] = ([[Char]
x],[])
split ([Char]
x:[Char]
y:[[Char]]
z) =
  case [[Char]] -> ([[Char]], [[Char]])
split [[Char]]
z of
    ([[Char]]
a,[[Char]]
b) -> ([Char]
x[Char] -> [[Char]] -> [[Char]]
forall a. a -> [a] -> [a]
:[[Char]]
a,[Char]
y[Char] -> [[Char]] -> [[Char]]
forall a. a -> [a] -> [a]
:[[Char]]
b)

supportsTLS :: [String] -> Bool
supportsTLS :: [[Char]] -> Bool
supportsTLS [[Char]]
xs =
  case [[Char]] -> ([[Char]], [[Char]])
split [[Char]]
xs of
    ([[Char]]
supers, [[Char]]
hypers) -> ([Char] -> Bool) -> [[Char]] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any [Char] -> Bool
forall {a}. Eq a => [a] -> Bool
hasABBA [[Char]]
supers Bool -> Bool -> Bool
&& Bool -> Bool
not (([Char] -> Bool) -> [[Char]] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any [Char] -> Bool
forall {a}. Eq a => [a] -> Bool
hasABBA [[Char]]
hypers)
  where
    hasABBA :: [a] -> Bool
hasABBA [a]
ys = ([a] -> Bool) -> [[a]] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any [a] -> Bool
forall {a}. Eq a => [a] -> Bool
isABBA ([a] -> [[a]]
forall a. [a] -> [[a]]
tails [a]
ys)

    isABBA :: [a] -> Bool
isABBA (a
w:a
x:a
y:a
z:[a]
_) = a
w a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
z Bool -> Bool -> Bool
&& a
x a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
y Bool -> Bool -> Bool
&& a
w a -> a -> Bool
forall a. Eq a => a -> a -> Bool
/= a
x
    isABBA [a]
_ = Bool
False

supportsSSL :: [String] -> Bool
supportsSSL :: [[Char]] -> Bool
supportsSSL [[Char]]
xs =
  case [[Char]] -> ([[Char]], [[Char]])
split [[Char]]
xs of
    ([[Char]]
supers, [[Char]]
hypers) ->
      Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ [()] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null
       do [Char]
s <- [[Char]]
supers
          Char
x:Char
y:Char
z:[Char]
_ <- [Char] -> [[Char]]
forall a. [a] -> [[a]]
tails [Char]
s
          Bool -> [()]
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Char
x Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
z Bool -> Bool -> Bool
&& Char
x Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= Char
y)
          [Char]
h <- [[Char]]
hypers
          Bool -> [()]
forall (f :: * -> *). Alternative f => Bool -> f ()
guard ( [Char
y,Char
x,Char
y] [Char] -> [Char] -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isInfixOf` [Char]
h )