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

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

-}
module Main where

import Advent ( getInputLines )
import Control.Applicative ( Alternative(some) )
import Text.ParserCombinators.ReadP as ReadP
import Data.Char (isDigit)

main :: IO ()
IO ()
main =
  do [String]
xs <- Int -> Int -> IO [String]
getInputLines Int
2016 Int
9
     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 ((String -> Int) -> [String] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map String -> Int
decode1 [String]
xs))
     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 ((String -> Int) -> [String] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map String -> Int
decode2 [String]
xs))

decode1 :: String -> Int
decode1 :: String -> Int
decode1 = (Int -> String -> Int) -> String -> Int
mkDecode (\Int
n String
xs -> Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
* String -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
xs)

decode2 :: String -> Int
decode2 :: String -> Int
decode2 = (Int -> String -> Int) -> String -> Int
mkDecode (\Int
n String
xs -> Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
* String -> Int
decode2 String
xs)

mkDecode ::
  (Int -> String -> Int) {- ^ repeated segment logic -} ->
  String                 {- ^ input string           -} ->
  Int                    {- ^ decoded length         -}
mkDecode :: (Int -> String -> Int) -> String -> Int
mkDecode Int -> String -> Int
f = (Int, String) -> Int
forall a b. (a, b) -> a
fst ((Int, String) -> Int)
-> (String -> (Int, String)) -> String -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [(Int, String)] -> (Int, String)
forall a. HasCallStack => [a] -> a
head ([(Int, String)] -> (Int, String))
-> (String -> [(Int, String)]) -> String -> (Int, String)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ReadP Int -> String -> [(Int, String)]
forall a. ReadP a -> ReadS a
readP_to_S ([Int] -> Int
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum ([Int] -> Int) -> ReadP [Int] -> ReadP Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ReadP Int -> ReadP [Int]
forall a. ReadP a -> ReadP [a]
ReadP.many (ReadP Int
repeated ReadP Int -> ReadP Int -> ReadP Int
forall a. ReadP a -> ReadP a -> ReadP a
<++ ReadP Int
plain) ReadP Int -> ReadP () -> ReadP Int
forall a b. ReadP a -> ReadP b -> ReadP a
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* ReadP ()
eof)
  where
    number :: ReadP Int
number = String -> Int
forall a. Read a => String -> a
read (String -> Int) -> ReadP String -> ReadP Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Char -> Bool) -> ReadP String
munch1 Char -> Bool
isDigit
    plain :: ReadP Int
plain = String -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length (String -> Int) -> ReadP String -> ReadP Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Char -> Bool) -> ReadP String
munch1 (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/=Char
'(')
    repeated :: ReadP Int
repeated =
       do Int
len <- Char -> ReadP Char
char Char
'(' ReadP Char -> ReadP Int -> ReadP Int
forall a b. ReadP a -> ReadP b -> ReadP b
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> ReadP Int
number ReadP Int -> ReadP Char -> ReadP Int
forall a b. ReadP a -> ReadP b -> ReadP a
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* Char -> ReadP Char
char Char
'x'
          Int -> String -> Int
f (Int -> String -> Int) -> ReadP Int -> ReadP (String -> Int)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ReadP Int
number ReadP (String -> Int) -> ReadP Char -> ReadP (String -> Int)
forall a b. ReadP a -> ReadP b -> ReadP a
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* Char -> ReadP Char
char Char
')' ReadP (String -> Int) -> ReadP String -> ReadP Int
forall a b. ReadP (a -> b) -> ReadP a -> ReadP b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Int -> ReadP Char -> ReadP String
forall a. Int -> ReadP a -> ReadP [a]
ReadP.count Int
len ReadP Char
get