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

<https://adventofcode.com/2020/day/1>

Find entries in an /expense report/ that sum up to 2020 and return their
product.

-}
module Main where

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

-- | >>> :main
-- 494475
-- 267520550
main :: IO ()
IO ()
main =
  do [Int]
input <- [format|2020 1 (%u%n)*|]
     Int -> IO ()
forall a. Show a => a -> IO ()
print ([Int] -> Int -> Int
solve [Int]
input Int
2)
     Int -> IO ()
forall a. Show a => a -> IO ()
print ([Int] -> Int -> Int
solve [Int]
input Int
3)

-- | Given a list of integer inputs, find the product of @count@
-- entries that sum up to @2020@.
--
-- >>> solve [1721, 979, 366, 299, 675, 1456] 2
-- 514579
--
-- | >>> solve [1721, 979, 366, 299, 675, 1456] 3
-- 241861950
solve ::
  [Int] {- ^ inputs  -} ->
  Int   {- ^ count   -} ->
  Int   {- ^ product -}
solve :: [Int] -> Int -> Int
solve [Int]
input Int
n = [Int] -> Int -> Int -> Int -> Int -> Int
solve' ([Int] -> [Int]
forall a. Ord a => [a] -> [a]
sort [Int]
input) Int
n Int
2020 Int
1 (String -> Int
forall a. HasCallStack => String -> a
error String
"no solution")

solve' ::
  [Int] {- ^ sorted inputs    -} ->
  Int   {- ^ count            -} ->
  Int   {- ^ target sum       -} ->
  Int   {- ^ current product  -} ->
  Int   {- ^ next alternative -} ->
  Int   {- ^ final product    -}
solve' :: [Int] -> Int -> Int -> Int -> Int -> Int
solve' [Int]
_      Int
0 Int
0 Int
p Int
_ = Int
p
solve' (Int
x:[Int]
xs) Int
n Int
s Int
p Int
e | Int
0 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
n, Int
x Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
s = [Int] -> Int -> Int -> Int -> Int -> Int
solve' [Int]
xs (Int
nInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
1) (Int
sInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
x) (Int
pInt -> Int -> Int
forall a. Num a => a -> a -> a
*Int
x) ([Int] -> Int -> Int -> Int -> Int -> Int
solve' [Int]
xs Int
n Int
s Int
p Int
e)
solve' [Int]
_      Int
_ Int
_ Int
_ Int
e = Int
e