-- |
-- Module      : AOC.Challenge.Day06
-- License     : BSD3
--
-- Stability   : experimental
-- Portability : non-portable
--
-- Day 6.  See "AOC.Solver" for the types used in this module!

module AOC.Challenge.Day06 (
    day06a
  , day06b
  ) where

import           AOC.Solver         ((:~>)(..))
import           Data.Bits          (setBit, popCount, (.&.), (.|.))
import           Data.Char          (ord)
import           Data.List          (foldl')
import           Data.List.NonEmpty (NonEmpty)
import           Data.List.Split    (splitOn)
import           Data.Maybe         (mapMaybe)
import qualified Data.List.NonEmpty as NE

type CharSet = Word

toCharSet :: [Char] -> CharSet
toCharSet :: [Char] -> CharSet
toCharSet = (CharSet -> Char -> CharSet) -> CharSet -> [Char] -> CharSet
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' CharSet -> Char -> CharSet
forall {a}. Bits a => a -> Char -> a
insertCharSet CharSet
0
  where
    insertCharSet :: a -> Char -> a
insertCharSet a
cs Char
c = a
cs a -> Int -> a
forall a. Bits a => a -> Int -> a
`setBit` Int
i
      where
        i :: Int
i = Char -> Int
ord Char
c Int -> Int -> Int
forall a. Num a => a -> a -> a
- Char -> Int
ord Char
'a'

answers :: [String] -> Maybe (NonEmpty CharSet)
answers :: [[Char]] -> Maybe (NonEmpty CharSet)
answers = ((NonEmpty [Char] -> NonEmpty CharSet)
-> Maybe (NonEmpty [Char]) -> Maybe (NonEmpty CharSet)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((NonEmpty [Char] -> NonEmpty CharSet)
 -> Maybe (NonEmpty [Char]) -> Maybe (NonEmpty CharSet))
-> (([Char] -> CharSet) -> NonEmpty [Char] -> NonEmpty CharSet)
-> ([Char] -> CharSet)
-> Maybe (NonEmpty [Char])
-> Maybe (NonEmpty CharSet)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([Char] -> CharSet) -> NonEmpty [Char] -> NonEmpty CharSet
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap) [Char] -> CharSet
toCharSet (Maybe (NonEmpty [Char]) -> Maybe (NonEmpty CharSet))
-> ([[Char]] -> Maybe (NonEmpty [Char]))
-> [[Char]]
-> Maybe (NonEmpty CharSet)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [[Char]] -> Maybe (NonEmpty [Char])
forall a. [a] -> Maybe (NonEmpty a)
NE.nonEmpty

day06With
    :: (CharSet -> CharSet -> CharSet)
    -> [[String]] :~> Int
day06With :: (CharSet -> CharSet -> CharSet) -> [[[Char]]] :~> Int
day06With CharSet -> CharSet -> CharSet
f = MkSol :: forall a b.
([Char] -> Maybe a)
-> ((?dyno::DynoMap) => a -> Maybe b) -> (b -> [Char]) -> a :~> b
MkSol
    { sParse :: [Char] -> Maybe [[[Char]]]
sParse = [[[Char]]] -> Maybe [[[Char]]]
forall a. a -> Maybe a
Just ([[[Char]]] -> Maybe [[[Char]]])
-> ([Char] -> [[[Char]]]) -> [Char] -> Maybe [[[Char]]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([Char] -> [[Char]]) -> [[Char]] -> [[[Char]]]
forall a b. (a -> b) -> [a] -> [b]
map [Char] -> [[Char]]
lines ([[Char]] -> [[[Char]]])
-> ([Char] -> [[Char]]) -> [Char] -> [[[Char]]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> [Char] -> [[Char]]
forall a. Eq a => [a] -> [a] -> [[a]]
splitOn [Char]
"\n\n"
    , sShow :: Int -> [Char]
sShow  = Int -> [Char]
forall a. Show a => a -> [Char]
show
    , sSolve :: (?dyno::DynoMap) => [[[Char]]] -> Maybe Int
sSolve = Int -> Maybe Int
forall a. a -> Maybe a
Just (Int -> Maybe Int)
-> ([[[Char]]] -> Int) -> [[[Char]]] -> Maybe Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Int] -> Int
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum ([Int] -> Int) -> ([[[Char]]] -> [Int]) -> [[[Char]]] -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([[Char]] -> Maybe Int) -> [[[Char]]] -> [Int]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe ((NonEmpty CharSet -> Int) -> Maybe (NonEmpty CharSet) -> Maybe Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (CharSet -> Int
forall a. Bits a => a -> Int
popCount (CharSet -> Int)
-> (NonEmpty CharSet -> CharSet) -> NonEmpty CharSet -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (CharSet -> CharSet -> CharSet) -> NonEmpty CharSet -> CharSet
forall (t :: * -> *) a. Foldable t => (a -> a -> a) -> t a -> a
foldr1 CharSet -> CharSet -> CharSet
f) (Maybe (NonEmpty CharSet) -> Maybe Int)
-> ([[Char]] -> Maybe (NonEmpty CharSet)) -> [[Char]] -> Maybe Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [[Char]] -> Maybe (NonEmpty CharSet)
answers)
    }

day06a :: [[String]] :~> Int
day06a :: [[[Char]]] :~> Int
day06a = (CharSet -> CharSet -> CharSet) -> [[[Char]]] :~> Int
day06With CharSet -> CharSet -> CharSet
forall a. Bits a => a -> a -> a
(.|.)

day06b :: [[String]] :~> Int
day06b :: [[[Char]]] :~> Int
day06b = (CharSet -> CharSet -> CharSet) -> [[[Char]]] :~> Int
day06With CharSet -> CharSet -> CharSet
forall a. Bits a => a -> a -> a
(.&.)