-- |
-- Module      : AOC.Challenge.Day03
-- License     : BSD3
--
-- Stability   : experimental
-- Portability : non-portable

module AOC.Challenge.Day03 (
    day03a
  , day03b
  , validCoord
  ) where

import           AOC.Common  (countTrue)
import           AOC.Solver  ((:~>)(..))
import           Data.Char   (isSpace)
import           Data.Finite (Finite, modulo)

type Coord = (Finite 31, Int)

validCoord
    :: Finite 31        -- ^ dx
    -> Int              -- ^ dy
    -> Coord
    -> Bool
validCoord :: Finite 31 -> Int -> Coord -> Bool
validCoord Finite 31
dx Int
dy = \(Finite 31
x,Int
y) ->
    let (Int
i,Int
r) = Int
y Int -> Int -> (Int, Int)
forall a. Integral a => a -> a -> (a, a)
`divMod` Int
dy
    in  Int
r Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 Bool -> Bool -> Bool
&& Finite 31
dx Finite 31 -> Finite 31 -> Finite 31
forall a. Num a => a -> a -> a
* Integer -> Finite 31
forall (n :: Nat). KnownNat n => Integer -> Finite n
modulo (Int -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
i) Finite 31 -> Finite 31 -> Bool
forall a. Eq a => a -> a -> Bool
== Finite 31
x

countLine :: Finite 31 -> Int -> String -> Int
countLine :: Finite 31 -> Int -> String -> Int
countLine Finite 31
dx Int
dy = ((Coord, Char) -> Bool) -> [(Coord, Char)] -> Int
forall (f :: * -> *) a. Foldable f => (a -> Bool) -> f a -> Int
countTrue ((Coord -> Char -> Bool) -> (Coord, Char) -> Bool
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry Coord -> Char -> Bool
tree)
                ([(Coord, Char)] -> Int)
-> (String -> [(Coord, Char)]) -> String -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Coord] -> String -> [(Coord, Char)]
forall a b. [a] -> [b] -> [(a, b)]
zip (Int -> Coord
forall {b} {a}. (Integral b, Num a) => b -> (a, b)
splitOut (Int -> Coord) -> [Int] -> [Coord]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Int
0..])
  where
    checkCoord :: Coord -> Bool
checkCoord = Finite 31 -> Int -> Coord -> Bool
validCoord Finite 31
dx Int
dy
    tree :: Coord -> Char -> Bool
tree Coord
xy Char
c  = Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'#' Bool -> Bool -> Bool
&& Coord -> Bool
checkCoord Coord
xy
    splitOut :: b -> (a, b)
splitOut b
i = (b -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral b
x, b
y)
      where
        (!b
y, !b
x) = b
i b -> b -> (b, b)
forall a. Integral a => a -> a -> (a, a)
`divMod` b
31

day03a :: String :~> Int
day03a :: String :~> Int
day03a = MkSol :: forall a b.
(String -> Maybe a)
-> ((?dyno::DynoMap) => a -> Maybe b) -> (b -> String) -> a :~> b
MkSol
    { sParse :: String -> Maybe String
sParse = String -> Maybe String
forall a. a -> Maybe a
Just (String -> Maybe String)
-> (String -> String) -> String -> Maybe String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not (Bool -> Bool) -> (Char -> Bool) -> Char -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Bool
isSpace)
    , sShow :: Int -> String
sShow  = Int -> String
forall a. Show a => a -> String
show
    , sSolve :: (?dyno::DynoMap) => String -> Maybe Int
sSolve = Int -> Maybe Int
forall a. a -> Maybe a
Just (Int -> Maybe Int) -> (String -> Int) -> String -> Maybe Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Finite 31 -> Int -> String -> Int
countLine Finite 31
3 Int
1
    }

day03b :: String :~> Int
day03b :: String :~> Int
day03b = MkSol :: forall a b.
(String -> Maybe a)
-> ((?dyno::DynoMap) => a -> Maybe b) -> (b -> String) -> a :~> b
MkSol
    { sParse :: String -> Maybe String
sParse = String -> Maybe String
forall a. a -> Maybe a
Just (String -> Maybe String)
-> (String -> String) -> String -> Maybe String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not (Bool -> Bool) -> (Char -> Bool) -> Char -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Bool
isSpace)
    , sShow :: Int -> String
sShow  = Int -> String
forall a. Show a => a -> String
show
    , sSolve :: (?dyno::DynoMap) => String -> Maybe Int
sSolve = \String
s -> Int -> Maybe Int
forall a. a -> Maybe a
Just (Int -> Maybe Int) -> ([Int] -> Int) -> [Int] -> Maybe Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Int] -> Int
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
product ([Int] -> Maybe Int) -> [Int] -> Maybe Int
forall a b. (a -> b) -> a -> b
$
        [ Finite 31 -> Int -> String -> Int
countLine Finite 31
1 Int
1
        , Finite 31 -> Int -> String -> Int
countLine Finite 31
3 Int
1
        , Finite 31 -> Int -> String -> Int
countLine Finite 31
5 Int
1
        , Finite 31 -> Int -> String -> Int
countLine Finite 31
7 Int
1
        , Finite 31 -> Int -> String -> Int
countLine Finite 31
1 Int
2
        ] [String -> Int] -> [String] -> [Int]
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> [String
s]
    }