--- /dev/null
+-- Writeup at https://work.njae.me.uk/2022/12/10/advent-of-code-2022-day-9/
+
+import AoC
+import Data.Text (Text)
+import qualified Data.Text.IO as TIO
+import Data.Attoparsec.Text hiding (take)
+import Control.Applicative
+import Data.List
+import Data.List.Split (chunksOf)
+
+data Operation = Noop | Addx Int
+ deriving (Show, Eq)
+
+type Signal = (Int, Int) -- during cycle, register
+
+main :: IO ()
+main =
+ do dataFileName <- getDataFileName
+ text <- TIO.readFile dataFileName
+ let ops = successfulParse text
+ let regVals = apply ops
+ print $ part1 regVals
+ putStrLn $ part2 regVals
+
+part1 :: [Signal] -> Int
+part1 regVals = calculateSixSignals $ extractSignals regVals
+
+part2 :: [Signal] -> String
+part2 regVals = unlines display
+ where pixels = map isLit regVals
+ rows = chunksOf 40 pixels
+ display = fmap (fmap showPixel) rows
+
+apply :: [Operation] -> [Signal]
+apply ops = zip [1..] $ scanl' (+) 1 $ concatMap applyOp ops
+
+applyOp :: Operation -> [Int]
+applyOp Noop = [0]
+applyOp (Addx d) = [0, d]
+
+extractSignals :: [Signal] -> [Signal]
+extractSignals signals = filter (\(t, _n) -> (t + 20) `mod` 40 == 0) signals
+
+calculateSixSignals :: [Signal] -> Int
+calculateSixSignals signals = sum [ (t * n)
+ | (t, n) <- signals
+ , t <= 220
+ ]
+
+
+isLit :: Signal -> Bool
+isLit (n, x) = abs (x - c) <= 1
+ where c = colummOf n
+
+colummOf :: Int -> Int
+-- colummOf n = (n - 1) `mod` 40 + 1
+colummOf n = (n - 1) `mod` 40
+
+showPixel :: Bool -> Char
+-- showPixel True = '#'
+-- showPixel False = '.'
+showPixel True = '█'
+showPixel False = ' '
+
+-- Parse the input file
+
+operationsP :: Parser [Operation]
+operationP, noopP, addxP :: Parser Operation
+
+operationsP = operationP `sepBy` endOfLine
+operationP = noopP <|> addxP
+noopP = Noop <$ "noop"
+addxP = Addx <$> ("addx " *> signed decimal)
+
+successfulParse :: Text -> [Operation]
+successfulParse input =
+ case parseOnly operationsP input of
+ Left _err -> [] -- TIO.putStr $ T.pack $ parseErrorPretty err
+ Right ops -> ops