diff --git a/Day9/puzzle2.hs b/Day9/puzzle2.hs new file mode 100644 index 0000000..524eeff --- /dev/null +++ b/Day9/puzzle2.hs @@ -0,0 +1,61 @@ +import Data.List (intersperse, groupBy) +import Data.Char (digitToInt) +import Data.Maybe (fromMaybe) +import Data.Function (on) +import qualified Data.Sequence as S +import qualified Data.Foldable as F + +type DiskElem = (Int, Int) + +parseDiskMap :: [Int] -> S.Seq DiskElem +parseDiskMap xs = let values = intersperse (-1) [0..] + in S.fromList $ zip values xs + +isSpaceEnough :: Int -> DiskElem -> Bool +isSpaceEnough n (-1, l) = l >= n +isSpaceEnough _ _ = False + +updateSpace :: Int -> DiskElem -> DiskElem +updateSpace n (-1, l) = (-1, l - n) + +combineSpace :: DiskElem -> DiskElem -> DiskElem +combineSpace (-1, l1) (-1, l2) = (-1, l1 + l2) + +compareFileValue :: Int -> DiskElem -> Bool +compareFileValue x (v, _) = x == v + +moveFile :: Int -> Int -> DiskElem -> DiskElem -> S.Seq DiskElem -> S.Seq DiskElem +moveFile i sIndex sVal fVal xs = let xs' = F.toList . S.insertAt sIndex fVal . S.insertAt sIndex sVal . S.deleteAt sIndex . S.insertAt i (-1, snd fVal) $ S.deleteAt i xs + in S.fromList $ map (foldl1 combineSpace) $ groupBy ((==) `on` fst) xs' + +compactFiles :: Int -> S.Seq DiskElem -> S.Seq DiskElem +compactFiles (-1) xs = xs +compactFiles 0 xs = xs +compactFiles n xs = if fst fVal == -1 || sIndex == -1 || sIndex >= n + then compactFiles (n - 1) xs + else compactFiles fIndex xs' + where fVal = S.index xs n + sIndex = fromMaybe (-1) $ S.findIndexL (isSpaceEnough (snd fVal)) xs + sVal = updateSpace (snd fVal) (fromMaybe (-1, 0) $ S.lookup sIndex xs) + xs' = moveFile n sIndex sVal fVal xs + fIndex = fromMaybe (-1) $ S.findIndexR (compareFileValue (fst fVal - 1)) xs' + +maskMinus1 :: [Int] -> [Int] +maskMinus1 [] = [] +maskMinus1 (l:ls) + | l == -1 = 0:maskMinus1 ls + | otherwise = l:maskMinus1 ls + +tuplesToIntList :: S.Seq DiskElem -> [Int] +tuplesToIntList disk = let listDisk = F.toList disk + in concatMap (\x -> replicate (snd x) (fst x)) listDisk + +checksum :: [Int] -> Int +checksum xs = sum $ zipWith (*) (maskMinus1 xs) [0..] + +main = do + contents <- init <$> readFile "day9.txt" + let disk = parseDiskMap $ map digitToInt contents + i = fromMaybe (-1) $ S.findIndexR (\x -> fst x /= -1) disk + compactedDisk = tuplesToIntList $ S.filter (\x -> snd x > 0) $ compactFiles i disk + print $ checksum compactedDisk