--- /dev/null
+-- Writeup at https://work.njae.me.uk/2022/12/02/advent-of-code-2022-day-2/
+
+import System.Environment
+import Data.Text ()
+import qualified Data.Text.IO as TIO
+import Data.Attoparsec.Text hiding (Result)
+import Control.Applicative
+
+data Shape = Rock | Paper | Scissors deriving (Show, Eq, Ord, Enum)
+data Result = Loss | Draw | Win deriving (Show, Eq, Ord, Enum)
+data Round = Round Shape Shape deriving (Eq, Show)
+data ShapeResult = ShapeResult Shape Result deriving (Eq, Show)
+
+main :: IO ()
+main =
+ do dataFileName <- getDataFileName
+ text <- TIO.readFile dataFileName
+ let match1 = successfulParse1 text
+ print $ part1 match1
+ let match2 = successfulParse2 text
+ print $ part2 match2
+
+getDataFileName :: IO String
+getDataFileName =
+ do args <- getArgs
+ progName <- getProgName
+ let baseDataName = if null args
+ then progName
+ else head args
+ let dataFileName = "data/" ++ baseDataName ++ ".txt"
+ return dataFileName
+
+part1 :: [Round] -> Int
+part1 = sum . fmap scoreRound
+
+part2 :: [ShapeResult] -> Int
+part2 = sum . fmap (scoreRound . roundFromResult)
+
+player2Result :: Round -> Result
+player2Result (Round Rock Paper) = Win
+player2Result (Round Paper Scissors) = Win
+player2Result (Round Scissors Rock) = Win
+player2Result (Round x y) | x == y = Draw
+player2Result _ = Loss
+
+scoreRound :: Round -> Int
+scoreRound r@(Round _ y) = scoreShape y + scoreResult (player2Result r)
+
+scoreShape :: Shape -> Int
+scoreShape s = 1 + fromEnum s
+
+scoreResult :: Result -> Int
+scoreResult r = 3 * fromEnum r
+
+roundFromResult :: ShapeResult -> Round
+roundFromResult (ShapeResult shape result) = Round shape p2s
+ where p2s = head [ p2Shape
+ | p2Shape <- [Rock .. Scissors]
+ , player2Result (Round shape p2Shape) == result
+ ]
+
+-- Parse the input file
+
+match1P = roundP `sepBy` endOfLine
+roundP = Round <$> p1ShapeP <*> (" " *> p2ShapeP)
+
+match2P = shapeResultP `sepBy` endOfLine
+shapeResultP = ShapeResult <$> p1ShapeP <*> (" " *> resultP)
+
+p1ShapeP = aP <|> bP <|> cP
+aP = Rock <$ "A"
+bP = Paper <$ "B"
+cP = Scissors <$ "C"
+
+p2ShapeP = xP <|> yP <|> zP
+xP = Rock <$ "X"
+yP = Paper <$ "Y"
+zP = Scissors <$ "Z"
+
+resultP = xrP <|> yrP <|> zrP
+xrP = Loss <$ "X"
+yrP = Draw <$ "Y"
+zrP = Win <$ "Z"
+
+-- successfulParse :: Text -> (Integer, [Maybe Integer])
+successfulParse1 input =
+ case parseOnly match1P input of
+ Left _err -> [] -- TIO.putStr $ T.pack $ parseErrorPretty err
+ Right match -> match
+
+successfulParse2 input =
+ case parseOnly match2P input of
+ Left _err -> [] -- TIO.putStr $ T.pack $ parseErrorPretty err
+ Right match -> match