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
- What is this?: Here is a post with a large amount of details: https://programming.dev/post/6637268
- Where do I participate?: https://adventofcode.com/
- Is there a leaderboard for the community?: We have a programming.dev leaderboard with the info on how to join in this post: https://programming.dev/post/6631465
Haskell
Part 2 could be improved significantly now that I know what to look for, but this is the (very inefficient) heuristic I eventually found the answer with.
Solution
import Control.Arrow import Data.Char import Data.List import Data.Map qualified as Map import Data.Maybe import Text.Parsec (w, h) = (101, 103) readInput :: String -> [((Int, Int), (Int, Int))] readInput = either (error . show) id . parse (robot `endBy` newline) "" where robot = (,) <$> (string "p=" >> coords) <*> (string " v=" >> coords) coords = (,) <$> num <* char ',' <*> num num = read <$> ((++) <$> option "" (string "-") <*> many1 digit) runBots :: [((Int, Int), (Int, Int))] -> [[(Int, Int)]] runBots = transpose . map botPath where botPath (p, (vx, vy)) = iterate (incWrap w vx *** incWrap h vy) p incWrap s d = (`mod` s) . (+ d) safetyFactor :: [(Int, Int)] -> Int safetyFactor = product . Map.fromListWith (+) . map (,1) . mapMaybe quadrant where cx = w `div` 2 cy = h `div` 2 quadrant (x, y) | x == cx || y == cy = Nothing | otherwise = Just (x `div` (cx + 1), y `div` (cy + 1)) render :: [(Int, Int)] -> [String] render bots = let counts = Map.fromListWith (+) $ map (,1) bots in flip map [0 .. h - 1] $ \y -> flip map [0 .. w - 1] $ \x -> maybe '.' intToDigit $ counts Map.!? (x, y) isImage :: [String] -> Bool isImage = (> 4) . length . filter hasRun where hasRun = any ((> 3) . length) . filter head . group . map (/= '.') main = do positions <- runBots . readInput <$> readFile "input14" print . safetyFactor $ positions !! 100 let (Just (t, image)) = find (isImage . snd) $ zip [0 ..] $ map render positions print t mapM_ putStrLn image