112 lines
3.2 KiB
Haskell
112 lines
3.2 KiB
Haskell
{-# LANGUAGE OverloadedStrings #-}
|
|
{-# OPTIONS_GHC -Wno-unused-do-bind #-}
|
|
|
|
module Day2 where
|
|
|
|
import Data.Attoparsec.ByteString.Char8 as A
|
|
import Data.Either (fromRight)
|
|
import Data.String (fromString)
|
|
import Data.Maybe
|
|
|
|
-- import Debug.Trace
|
|
|
|
main :: IO ()
|
|
main = do
|
|
dayInput <- readFile "inputs/day2.input"
|
|
putStrLn "Part 1 result:"
|
|
print $ part1 dayInput
|
|
putStrLn "Part 2 result:"
|
|
print $ part2 dayInput
|
|
|
|
data GameSpec =
|
|
GameSpec { gameSpecId :: Int, gameSpecInstances :: [GameInstance] }
|
|
deriving (Show)
|
|
|
|
data GameInstance = GameInstance
|
|
{ redDice :: Maybe Int
|
|
, greenDice :: Maybe Int
|
|
, blueDice :: Maybe Int
|
|
}
|
|
deriving (Show, Ord, Eq)
|
|
|
|
data Dice = RedDice Int
|
|
| GreenDice Int
|
|
| BlueDice Int
|
|
deriving Show
|
|
|
|
-- Returns a *new* maximal game instance, and not necessarily an existing game
|
|
-- instance
|
|
maxCubes :: [GameInstance] -> GameInstance
|
|
maxCubes gix = GameInstance (maxRed gix) (maxGreen gix) (maxBlue gix)
|
|
where
|
|
maxRed = maximum . map redDice
|
|
maxGreen = maximum . map greenDice
|
|
maxBlue = maximum . map blueDice
|
|
|
|
-- Determine which games would have been possible if the bag had been loaded
|
|
-- with only 12 red cubes, 13 green cubes, and 14 blue cubes.
|
|
part1 :: String -> String
|
|
part1 = show
|
|
. sum
|
|
. mapMaybe (possibleGame1 (GameInstance (Just 12) (Just 13) (Just 14)))
|
|
. parseInput
|
|
|
|
possibleGame1 :: GameInstance -> GameSpec -> Maybe Int
|
|
possibleGame1 spec actual =
|
|
if maxCubes [spec, maxCubes $ gameSpecInstances actual] == spec
|
|
then Just $ gameSpecId actual
|
|
else Nothing
|
|
|
|
part2 :: String -> String
|
|
part2 = show
|
|
. sum
|
|
. map possibleGame2
|
|
. parseInput
|
|
|
|
-- Fewest number of cubes of each color
|
|
possibleGame2 :: GameSpec -> Int
|
|
possibleGame2 actual = red * green * blue
|
|
where
|
|
maxInstance = maxCubes $ gameSpecInstances actual
|
|
red = fromMaybe 0 $ redDice maxInstance
|
|
green = fromMaybe 0 $ greenDice maxInstance
|
|
blue = fromMaybe 0 $ blueDice maxInstance
|
|
|
|
parseInput :: String -> [GameSpec]
|
|
parseInput = fromRight [] . parseOnly input . fromString
|
|
where
|
|
input :: Parser [GameSpec]
|
|
input = line `sepBy` endOfLine
|
|
|
|
-- Game 3: 8 green, 6 blue, 20 red; 5 blue, 4 red, 13 green; 5 green, 1 red
|
|
line :: Parser GameSpec
|
|
line = GameSpec <$> gameId <*> gameInstances
|
|
|
|
gameId :: Parser Int
|
|
gameId = "Game" *> space *> decimal <* ": "
|
|
|
|
gameInstances :: Parser [GameInstance]
|
|
gameInstances = sepBy gameInstance "; "
|
|
|
|
gameInstance :: Parser GameInstance
|
|
gameInstance =
|
|
sortThatShit <$> sepBy1
|
|
( choice [ RedDice <$> (decimal :: Parser Int) <* space <* "red"
|
|
, GreenDice <$> (decimal :: Parser Int) <* space <* "green"
|
|
, BlueDice <$> (decimal :: Parser Int) <* space <* "blue"
|
|
] :: Parser Dice
|
|
) ", "
|
|
where
|
|
sortThatShit :: [Dice] -> GameInstance
|
|
sortThatShit dx = GameInstance
|
|
(lookup "red" axs)
|
|
(lookup "green" axs)
|
|
(lookup "blue" axs)
|
|
where
|
|
axs = map toPair dx
|
|
toPair :: Dice -> (String,Int)
|
|
toPair (RedDice i) = ("red", i)
|
|
toPair (GreenDice i) = ("green", i)
|
|
toPair (BlueDice i) = ("blue", i)
|
|
|