mirror of
https://github.com/mx42/adventofcode.git
synced 2026-01-14 22:09:50 +01:00
79 lines
3.1 KiB
Haskell
79 lines
3.1 KiB
Haskell
module Y2015.Day06 (y15day06) where
|
|
|
|
import Data.List.Split
|
|
|
|
data Ranges = Ranges {
|
|
minWidth :: Int
|
|
, maxWidth :: Int
|
|
, minHeight :: Int
|
|
, maxHeight :: Int
|
|
} deriving Show
|
|
|
|
data Instruction = Toggle Ranges | TurnOn Ranges | TurnOff Ranges deriving Show
|
|
|
|
type Lights = [Bool]
|
|
|
|
getRanges :: [String] -> Ranges
|
|
getRanges parts = Ranges minW maxW minH maxH
|
|
where start = map read $ splitOn "," $ parts !! 0 :: [Int]
|
|
end = map read $ splitOn "," $ parts !! 2 :: [Int]
|
|
widths = [start !! 0, end !! 0]
|
|
heights = [start !! 1, end !! 1]
|
|
minW = minimum widths
|
|
maxW = maximum widths
|
|
minH = minimum heights
|
|
maxH = maximum heights
|
|
|
|
parseEntry :: [String] -> Instruction
|
|
parseEntry parts
|
|
| parts !! 0 == "turn" && parts !! 1 == "on" = TurnOn $ getRanges $ tail $ tail $ parts
|
|
| parts !! 0 == "turn" && parts !! 1 == "off" = TurnOff $ getRanges $ tail $ tail $ parts
|
|
| parts !! 0 == "toggle" = Toggle $ getRanges $ tail $ parts
|
|
|
|
applyInstructionP1 :: (Int, Int) -> Bool -> Instruction -> Bool
|
|
applyInstructionP1 (x, y) cur (TurnOn (Ranges minX maxX minY maxY))
|
|
| x >= minX && x <= maxX && y >= minY && y <= maxY = True
|
|
| otherwise = cur
|
|
applyInstructionP1 (x, y) cur (TurnOff (Ranges minX maxX minY maxY))
|
|
| x >= minX && x <= maxX && y >= minY && y <= maxY = False
|
|
| otherwise = cur
|
|
applyInstructionP1 (x, y) cur (Toggle (Ranges minX maxX minY maxY))
|
|
| x >= minX && x <= maxX && y >= minY && y <= maxY = not cur
|
|
| otherwise = cur
|
|
|
|
applyInstructionsP1 :: [Instruction] -> Bool -> (Int, Int) -> Bool
|
|
applyInstructionsP1 [] cur _ = cur
|
|
applyInstructionsP1 (inst:next) cur pos = applyInstructionsP1 next newState pos
|
|
where newState = applyInstructionP1 pos cur inst
|
|
|
|
countLightsP1 :: [Instruction] -> Int
|
|
countLightsP1 instr = length $ filter (== True) $ map (applyInstructionsP1 instr False) allPos
|
|
where allPos = map (\n -> (n `div` 1000, mod n 1000)) $ take 1000000 $ iterate (+1) 0
|
|
|
|
applyInstructionP2 :: (Int, Int) -> Int -> Instruction -> Int
|
|
applyInstructionP2 (x, y) cur (TurnOn (Ranges minX maxX minY maxY))
|
|
| x >= minX && x <= maxX && y >= minY && y <= maxY = cur + 1
|
|
| otherwise = cur
|
|
applyInstructionP2 (x, y) cur (TurnOff (Ranges minX maxX minY maxY))
|
|
| x >= minX && x <= maxX && y >= minY && y <= maxY && cur > 0 = cur - 1
|
|
| otherwise = cur
|
|
applyInstructionP2 (x, y) cur (Toggle (Ranges minX maxX minY maxY))
|
|
| x >= minX && x <= maxX && y >= minY && y <= maxY = cur + 2
|
|
| otherwise = cur
|
|
|
|
applyInstructionsP2 :: [Instruction] -> Int -> (Int, Int) -> Int
|
|
applyInstructionsP2 [] cur _ = cur
|
|
applyInstructionsP2 (inst:next) cur pos = applyInstructionsP2 next newState pos
|
|
where newState = applyInstructionP2 pos cur inst
|
|
|
|
countLightsP2 :: [Instruction] -> Int
|
|
countLightsP2 instr = sum $ map (applyInstructionsP2 instr 0) allPos
|
|
where allPos = map (\n -> (n `div` 1000, mod n 1000)) $ take 1000000 $ iterate (+1) 0
|
|
|
|
|
|
y15day06 :: [String] -> (String, String)
|
|
y15day06 input = (part1, part2)
|
|
where part1 = show $ countLightsP1 instructions
|
|
part2 = show $ countLightsP2 instructions
|
|
instructions = map (parseEntry . splitOn " ") input
|