• # Solution en Haskell

    Posté par . En réponse au message Advent of Code, jour 15. Évalué à 2.

    Problème très simple aujourd'hui. Aucune subtilité algorithmique ou autre astuce à avoir.
    Juste un petit détail, j'ai pensé à utiliser, pour représenter les boites, des hashmaps avec pour clé des strings (les labels) et pour valeur des ints (les longueurs focales).
    Petit problème, les HashMap de la librairie containers ne préservent pas l'ordre d'insertion, cet ordre étant nécessaire pour calculer le "focusingPower".
    J'ai donc utilisé des HashMaps d'une librairie tierce qui, elles, préservent l'ordre d'insertion.
    250 microseconds pour la partie 1 et 600 microseconds pour la partie 2.
    Je pense que ce serait plus performant si j'utilisais des structures de données mutables mais ce serait moins joli.

    data Operation = Remove | Insert !Int
    data Step = Step !String !Operation
    type Box = HMap.InsOrdHashMap String Int
    type Boxes = IntMap Box
    stepToString :: Step -> String
    stepToString (Step str Remove) = str ++ "-"
    stepToString (Step str (Insert n)) = str ++ "=" ++ show n
    parser :: Parser [Step]
    parser = step `sepEndBy1` "," where
     step = Step <$> some lowerChar <*> operation
     operation = Remove <$ "-" <|> Insert <$> ("=" *> decimal)
    hash :: String -> Int
    hash = foldl' go 0 where
     go acc ch = (acc + ord ch) * 17 `mod` 256
    part1 :: [Step] -> Int
    part1 = sum . map (hash . stepToString)
    hashmapStep :: Boxes -> Step -> Boxes
    hashmapStep boxes (Step label instr) = case instr of
     Remove -> IntMap.adjust (HMap.delete label) k boxes 
     Insert len -> IntMap.adjust (HMap.insert label len) k boxes
     where k = hash label
    focusingPower :: Boxes -> Int
    focusingPower boxes = sum [ (i+1) * j * len 
     | (i, box) <- IntMap.toList boxes
     , (j, (_, len)) <- zip [1..] (HMap.toList box)
     ]
    part2 :: [Step] -> Int
    part2 = focusingPower . foldl' hashmapStep initialBoxes where
     initialBoxes = IntMap.fromList (zip [0..] (replicate 256 HMap.empty))
    solve :: Text -> IO ()
    solve = aoc parser part1 part2