- let grid = transpose $ fmap (fmap readElem) $ lines text
- -- print grid
- -- print $ rollGrid $ transpose grid
- -- let r1 = rollToCompletion grid
- -- print r1
- -- putStrLn $ showGrid r1
- -- print $ transpose $ fmap reverse r1
- print $ part1 grid
- -- print $ rollCycle grid
- -- putStrLn $ showGrid $ rollCycle grid
- -- putStrLn $ showGrid $ rollCycle $ rollCycle grid
- -- putStrLn $ showGrid $ rollCycle $ rollCycle $ rollCycle grid
- -- print $ findRepeat grid
-
-
-
- print $ part2 grid
- -- print $ part2 patts
-
-part1 :: Grid -> Int
-part1 grid = scoreGrid grid'
- where grid' = rollToCompletion grid
-
-part2 grid = scoreGrid finalGrid
- where (grid', cache, i) = findRepeat grid
- repeatStart = cache M.! grid'
- repeatLen = i - repeatStart
- finalIndex = (1e9 - repeatStart - 1) `mod` repeatLen
- (finalGrid, _) = M.findMin $ M.filter (== finalIndex) cache
+ let (rGrid, cGrid) = readGrids text
+ -- putStrLn $ showGrid rGrid cGrid
+ -- let rGrid' = rollNorth rGrid cGrid
+ -- putStrLn $ showGrid rGrid' cGrid
+ print $ part1 rGrid cGrid
+ -- let rGrid1 = rollCycle rGrid cGrid
+ -- putStrLn $ showGrid rGrid1 cGrid
+ -- let rGrid2 = rollCycle rGrid1 cGrid
+ -- putStrLn $ showGrid rGrid2 cGrid
+ -- let rGrid3 = rollCycle rGrid2 cGrid
+ -- putStrLn $ showGrid rGrid3 cGrid
+ print $ part2 rGrid cGrid
+
+
+part1 :: Grid -> Grid -> Int
+part1 rGrid cGrid = getLoad $ rollNorth rGrid cGrid
+
+part2 rGrid cGrid = getLoad finalGrid
+ where (grid', cache, repeatEnd) = findRepeat rGrid cGrid
+ repeatStart = cache Map.! grid'
+ repeatLen = repeatEnd - repeatStart
+ finalIndex = ((1e9 - repeatStart) `mod` repeatLen) + repeatStart
+ (finalGrid, _) = Map.findMin $ Map.filter (== finalIndex) cache
+
+
+findRepeat :: Grid -> Grid -> (Grid, Cache, Int)
+findRepeat rGrid cGrid = head $ dropWhile test $ iterate go (rGrid, Map.empty, 0)
+ where test (g, c, _) = g `Map.notMember` c
+ go (g, c, i) = (rollCycle g cGrid, Map.insert g i c, (i + 1))
+
+rollNorth, rollCycle :: Grid -> Grid -> Grid
+rollNorth rGrid cGrid = roll (V2 0 0) (V2 0 1) (V2 1 0) cGrid rGrid
+
+rollCycle rGrid cGrid = foldl' go rGrid [ (V2 0 0, V2 0 1, V2 1 0)
+ , (V2 0 0, V2 1 0, V2 0 1)
+ , (V2 r 0, V2 0 1, V2 -1 0)
+ , (V2 0 c, V2 1 0, V2 0 -1)
+ ]
+ where (_, V2 r c) = U.bounds rGrid
+ go g (start, majorStep, minorStep) =
+ roll start majorStep minorStep cGrid g
+
+roll :: Position -> Position -> Position -> Grid -> Grid -> Grid
+roll start majorStep minorStep cGrid rGrid =
+ M.runSTUArray $
+ do grid <- M.thaw rGrid
+ holes <- newSTRef Q.Empty
+ forM_ (takeWhile (inBounds rGrid) $ iterate (^+^ majorStep) start) $ \maj ->
+ do writeSTRef holes Q.Empty
+ forM_ (takeWhile (inBounds rGrid) $ iterate (^+^ minorStep) maj) $ \here ->
+ do rollPosition grid cGrid holes here
+ return grid
+
+rollPosition :: (MGrid s) -> Grid -> (Gaps s) -> Position -> ST s ()
+rollPosition grid cGrid holes here
+ | cGrid U.! here = writeSTRef holes Q.Empty
+ | otherwise = do roundHere <- M.readArray grid here
+ holesVal <- readSTRef holes
+ if roundHere then
+ case holesVal of
+ Q.Empty -> return ()
+ (h :<| hs) -> do M.writeArray grid h True
+ M.writeArray grid here False
+ writeSTRef holes (hs :|> here)
+ else modifySTRef holes (:|> here)
+
+inBounds :: Grid -> Position -> Bool
+inBounds g h = inRange (U.bounds g) h
+
+getLoad :: Grid -> Int
+getLoad grid = sum columnLoads
+ where (_, V2 rMax cMax) = U.bounds grid
+ columnLoads = [getColLoad c | c <- [0..cMax]]
+ getColLoad c = sum [(rMax - r + 1) | r <- [0..rMax], grid U.! (V2 r c)]
+
+readGrids :: String -> (Grid, Grid)
+readGrids text = (rGrid, cGrid)
+ where rows = lines text
+ r = length rows - 1
+ c = (length $ head rows) - 1
+ rGrid = U.listArray ((V2 0 0), (V2 r c)) $ map ((== Round) . readElem) $ concat rows
+ cGrid = U.listArray ((V2 0 0), (V2 r c)) $ map ((== Cube ) . readElem) $ concat rows