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

<https://adventofcode.com/2015/day/2>

Computes volumes and surface areas of boxes.

>>> :main + "2x3x4\n"
58
34

>>> :main + "1x1x10\n"
43
14

-}
module Main where

import Advent (format)
import Data.List (sort)

data Package = Package Int Int Int
data Face = Face Int Int

-- |
-- >>> :main
-- 1606483
-- 3842356
main :: IO ()
IO ()
main =
 do [(Int, Int, Int)]
input <- [format|2015 2 (%ux%ux%u%n)*|]
    let packages :: [Package]
packages = [Int -> Int -> Int -> Package
Package Int
x Int
y Int
z | (Int
x,Int
y,Int
z) <- [(Int, Int, Int)]
input]   
    Int -> IO ()
forall a. Show a => a -> IO ()
print ([Int] -> Int
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum (Package -> Int
part1 (Package -> Int) -> [Package] -> [Int]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Package]
packages))
    Int -> IO ()
forall a. Show a => a -> IO ()
print ([Int] -> Int
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum (Package -> Int
part2 (Package -> Int) -> [Package] -> [Int]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Package]
packages))

part1 :: Package -> Int
part1 :: Package -> Int
part1 Package
p = Package -> Int
surfaceArea Package
p Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Face -> Int
area (Package -> Face
smallestFace Package
p)

part2 :: Package -> Int
part2 :: Package -> Int
part2 Package
p = Package -> Int
volume Package
p Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Face -> Int
perimeter (Package -> Face
smallestFace Package
p)

volume :: Package -> Int
volume :: Package -> Int
volume (Package Int
x Int
y Int
z) = Int
xInt -> Int -> Int
forall a. Num a => a -> a -> a
*Int
yInt -> Int -> Int
forall a. Num a => a -> a -> a
*Int
z

surfaceArea :: Package -> Int
surfaceArea :: Package -> Int
surfaceArea (Package Int
x Int
y Int
z) = Int
2 Int -> Int -> Int
forall a. Num a => a -> a -> a
* (Int
xInt -> Int -> Int
forall a. Num a => a -> a -> a
*Int
y Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
xInt -> Int -> Int
forall a. Num a => a -> a -> a
*Int
z Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
yInt -> Int -> Int
forall a. Num a => a -> a -> a
*Int
z)

smallestFace :: Package -> Face
smallestFace :: Package -> Face
smallestFace (Package Int
x Int
y Int
z) = let Int
a:Int
b:[Int]
_ = [Int] -> [Int]
forall a. Ord a => [a] -> [a]
sort [Int
x,Int
y,Int
z] in Int -> Int -> Face
Face Int
a Int
b

area :: Face -> Int
area :: Face -> Int
area (Face Int
x Int
y) = Int
xInt -> Int -> Int
forall a. Num a => a -> a -> a
*Int
y

perimeter :: Face -> Int
perimeter :: Face -> Int
perimeter (Face Int
x Int
y) = Int
2Int -> Int -> Int
forall a. Num a => a -> a -> a
*(Int
xInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
y)