🏡 index : ~doyle/aoc.git

author Jordan Doyle <jordan@doyle.la> 2023-12-21 15:39:10.0 +00:00:00
committer Jordan Doyle <jordan@doyle.la> 2023-12-21 15:39:10.0 +00:00:00
commit
d642bde642a33969417f57772c540a96180c72b0 [patch]
tree
010cb4a0990a73a5e94b9673c19cd7fb0f53f456
parent
c54a7357943099fa423c2445ed5d8b504ce2c6c1
download
d642bde642a33969417f57772c540a96180c72b0.tar.gz

Add day 15



Diff

 2023/15.hs | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 50 insertions(+)

diff --git a/2023/15.hs b/2023/15.hs
new file mode 100755
index 0000000..f1bf14c
--- /dev/null
+++ b/2023/15.hs
@@ -0,0 +1,50 @@
#!/usr/bin/env nix-shell
#!nix-shell --pure -i "runghc -- -i../" -p "haskellPackages.ghcWithPackages (pkgs: with pkgs; [ ordered-containers ])"

import Aoc (readAndParseStdin)
import Data.Char (ord)
import qualified Data.Map as Map
import qualified Data.Map.Ordered as OM
import Text.Parsec (char, choice, digit, many, many1, noneOf, parse, sepBy)
import Text.Parsec.String (Parser)

main = do
  input <- readAndParseStdin parseInput
  print $ part1 input
  print $ part2 input

part1 :: [String] -> Int
part1 input = sum $ map hash input

part2 :: [String] -> Int
part2 input = calcScore $ foldl folder (Map.fromList (zip [0 ..] $ replicate 256 OM.empty)) input
  where
    calcScore :: Map.Map Int (OM.OMap String Int) -> Int
    calcScore = Map.foldrWithKey (\i v acc -> acc + ((i + 1) * sum (zipWith (*) [1 ..] (map snd $ OM.assocs v)))) 0
    folder :: Map.Map Int (OM.OMap String Int) -> String -> Map.Map Int (OM.OMap String Int)
    folder acc input =
      let (label, add, focalLength) = parsePart2Input input
          hashedLabel = hash label
          updateBox = OM.alter (\_ -> if add then Just focalLength else Nothing) label
       in Map.adjust updateBox hashedLabel acc

hash :: String -> Int
hash = foldl (\acc c -> ((acc + ord c) * 17) `rem` 256) 0

parsePart2Input :: String -> (String, Bool, Int)
parsePart2Input input = case parse doParse "" input of
  Left parseError -> error $ show parseError
  Right doc -> doc
  where
    doParse = do
      label <- many1 (noneOf "-=")
      operation <-
        choice
          [ True <$ char '=',
            False <$ char '-'
          ]
      focalLength <- read <$> many digit
      return (label, operation, focalLength)

parseInput :: Parser [String]
parseInput = many1 (noneOf ",\n") `sepBy` char ','