1
1
module Main where
2
2
3
3
import Control.Parallel.Strategies
4
+ import Data.Map (Map )
5
+ import Data.Map qualified as M
4
6
import Debug.Trace
5
7
import System.Environment
6
8
@@ -11,37 +13,52 @@ type Output = Int
11
13
parseInput :: String -> Input
12
14
parseInput = map read . words . head . lines
13
15
16
+ -- Number of digits in a number : digitCount 128 = 3
14
17
digitCount :: Int -> Int
15
18
digitCount i
16
19
| i < 10 = 1
17
20
| otherwise = 1 + digitCount (div i 10 )
18
21
19
- splitNumber :: Int -> Int -> [Int ]
20
- splitNumber n lengthn = [firstHalf, secondHalf]
22
+ -- Splits a number containing an even number of digits in 2 : splitNumber 2048 = [20, 48]
23
+ splitNumber :: Int -> [Int ]
24
+ splitNumber n = [firstHalf, secondHalf]
21
25
where
26
+ lengthn = {-# SCC stoneLength #-} digitCount n
22
27
powered10 = {-# SCC powered10 #-} (10 ^ (div lengthn 2 ))
23
28
firstHalf = {-# SCC firstHalf #-} div n powered10
24
29
secondHalf = {-# SCC secondHalf #-} n - (firstHalf * powered10)
25
30
26
- iterateStones :: [Int ] -> [Int ]
27
- iterateStones stones = concat $ map iterateStone stones
31
+ -- Main Algorithm of the day
32
+ iterateStone :: Int -> [Int ]
33
+ iterateStone 0 = [1 ]
34
+ iterateStone stone
35
+ | (== 0 ) . (`mod` 2 ) $ digitCount stone = splitNumber stone
36
+ | otherwise = [stone * 2024 ]
37
+
38
+ solveFold :: Map (Int , Int ) Int -> (Int , Int ) -> Map (Int , Int ) Int
39
+ solveFold memRes (stone, n)
40
+ | (stone, n) `M.member` memRes = memRes
41
+ | n == 1 = M. insert (stone, n) (length newStones) memRes
42
+ | otherwise = M. insert (stone, n) total memResFold
28
43
where
29
- iterateStone 0 = [1 ]
30
- iterateStone stone
31
- | isSplitable = splitNumber stone stoneLength
32
- | otherwise = [stone * 2024 ]
33
- where
34
- isSplitable = {-# SCC isSplitable #-} (== 0 ) $ (`mod` 2 ) stoneLength
35
- stoneLength = {-# SCC stoneLength #-} digitCount stone
44
+ newStones = iterateStone stone
45
+ newQuerries = zip newStones $ repeat (n - 1 )
46
+
47
+ memResFold = foldl solveFold memRes $ newQuerries
48
+
49
+ total = sum . map (memResFold M. ! ) $ newQuerries
36
50
37
51
solve :: Int -> Input -> Output
38
- solve n arr = length . fst . head . drop n $ iterate (\ (l, i) -> trace (show (i, length l)) (iterateStones l, i + 1 )) (arr, 0 )
52
+ solve n arr = sum $ map (solutions M. ! ) . zip arr $ repeat n
53
+ where
54
+ solutions :: Map (Int , Int ) Int
55
+ solutions = foldl solveFold M. empty . zip arr $ repeat n
39
56
40
57
part1 :: Input -> Output
41
58
part1 = solve 25
42
59
43
60
part2 :: Input -> Output
44
- part2 = solve 40
61
+ part2 = solve 75
45
62
46
63
main :: IO ()
47
64
main = do
@@ -51,5 +68,44 @@ main = do
51
68
52
69
print input
53
70
54
- print $ part1 input
55
- print $ (== 11965325 ) $ part2 input
71
+ let res1 = part1 input
72
+ -- print res1
73
+ print $ any (== res1) [55312 , 183484 ]
74
+ let res2 = part2 input
75
+ -- print res2
76
+ print $ any (== res2) [65601038650482 , 218817038947400 ]
77
+
78
+
79
+
80
+
81
+ -- Gets main algorithm using a memory map to avoid calculating the same result twice
82
+ -- lookUpIterateStone :: Map Int [Int] -> Int -> (Map Int [Int], [Int])
83
+ -- lookUpIterateStone mem n
84
+ -- | n `M.member` mem = (mem, mem M.! n)
85
+ -- | otherwise = (newMem, newArr)
86
+ -- where
87
+ -- newArr = iterateStone n
88
+ -- newMem = M.insert n newArr mem
89
+
90
+ -- solveFold :: (Map (Int, Int) Int, Map Int [Int]) -> (Int, Int) -> (Map (Int, Int) Int, Map Int [Int])
91
+ -- solveFold (memRes, mem1) (stone, n)
92
+ -- | (stone, n) `M.member` memRes = (memRes, mem1)
93
+ -- | n == 1 = (M.insert (stone, n) (length resLookUp) memRes, mem1LookUp)
94
+ -- | otherwise = (M.insert (stone, n) total memResFold, mem1Fold)
95
+ -- where
96
+ -- (mem1LookUp, resLookUp) = lookUpIterateStone mem1 stone
97
+ -- (memResSub1, mem1Sub1) = solveFold (memRes, mem1) (stone, n - 1)
98
+
99
+ -- newStones :: [Int]
100
+ -- newStones = mem1Sub1 M.! stone
101
+
102
+ -- newQuerries :: [(Int, Int)]
103
+ -- newQuerries = zip newStones $ repeat (n - 1)
104
+ -- (memResFold, mem1Fold) = foldl solveFold (memResSub1, mem1Sub1) $ newQuerries
105
+ -- total = sum . map (memResFold M.!) $ newQuerries
106
+
107
+ -- solve :: Int -> Input -> Output
108
+ -- solve n arr = sum $ map (solutions M.!) . zip arr $ repeat n
109
+ -- where
110
+ -- solutions :: Map (Int, Int) Int
111
+ -- solutions = fst . foldl solveFold (M.empty, M.empty) . zip arr $ repeat n
0 commit comments