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

<https://adventofcode.com/2016/day/15>

Solved using <https://en.wikipedia.org/wiki/Chinese_remainder_theorem>

-}
module Main where

import Advent (format)
import Advent.Chinese (chinese, toMod)

-- | >>> :main
-- Just 376777
-- Just 3903937
main :: IO ()
IO ()
main =
 do [(Integer, Integer, Integer, Integer)]
input1 <- [format|2016 15 (Disc #%lu has %lu positions; at time=%lu, it is at position %lu.%n)*|]
    let input2 :: [(Integer, Integer, Integer, Integer)]
input2 = [(Integer, Integer, Integer, Integer)]
input1 [(Integer, Integer, Integer, Integer)]
-> [(Integer, Integer, Integer, Integer)]
-> [(Integer, Integer, Integer, Integer)]
forall a. [a] -> [a] -> [a]
++ [(Int -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral ([(Integer, Integer, Integer, Integer)] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [(Integer, Integer, Integer, Integer)]
input1) Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
1, Integer
11, Integer
0, Integer
0)]
    Maybe Integer -> IO ()
forall a. Show a => a -> IO ()
print ([(Integer, Integer, Integer, Integer)] -> Maybe Integer
solve [(Integer, Integer, Integer, Integer)]
input1)
    Maybe Integer -> IO ()
forall a. Show a => a -> IO ()
print ([(Integer, Integer, Integer, Integer)] -> Maybe Integer
solve [(Integer, Integer, Integer, Integer)]
input2)

-- | Given a list of discs, find the right time to push the button.
--
-- Example:
--
-- @
-- Disc #1 has 5 positions; at time=0, it is at position 4.
-- Disc #2 has 2 positions; at time=0, it is at position 1.
-- @
--
-- >>> solve [(1, 5, 0, 4), (2, 2, 0, 1)]
-- Just 5
solve ::
  [(Integer, Integer, Integer, Integer)] {- ^ disc location, disc size, initial time, initial rotations -} ->
  Maybe Integer {- ^ time to press button -}
solve :: [(Integer, Integer, Integer, Integer)] -> Maybe Integer
solve [(Integer, Integer, Integer, Integer)]
discs = [Mod] -> Maybe Integer
chinese [Integer -> Integer -> Mod
toMod (Integer
tInteger -> Integer -> Integer
forall a. Num a => a -> a -> a
-Integer
pInteger -> Integer -> Integer
forall a. Num a => a -> a -> a
-Integer
i) Integer
n | (Integer
i, Integer
n, Integer
t, Integer
p) <- [(Integer, Integer, Integer, Integer)]
discs]