97 lines
3.4 KiB
Haskell
97 lines
3.4 KiB
Haskell
module Day10Lib
|
|
( day10
|
|
, day10'
|
|
) where
|
|
|
|
import Data.List (transpose)
|
|
|
|
data Instruction = Noop | Addx Int deriving (Show)
|
|
type Register = Int
|
|
type Cycle = Int
|
|
|
|
type Computer = (Register, Cycle)
|
|
|
|
processInstruction :: Computer -> Instruction -> [Computer]
|
|
processInstruction (r, c) (Addx x) = [(r,c + 1), (r + x, c + 2)]
|
|
processInstruction (r, c) Noop = [(r,c + 1)]
|
|
|
|
processInstructions :: Computer -> [Instruction] -> [Computer]
|
|
processInstructions comp@(r,c) (ins:inss) = processedComps ++ processInstructions processedComp inss
|
|
-- | c == 220 = [processedComp]
|
|
-- -- | c == 20 = processedComp : r * c + processInstructions processedComp inss
|
|
-- -- | c `mod` 40 == 0 = r * c + processInstructions processedComp inss
|
|
-- | otherwise = processedComp : processInstructions processedComp inss
|
|
where
|
|
processedComps = processInstruction comp ins
|
|
processedComp = last processedComps
|
|
|
|
-- PARSING
|
|
convertToInt :: String -> Int
|
|
convertToInt s = read s :: Int
|
|
|
|
parseInstruction :: String -> Instruction
|
|
parseInstruction s = case firstPart of
|
|
"noop" -> Noop
|
|
"addx" -> Addx lastPart
|
|
where
|
|
asWords = words s
|
|
firstPart = head asWords
|
|
lastPart = convertToInt $ last asWords
|
|
|
|
parseInput :: String -> [Instruction]
|
|
parseInput i = map parseInstruction $ lines i
|
|
|
|
-- Increment cycle by 1 to account for offset of looking at previous cycle to determine during cycle value
|
|
accountForDuringCycleOffset :: Computer -> Computer
|
|
accountForDuringCycleOffset (r, c) = (r, c + 1)
|
|
|
|
getSignalStrength :: Computer -> Int
|
|
getSignalStrength (r, c) = r * c
|
|
|
|
day10 :: String -> Int
|
|
day10 input = registerSum
|
|
where
|
|
-- There are less instructions than cycles we are interested in
|
|
-- The problem isn't clear about this but I believe the program loops
|
|
instructions = cycle $ parseInput input
|
|
-- Infinite computer list
|
|
startingState = (1,0)
|
|
icl = processInstructions (1, 0) instructions
|
|
-- -2 on all indexs, one for zero indexing the other for being about the value _during_ the cycle
|
|
cyclesOfInterest = [icl !! 18, icl !! 58, icl !! 98, icl !! 138, icl !! 178, icl !! 218]
|
|
registers = map getSignalStrength $ map accountForDuringCycleOffset cyclesOfInterest
|
|
registerSum = sum registers
|
|
|
|
type Pixel = Bool
|
|
|
|
drawPixel :: Pixel -> Char
|
|
drawPixel False = '.'
|
|
drawPixel True = '#'
|
|
|
|
drawPixelGrid :: [[Pixel]] -> String
|
|
drawPixelGrid grid = unlines $ map (map drawPixel) grid
|
|
|
|
rowifyPixelList :: [Pixel] -> [[Pixel]]
|
|
rowifyPixelList pl = [r1, r2, r3, r4, r5, r6]
|
|
where
|
|
r1 = take 40 pl
|
|
r2 = take 40 $ drop 40 pl
|
|
r3 = take 40 $ drop 80 pl
|
|
r4 = take 40 $ drop 120 pl
|
|
r5 = take 40 $ drop 160 pl
|
|
r6 = take 40 $ drop 200 pl
|
|
|
|
zipPixelListWithComputerList :: Computer -> Int -> Pixel
|
|
zipPixelListWithComputerList (r, c) pindex = if r == horizontalPostion || r - horizontalPostion == 1 || r - horizontalPostion == -1
|
|
then True
|
|
else False
|
|
where horizontalPostion = pindex `mod` 40
|
|
|
|
day10' :: String -> String
|
|
day10' input = drawPixelGrid $ rowifyPixelList $ zipWith zipPixelListWithComputerList icl pixelgrid
|
|
where
|
|
instructions = cycle $ parseInput input
|
|
startingState = (1,0)
|
|
icl = startingState : processInstructions (1, 0) instructions
|
|
pixelgrid = [0..239]
|