module AOC.Challenge.Day03 (
    day03a
  , day03b
  ) where
import           AOC.Common         (Point, mannDist, Dir, dirPoint, parseDir)
import           AOC.Solver         ((:~>)(..))
import           Control.Monad      ((<=<))
import           Data.List.NonEmpty (NonEmpty(..))
import           Data.List.Split    (splitOn)
import           Data.Map           (Map)
import           Data.Semigroup     (Min(..))
import           Safe               (scanl1Def)
import           Safe.Foldable      (minimumMay)
import           Text.Read          (readMaybe)
import qualified Data.List.NonEmpty as NE
import qualified Data.Map           as M
type Path = [(Dir, Int)]
parsePath :: String -> Maybe Path
parsePath = traverse parsePoint . splitOn ","
  where
    parsePoint (d:ns) = (,) <$> parseDir d <*> readMaybe ns
    parsePoint _      = Nothing
crossings :: NonEmpty Path -> Map Point Int
crossings = foldr1 (M.intersectionWith (+)) . fmap follow
  where
    
    follow :: Path -> Map Point Int
    follow = M.fromListWith min
           . flip zip [1..]
           . scanl1Def [] (+)
           . concatMap (uncurry expandDir)
    expandDir d ns = replicate ns (dirPoint d)
day03a :: NonEmpty Path :~> Int
day03a = MkSol
    { sParse = NE.nonEmpty <=< traverse parsePath . lines
    , sShow  = show
    , sSolve = fmap getMin
             . foldMap (Just . Min . mannDist 0)
             . M.keys
             . crossings
    }
day03b :: NonEmpty Path :~> Int
day03b = MkSol
    { sParse = NE.nonEmpty <=< traverse parsePath . lines
    , sShow  = show
    , sSolve = minimumMay . crossings
    }