-moveElf :: Elf -> Elf
-moveElf elf = elf & current .~ (elf ^. proposed)
-
--- part 1 solution utilities
-
-findBounds :: S.Set Elf -> (Position, Position)
-findBounds grove = ((V2 minX minY), (V2 maxX maxY))
- where minX = fromJust $ minimumOf (folded . current . _x) grove
- minY = fromJust $ minimumOf (folded . current . _y) grove
- maxX = fromJust $ maximumOf (folded . current . _x) grove
- maxY = fromJust $ maximumOf (folded . current . _y) grove
-
-countEmpty :: S.Set Elf -> (Position, Position) -> Int
-countEmpty grove bounds = (rangeSize bounds) - (S.size grove)
+moveElves :: MPopulation s -> ST s ()
+moveElves elves =
+ do assocs <- M.getAssocs elves
+ mapM_ (moveElf elves) assocs
+
+moveElf :: MPopulation s -> (Position, Maybe Elf) -> ST s ()
+moveElf _elves (_here, Nothing) = return ()
+moveElf elves (here, Just (Elf there)) =
+ do M.writeArray elves here Nothing
+ M.writeArray elves there (Just (Elf there))
+
+-- reset the array bounds
+
+findBounds :: Population -> (Position, Position)
+findBounds grove = boundsR
+ where bounds0 = A.bounds grove
+ boundsT = shrink grove topStrip topShrink bounds0
+ boundsB = shrink grove bottomStrip bottomShrink boundsT
+ boundsL = shrink grove leftStrip leftShrink boundsB
+ boundsR = shrink grove rightStrip rightShrink boundsL
+
+shrink :: Population
+ -> ((Position, Position) -> (Position, Position))
+ -> (Position, Position)
+ -> (Position, Position)
+ -> (Position, Position)
+shrink grove findStrip stripDirection currentBounds
+ | emptyStrip grove (findStrip currentBounds) =
+ shrink grove findStrip stripDirection (shiftBounds currentBounds stripDirection)
+ | otherwise = currentBounds
+ where shiftBounds (b0, b1) (d0, d1) = (b0 ^+^ d0, b1 ^+^ d1)
+
+emptyStrip :: Population -> (Position, Position) -> Bool
+emptyStrip grove strip = all isNothing $ fmap (grove A.!) $ range strip
+
+topStrip, bottomStrip, leftStrip, rightStrip :: (Position, Position) -> (Position, Position)
+topStrip (V2 minX _minY, V2 maxX maxY) = (V2 minX maxY, V2 maxX maxY)
+bottomStrip (V2 minX minY, V2 maxX _maxY) = (V2 minX minY, V2 maxX minY)
+leftStrip (V2 minX minY, V2 _maxX maxY) = (V2 minX minY, V2 minX maxY)
+rightStrip (V2 _minX minY, V2 maxX maxY) = (V2 maxX minY, V2 maxX maxY)
+
+topShrink, bottomShrink, leftShrink, rightShrink :: (Position, Position)
+topShrink = (V2 0 0, V2 0 -1)
+bottomShrink = (V2 0 1, V2 0 0)
+leftShrink = (V2 1 0, V2 0 0)
+rightShrink = (V2 0 0, V2 -1 0)
+
+countEmpty :: Population -> (Position, Position) -> Int
+countEmpty grove bounds = length $ filter isNothing $ fmap (grove A.!) cells
+ where cells = range bounds