This repository was archived by the owner on Nov 17, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathDay16.hs
98 lines (85 loc) · 2.8 KB
/
Day16.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
-- |
-- Module : AOC.Challenge.Day16
-- License : BSD3
--
-- Stability : experimental
-- Portability : non-portable
--
-- Day 16. See "AOC.Solver" for the types used in this module!
module AOC.Challenge.Day16 (
day16a
, day16b
, binom99
) where
import AOC.Common ((!!!), digitToIntSafe)
import AOC.Solver ((:~>)(..))
import Control.Monad
import Control.Monad.ST (runST)
import Control.Monad.State (evalStateT, get, put)
import Data.Foldable (forM_)
import Data.List (tails, unfoldr)
import Data.Maybe (mapMaybe)
import qualified Data.Vector.Storable as VS
import qualified Data.Vector.Storable.Mutable as MVS
day16a :: [Int] :~> [Int]
day16a = MkSol
{ sParse = Just . mapMaybe digitToIntSafe
, sShow = concatMap show
, sSolve = Just
. VS.toList
. VS.take 8
. (!!! 100)
. iterate stepVec
. VS.fromList
}
day16b :: [Int] :~> [Int]
day16b = MkSol
{ sParse = Just . mapMaybe digitToIntSafe
, sShow = concatMap show
, sSolve = \str ->
let origLen = length str
n = read . concatMap show $ take 7 str
startPoint = n `mod` origLen
endPoint = origLen * 10000 - n
xs = take endPoint . drop startPoint . cycle $ str
result = map (`dot` binom99) (tails xs)
good = n >= (origLen * 5000)
in take 8 result <$ guard good
}
where
dot xs ys = (`mod` 10) . sum . map (`mod` 10) $ zipWith (*) xs ys
-- | Binomial(n+99,99)
binom99 :: [Int]
binom99 = fromIntegral . (`mod` 10) <$> unfoldr go (99, fac99)
where
fac99 :: Integer
fac99 = product [1..99]
go (id->(!n, !nfac)) = Just (x, (n', nfac'))
where
x = nfac `div` fac99
n' = n + 1
nfac' = (nfac `div` (n' - 99)) * n'
-- | needlessly over-optimized
stepVec :: VS.Vector Int -> VS.Vector Int
stepVec v = runST $ do
mv <- MVS.replicate (VS.length v) 0
flip evalStateT (0,[]) . flip VS.mapM_ v $ \x -> do
(i, steps0) <- get
let !i' = i + 1
!steps = newStep (i + 1) : map succStep steps0
put (i', steps)
forM_ (zip [0..] steps) $ \(j, s) ->
forM_ (stepOut s) $ \q ->
MVS.modify mv ((q * x) +) (i - j)
VS.map ((`mod` 10) . abs) <$> VS.freeze mv
data Step = Step { sSize :: !Int, sPhase :: !Int }
deriving Show
stepOut :: Step -> Maybe Int
stepOut Step{..} = case (sPhase `div` sSize) `mod` 4 of
0 -> Just 1
2 -> Just (-1)
_ -> Nothing
succStep :: Step -> Step
succStep Step{..} = Step sSize (sPhase + 1)
newStep :: Int -> Step
newStep n = Step n 0