module Day2.Main (main) where

import Data.List
import Data.Tuple
import Data.Maybe
import System.IO
import Control.Monad

main :: IO ()
main = do
    putStrLn "Day 2"
    
    handle <- openFile "app/Day2/input" ReadMode
    contents <- hGetContents handle

    let r1 = part1 contents
    putStrLn $ "part 1: " ++ show r1

    let r2 = part2 contents
    putStrLn $ "part 2: " ++ show r2

data Shape = Rock | Paper | Scissors
             deriving (Show, Eq)

instance Read Shape where
    readsPrec _ "A" = [(Rock,     "")]
    readsPrec _ "B" = [(Paper,    "")]
    readsPrec _ "C" = [(Scissors, "")]
    
    readsPrec _ "X" = [(Rock,     "")]
    readsPrec _ "Y" = [(Paper,    "")]
    readsPrec _ "Z" = [(Scissors, "")]

    readsPrec _ _   = []

instance Enum Shape where
    fromEnum Rock     = 1
    fromEnum Paper    = 2
    fromEnum Scissors = 3

    toEnum _ = error "nope"

data Result = Loss | Tie | Win
              deriving (Show, Eq)

instance Read Result where
    readsPrec _ "X" = [(Loss, "")]
    readsPrec _ "Y" = [(Tie,  "")]
    readsPrec _ "Z" = [(Win,  "")]
    readsPrec _ _   = []

instance Enum Result where
    fromEnum Loss = 0
    fromEnum Tie  = 3
    fromEnum Win  = 6

    toEnum _ = error "nope"

result :: Shape -> Shape -> Result
result a b | a == b   = Tie
result Rock Paper     = Loss
result Rock Scissors  = Win
result Paper Rock     = Win
result Paper Scissors = Loss
result Scissors Rock  = Loss
result Scissors Paper = Win

parseInput :: String -> (String -> a) -> (String -> b) -> [(a, b)]
parseInput contents lhs rhs = shapes
    where
        rounds = lines contents
        picks = map (\l -> ([l !! 0], [l !! 2])) rounds
        shapes = map (\(a,b) -> (lhs a, rhs b)) picks

part1 :: String -> Int
part1 contents = sum scoresResults + sum scoresPicks
    where
        rounds = parseInput contents (read :: String -> Shape) (read :: String -> Shape)
        scoresResults = map (fromEnum . (uncurry result) . swap) rounds
        scoresPicks = map (fromEnum . snd) rounds

part2 :: String -> Int
part2 contents = sum solutions + sum outcomes
    where
        rounds = parseInput contents (read :: String -> Shape) (read :: String -> Result)
        getResult o r = fromJust $ find (\p -> result p o == r) [Rock,Paper,Scissors]
        solutions = map (fromEnum . uncurry getResult) rounds
        outcomes = map (fromEnum . snd) rounds