Day 13: Claw Contraption

Megathread guidelines

  • Keep top level comments as only solutions, if you want to say something other than a solution put it in a new post. (replies to comments can be whatever)
  • You can send code in code blocks by using three backticks, the code, and then three backticks or use something such as https://topaz.github.io/paste/ if you prefer sending it through a URL

FAQ

  • lwhjp@lemmy.sdf.org
    link
    fedilink
    arrow-up
    4
    ·
    9 days ago

    Haskell

    Whee, linear algebra! Converting between numeric types is a bit annoying in Haskell, but I’m reasonably happy with this solution.

    import Control.Monad
    import Data.Matrix qualified as M
    import Data.Maybe
    import Data.Ratio
    import Data.Vector qualified as V
    import Text.Parsec
    
    type C = (Int, Int)
    
    readInput :: String -> [(C, C, C)]
    readInput = either (error . show) id . parse (machine `sepBy` newline) ""
      where
        machine = (,,) <$> coords <*> coords <*> coords
        coords =
          (,)
            <$> (manyTill anyChar (string ": X") >> anyChar >> num)
            <*> (string ", Y" >> anyChar >> num)
            <* newline
        num = read <$> many1 digit
    
    presses :: (C, C, C) -> Maybe C
    presses ((ax, ay), (bx, by), (px, py)) =
      do
        let m = fromIntegral <$> M.fromLists [[ax, bx], [ay, by]]
        m' <- either (const Nothing) Just $ M.inverse m
        let [a, b] = M.toList $ m' * M.colVector (fromIntegral <$> V.fromList [px, py])
        guard $ denominator a == 1
        guard $ denominator b == 1
        return (numerator a, numerator b)
    
    main = do
      input <- readInput <$> readFile "input13"
      mapM_
        (print . sum . map (\(a, b) -> 3 * a + b) . mapMaybe presses)
        [ input,
          map (\(a, b, (px, py)) -> (a, b, (10000000000000 + px, 10000000000000 + py))) input
        ]