1 -- Writeup at https://work.njae.me.uk/2022/12/02/advent-of-code-2022-day-2/
4 import Data.Text (Text)
5 import qualified Data.Text.IO as TIO
6 import Data.Attoparsec.Text hiding (Result)
7 import Control.Applicative
9 data Shape = Rock | Paper | Scissors deriving (Show, Eq, Ord, Enum, Bounded)
10 data Result = Loss | Draw | Win deriving (Show, Eq, Ord, Enum)
11 data Round = Round Shape Shape deriving (Eq, Show)
12 data ShapeResult = ShapeResult Shape Result deriving (Eq, Show)
16 do dataFileName <- getDataFileName
17 text <- TIO.readFile dataFileName
18 let match1 = successfulParse1 text
20 let match2 = successfulParse2 text
23 part1 :: [Round] -> Int
24 part1 = sum . fmap scoreRound
26 part2 :: [ShapeResult] -> Int
27 part2 = sum . fmap (scoreRound . roundFromResult)
29 player2Result :: Round -> Result
30 player2Result (Round Rock Paper) = Win
31 player2Result (Round Paper Scissors) = Win
32 player2Result (Round Scissors Rock) = Win
33 player2Result (Round x y) | x == y = Draw
34 player2Result _ = Loss
36 scoreRound :: Round -> Int
37 scoreRound r@(Round _ y) = scoreShape y + scoreResult (player2Result r)
39 scoreShape :: Shape -> Int
40 scoreShape s = 1 + fromEnum s
42 scoreResult :: Result -> Int
43 scoreResult r = 3 * fromEnum r
45 roundFromResult :: ShapeResult -> Round
46 roundFromResult (ShapeResult shape result) = Round shape p2s
47 where p2s = head [ p2Shape
48 -- | p2Shape <- [Rock .. Scissors]
49 | p2Shape <- [minBound .. maxBound]
50 , player2Result (Round shape p2Shape) == result
53 -- Parse the input file
55 match1P :: Parser [Round]
56 match2P :: Parser [ShapeResult]
57 roundP :: Parser Round
58 shapeResultP :: Parser ShapeResult
59 p1ShapeP, p2ShapeP, aP, bP, cP, xP, yP, zP :: Parser Shape
60 resultP, xrP, yrP, zrP :: Parser Result
62 match1P = roundP `sepBy` endOfLine
63 roundP = Round <$> p1ShapeP <*> (" " *> p2ShapeP)
65 match2P = shapeResultP `sepBy` endOfLine
66 shapeResultP = ShapeResult <$> p1ShapeP <*> (" " *> resultP)
68 p1ShapeP = aP <|> bP <|> cP
73 p2ShapeP = xP <|> yP <|> zP
78 resultP = xrP <|> yrP <|> zrP
83 successfulParse1 :: Text -> [Round]
84 successfulParse1 input =
85 case parseOnly match1P input of
86 Left _err -> [] -- TIO.putStr $ T.pack $ parseErrorPretty err
87 Right matches -> matches
89 successfulParse2 :: Text -> [ShapeResult]
90 successfulParse2 input =
91 case parseOnly match2P input of
92 Left _err -> [] -- TIO.putStr $ T.pack $ parseErrorPretty err
93 Right matches -> matches