|
| 1 | +module Main where |
| 2 | +import Debug.Trace |
| 3 | +import System.Environment |
| 4 | + |
| 5 | +type Input = [Int] |
| 6 | +type Output = Int |
| 7 | + |
| 8 | +parseInput :: String -> Input |
| 9 | +parseInput = map (\c -> read [c]) . filter (/= '\n') |
| 10 | + |
| 11 | +expand :: [Int] -> [Int] |
| 12 | +expand = concat . map (\(i, n) -> replicate n (if i `mod` 2 == 0 then (i `div` 2) else -1)) . zip [0..] |
| 13 | + |
| 14 | +exchangeAt :: [a] -> Int -> a -> [a] |
| 15 | +exchangeAt arr i e = elsBefore ++ [e] ++ elsAfter |
| 16 | + where |
| 17 | + (elsBefore, _:elsAfter) = splitAt i arr |
| 18 | + |
| 19 | +retract :: [Int] -> [Int] |
| 20 | +retract arr = sub arr (reverse arr) 0 (length arr - 1) |
| 21 | + where |
| 22 | + sub arr rev i j |
| 23 | + | i == j = [head arr] |
| 24 | + | head arr /= -1 = head arr : sub (drop 1 arr) rev (i+1) j |
| 25 | + | head rev == -1 = sub arr (drop 1 rev) i (j-1) |
| 26 | + | otherwise = head rev: sub (drop 1 arr) (drop 1 rev) (i+1) (j-1) |
| 27 | + |
| 28 | + |
| 29 | +part1 :: Input -> Int |
| 30 | +part1 = sum . map (uncurry (*)) . zip [0..] . retract . expand |
| 31 | + |
| 32 | + |
| 33 | +-- Artifact of previous version in which I segmented the drive as (id, size) (id -1 beeing free) but had the issue of [(-1, 2), (-1, 3)] which should be converted to [(-1, 5)] |
| 34 | +-- and meant to pass onee more time on the array => seemed either slow or more complicated even if doable |
| 35 | +-- expand2 :: [Int] -> [(Int, Int)] |
| 36 | +-- expand2 = map (\(i, n) -> (if i `mod` 2 == 0 then (i `div` 2) else -1, n)) . zip [0..] |
| 37 | + |
| 38 | +-- retract2 :: [(Int, Int)] -> [(Int, Int)] |
| 39 | +-- retract2 arr = foldl (\res (j, (idi, size)) -> sub res 0 j (idi, size)) arr $ zip (reverse [0..length arr - 1]) arr |
| 40 | +-- where |
| 41 | +-- sub :: [(Int, Int)] -> Int -> Int -> (Int, Int) -> Bool -> [(Int, Int)] |
| 42 | +-- sub arr i j (idi, size) added |
| 43 | +-- | added && i == j = (-1, size) : (drop 1 arr) |
| 44 | +-- | i >= j = arr |
| 45 | +-- | idi == -1 = arr |
| 46 | +-- | (fst $ head arr) /= -1 = head arr : sub (drop 1 arr) (i+1) j (idi, size) added |
| 47 | +-- | (snd $ head arr) < size = head arr : sub (drop 1 arr) (i+1) j (idi, size) added |
| 48 | +-- | (snd $ head arr) == size = (idi, size) : sub (drop 1 arr) (i+1) j (idi, size) True |
| 49 | +-- | (snd $ head arr) > size = (idi, size) : (-1, (snd $ head arr) - size) : sub (drop 1 arr) (i+1) j (idi, size) True |
| 50 | +-- sub2 arr rev j |
| 51 | +-- | rev == [] = arr |
| 52 | +-- | (fst $ head rev) == -1 = sub2 arr (drop 1 rev) (j-1) |
| 53 | +-- | otherwise = sub arr 0 j head (rev) |
| 54 | + |
| 55 | + |
| 56 | +-- exchangeAt :: [a] -> Int -> a -> [a] |
| 57 | +-- exchangeAt arr i e = elsBefore ++ [e] ++ elsAfter |
| 58 | +-- where |
| 59 | + -- (elsBefore, _:elsAfter) = splitAt i arr |
| 60 | + |
| 61 | +retract2 :: [Int] -> [Int] |
| 62 | +retract2 arr = {-# SCC sub2 #-} sub2 arr (reverse arr) (length arr -1) |
| 63 | + where |
| 64 | + sub arr jBlock i j |
| 65 | + | i >= j = arr |
| 66 | + | head arr /= -1 = iBlock ++ {-# SCC notFreeSubCall #-} sub (drop leni arr) jBlock (i+leni) j |
| 67 | + | leni < lenj = iBlock ++ {-# SCC tooSmallSubCall #-} sub (drop leni arr) jBlock (i+leni) j |
| 68 | + | otherwise = jBlock ++ {-# SCC removeElt #-} removeElt (head jBlock) (drop lenj arr) |
| 69 | + where |
| 70 | + iBlock = takeWhile (== (head arr)) arr |
| 71 | + leni = length iBlock |
| 72 | + lenj = length jBlock |
| 73 | + |
| 74 | + removeElt elt arr = map (\e -> if e == elt then -1 else e) arr |
| 75 | + |
| 76 | + sub2 arr rev j |
| 77 | + | j <= 0 = arr |
| 78 | + | head rev == -1 = sub2 arr (drop lenj rev) (j - lenj) |
| 79 | + | otherwise = sub2 ({-# SCC firstSubCall #-} sub arr jBlock 0 (j-lenj)) (drop lenj rev) (j - lenj) |
| 80 | + where |
| 81 | + jBlock = takeWhile (== (head rev)) rev |
| 82 | + lenj = length jBlock |
| 83 | + |
| 84 | + |
| 85 | +part2 :: Input -> Output |
| 86 | +part2 = sum . map (uncurry (*)) . filter ((/= -1) . snd) . zip [0..] . retract2 . expand |
| 87 | + |
| 88 | +main :: IO () |
| 89 | +main = do |
| 90 | + args <- getArgs |
| 91 | + content <- readFile (last args) |
| 92 | + let input = parseInput content |
| 93 | + |
| 94 | + print $ part1 input |
| 95 | + print $ part2 input |
0 commit comments