-- ---
-- jupyter:
--   jupytext:
--     text_representation:
--       extension: .hs
--       format_name: light
--       format_version: '1.5'
--       jupytext_version: 1.14.4
--   kernelspec:
--     display_name: Haskell
--     language: haskell
--     name: haskell
-- ---

-- # Day 9: Explosives in Cyberspace

inputLines = lines <$> readFile "input/day9.txt"

decompressedLength :: Bool -> String -> Int
decompressedLength recursive xs = decompressedLength' xs
    where
        -- getSequenceLength determines the (decompressed) length of the sequence after a marker.
        getSequenceLength :: String -> Int
        getSequenceLength = if recursive then decompressedLength' else length

        -- It seems that there are currently no Haskell modules for regular expressions in
        -- ihaskell, so we parse the markers manually.
        decompressedLength' "" = 0
        decompressedLength' ('(':xs) = parseSequenceLength xs
        decompressedLength' xs = length beforeMarker + decompressedLength' rest
            where (beforeMarker, rest) = span (/= '(') xs

        -- The beginning of ys is the length declaration inside a marker.
        -- Parse it and continue processing.
        parseSequenceLength :: String -> Int
        parseSequenceLength ys = parseCount (read markerLength) $ tail rest
            where
                (markerLength, rest) = span (/= 'x') ys
            
        -- The beginning of ys is the repeat count declaration inside a marker.
        -- Parse it and continue processing.
        parseCount :: Int -> String -> Int
        parseCount markerLength ys = parseSequence markerLength (read markerCount) $ tail rest
            where
                (markerCount, rest) = span (/= ')') ys

        -- The beginning of ys is the string after the marker. Calculate the total decompressed
        -- length of the marker and add the decompressed length of the remainder.
        parseSequence :: Int -> Int -> String -> Int
        parseSequence markerLength markerCount ys =
            markerCount * getSequenceLength zs + decompressedLength' rest
            where
                (zs, rest) = splitAt markerLength ys

-- # Part 1: No recursive decompression of markers

decompressedLength1 = decompressedLength False

-- Verify the given expample results.
decompressedLength1 "ADVENT"
decompressedLength1 "A(1x5)BC"
decompressedLength1 "(3x3)XYZ"
decompressedLength1 "A(2x2)BCD(2x2)EFG"
decompressedLength1 "(6x1)(1x3)A"
decompressedLength1 "X(8x2)(3x3)ABCY"

decompressedLength1 . head <$> inputLines

-- # Part 2: Decompress markers recursively

decompressedLength2 = decompressedLength True

-- Verify the given expample results.
decompressedLength2 "(3x3)XYZ"
decompressedLength2 "X(8x2)(3x3)ABCY"
decompressedLength2 "(27x12)(20x12)(13x14)(7x10)(1x12)A"
decompressedLength2 "(25x3)(3x3)ABC(2x3)XY(5x2)PQRSTX(18x9)(3x2)TWO(5x7)SEVEN"

decompressedLength2 . head <$> inputLines

StarcoderdataJupyterScriptsDedupFiltered