🏡 index : ~doyle/aoc.git

#!/usr/bin/env nix-shell
#!nix-shell --pure -i "runghc -- -i../" -p "haskellPackages.ghcWithPackages (pkgs: with pkgs; [ ])"

import Aoc (readAndParseStdin, shoelace)
import Text.Parsec (char, choice, count, digit, hexDigit, many1, sepBy, spaces, string)
import Text.Parsec.String (Parser)

main = do
  input <- readAndParseStdin parse
  print $ (score . map fst) input
  print $ (score . map snd) input

score :: [(Direction, Int)] -> Int
score input = round $ shoelace (calculateVertices input) + fromIntegral (perimiter input `div` 2) + 1

perimiter :: [(Direction, Int)] -> Int
perimiter = sum . map snd

calculateVertices :: [(Direction, Int)] -> [(Int, Int)]
calculateVertices input = go input 0 0
  where
    go [] hAcc vAcc = []
    go ((d, c) : xs) hAcc vAcc =
      let (newHAcc, newVAcc) = calcAcc d c hAcc vAcc
       in (newHAcc, newVAcc) : go xs newHAcc newVAcc

calcAcc :: Direction -> Int -> Int -> Int -> (Int, Int)
calcAcc U c hAcc vAcc = (hAcc, vAcc - c)
calcAcc D c hAcc vAcc = (hAcc, vAcc + c)
calcAcc L c hAcc vAcc = (hAcc - c, vAcc)
calcAcc R c hAcc vAcc = (hAcc + c, vAcc)

parse :: Parser [((Direction, Int), (Direction, Int))]
parse = parseLine `sepBy` char '\n'

parseLine :: Parser ((Direction, Int), (Direction, Int))
parseLine = do
  p1d <- parseDirection <* spaces
  p1c <- read <$> many1 digit <* spaces
  p2c <- string "(#" *> count 5 hexDigit
  p2d <- parseNumericDirection <* char ')'
  return ((p1d, p1c), (p2d, read ("0x" ++ p2c)))

parseDirection :: Parser Direction
parseDirection =
  choice
    [ U <$ char 'U',
      D <$ char 'D',
      L <$ char 'L',
      R <$ char 'R'
    ]

parseNumericDirection :: Parser Direction
parseNumericDirection =
  choice
    [ U <$ char '3',
      D <$ char '1',
      L <$ char '2',
      R <$ char '0'
    ]

data Direction = U | D | L | R deriving (Show, Enum)