{-|
Module:         Day7
Description:    <https://adventofcode.com/2021/day/7 Day 7: The Treachery of Whales>
-}
{-# LANGUAGE OverloadedStrings #-}
module Day7 (day7a, day7b) where

import Common (readEntire)
import Data.List (sort)
import Data.Ratio ((%))
import Data.Text (Text)
import qualified Data.Text as T (lines, splitOn)
import qualified Data.Text.Read as T (decimal)

day7a :: Text -> Either String Int
day7a :: Text -> Either String Int
day7a Text
input = do
    [Int]
nums <- (Text -> Either String Int) -> [Text] -> Either String [Int]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (Reader Int -> Text -> Either String Int
forall a. Reader a -> Text -> Either String a
readEntire Reader Int
forall a. Integral a => Reader a
T.decimal) ([Text] -> Either String [Int]) -> [Text] -> Either String [Int]
forall a b. (a -> b) -> a -> b
$ Text -> Text -> [Text]
T.splitOn Text
"," (Text -> [Text]) -> [Text] -> [Text]
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Text -> [Text]
T.lines Text
input
    let median :: Int
median = [Int] -> [Int]
forall a. Ord a => [a] -> [a]
sort [Int]
nums [Int] -> Int -> Int
forall a. [a] -> Int -> a
!! ([Int] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Int]
nums Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
2)
    Int -> Either String Int
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Int -> Either String Int) -> Int -> Either String Int
forall a b. (a -> b) -> a -> b
$ [Int] -> Int
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum [Int -> Int
forall a. Num a => a -> a
abs (Int -> Int) -> Int -> Int
forall a b. (a -> b) -> a -> b
$ Int
num Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
median | Int
num <- [Int]
nums]

day7b :: Text -> Either String Int
day7b :: Text -> Either String Int
day7b Text
input = do
    [Int]
nums <- (Text -> Either String Int) -> [Text] -> Either String [Int]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (Reader Int -> Text -> Either String Int
forall a. Reader a -> Text -> Either String a
readEntire Reader Int
forall a. Integral a => Reader a
T.decimal) ([Text] -> Either String [Int]) -> [Text] -> Either String [Int]
forall a b. (a -> b) -> a -> b
$ Text -> Text -> [Text]
T.splitOn Text
"," (Text -> [Text]) -> [Text] -> [Text]
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Text -> [Text]
T.lines Text
input
    let mean :: Ratio Int
mean = [Int] -> Int
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum [Int]
nums Int -> Int -> Ratio Int
forall a. Integral a => a -> a -> Ratio a
% [Int] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Int]
nums
        weight :: Int -> Int
weight Int
mid = [Int] -> Int
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum [Int
dx Int -> Int -> Int
forall a. Num a => a -> a -> a
* (Int
dx Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
2 | Int
num <- [Int]
nums, let dx :: Int
dx = Int -> Int
forall a. Num a => a -> a
abs (Int -> Int) -> Int -> Int
forall a b. (a -> b) -> a -> b
$ Int
num Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
mid]
    Int -> Either String Int
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Int -> Either String Int) -> Int -> Either String Int
forall a b. (a -> b) -> a -> b
$ Int -> Int -> Int
forall a. Ord a => a -> a -> a
min (Int -> Int
weight (Int -> Int) -> Int -> Int
forall a b. (a -> b) -> a -> b
$ Ratio Int -> Int
forall a b. (RealFrac a, Integral b) => a -> b
floor Ratio Int
mean) (Int -> Int
weight (Int -> Int) -> Int -> Int
forall a b. (a -> b) -> a -> b
$ Ratio Int -> Int
forall a b. (RealFrac a, Integral b) => a -> b
ceiling Ratio Int
mean)