Done day 2
[advent-of-code-22.git] / advent02 / Main.hs
diff --git a/advent02/Main.hs b/advent02/Main.hs
new file mode 100644 (file)
index 0000000..9cb89cc
--- /dev/null
@@ -0,0 +1,94 @@
+-- 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