import Data.Char import Data.List.Split main :: IO () main = do input <- readFile "input" -- let size = (11,7) let size = (101,103) let ls = map parseLine $ lines input -- print $ part1 size ls part2 size ls parseLine line = toPair $ map readPair $ words $ filter valid line where valid c = isDigit c || isSpace c || c == ',' || c == '-' readPair s = toPair $ map readInt $ splitOn "," s readInt :: String -> Int readInt = read toPair [a,b] = (a,b) modp x y = let m = x `mod` y in if m < 0 then m+y else m moveN n (mx,my) ((x,y), (vx,vy)) = (((x+n*vx) `modp` mx, (y+n*vy) `modp` my), (vx,vy)) part1 size robots = calcScore size (map (moveN 100 size) robots) calcScore (sx, sy) robots = let (mx,my) = (sx `div` 2, sy `div` 2) positions = map fst robots q1 = filter (inBounds (0,0) (mx,my)) positions q2 = filter (inBounds (mx+1,0) (sx,my)) positions q3 = filter (inBounds (0,my+1) (mx,sy)) positions q4 = filter (inBounds (mx+1,my+1) (sx,sy)) positions in (length q1) * (length q2) * (length q3) * (length q4) inBounds (minx,miny) (maxx,maxy) (x,y) = minx <= x && x < maxx && miny <= y && y < maxy part2 :: (Int,Int) -> [((Int,Int), (Int,Int))] -> IO () part2 size robots = doPart2 1000000000000000 0 size robots doPart2 best gen size robots | gen > 10000 = return () | otherwise = do let score = calcScore size robots if score < best then do putStrLn $ "gen " ++ (show gen) printGrid size (map fst robots) putStrLn "" else do return () doPart2 (min score best) (gen+1) size (map (moveN 1 size) robots) printGrid :: (Int,Int) -> [(Int,Int)] -> IO () printGrid (sx,sy) coords = let g = [[if (x,y) `elem` coords then '#' else '.' | x <- [0..sx-1]] | y <- [0..sy-1]] in mapM_ putStrLn g