Day 14: Restroom Redoubt

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

  • LeixB@lemmy.world
    link
    fedilink
    arrow-up
    1
    ·
    8 days ago

    Haskell

    Spent a lot of time trying to find symmetric quadrants. In the end made an interactive visualization and found that a weird pattern appeared on iterations (27 + 101k) and (75 + 103k’). Put those congruences in an online Chinese remainder theorem calculator and go to the answer: x ≡ 8006 (mod 101*103)

    import Data.Bifunctor
    import Data.Char
    import qualified Data.Set as S
    import Data.Functor
    import Data.List
    import Control.Monad
    import Text.ParserCombinators.ReadP
    import Data.IORef
    
    bounds = (101, 103)
    
    parseInt :: ReadP Int
    parseInt = (*) <$> option 1 (char '-' $> (-1)) <*> (read <$> munch1 isDigit)
    parseTuple = (,) <$> parseInt <*> (char ',' *> parseInt)
    parseRow = (,) <$> (string "p=" *> parseTuple) <*> (string " v=" *> parseTuple)
    parse = fst . last . readP_to_S (endBy parseRow (char '\n'))
    
    move t (x, y) (vx, vy) = bimap (mod (x + vx * t)) (mod (y + vy * t)) bounds
    
    getQuadrant :: (Int, Int) -> Int
    getQuadrant (x, y)
        | x == mx || y == my = 0
        | otherwise = case (x > mx, y > my) of
            (True, True) -> 1
            (True, False) -> 2
            (False, True) -> 3
            (False, False) -> 4
      where
        (mx, my) = bimap (`div` 2) (`div` 2) bounds
    
    step (x, y) (vx, vy) = (,(vx, vy)) $ bimap (mod (x + vx)) (mod (y + vy)) bounds
    
    main = do
        p <- parse <$> readFile "input14"
    
        print . product . fmap length . group . sort . filter (/=0) . fmap (getQuadrant . uncurry (move 100)) $ p
    
        let l = iterate (fmap (uncurry step)) p
    
        current <- newIORef 0
        actions <- lines <$> getContents
        forM_ actions $ \a -> do
            case a of
                "" -> modifyIORef current (+1)
                "+" -> modifyIORef current (+1)
                "-" -> modifyIORef current (subtract 1)
                n -> writeIORef current (read n)
            pos <- readIORef current
            putStr "\ESC[2J" -- clear screen
            print pos
            visualize $ fst <$> l !! pos
    
    visualize :: [(Int, Int)] -> IO ()
    visualize pos = do
        let p = S.fromList pos
        forM_ [1..(snd bounds)] $ \y -> do
            forM_ [1..(fst bounds)] $ \x -> do
                putChar $ if S.member (x, y) p then '*' else '.'
            putChar '\n'