I wrote something to find objects of one type for another SO question. The following example adds two more types. Any repeated iteration will review the entire list again. The idea is to process a list of points for each type separately. The solve function groups any connected points and removes them from the list before listing the next group. areConnected checks the relationship between the coordinates of points, since we only check points of the same type. In this generalized version, types ( abc ) can be any (strings, numbers, tuples, etc.) if they match.
btw - here is a link to javascript example j_random_hacker awesome algorithm: http://jsfiddle.net/groovy/fP5kP/
Haskell Code:
import Data.List (elemIndices, delete) example = ["xxyyyz" ,"xyyzzz" ,"yxxzzy" ,"yyxzxy" ,"xyzxyy" ,"xzxxzz" ,"xyzyyz" ,"xyzxyy"] objects abc ws = [("X",solve xs []),("Y",solve ys []),("Z",solve zs [])] where mapIndexes s = concatMap (\(y,xs)-> map (\x->(y,x)) xs) $ zip [0..] (map (elemIndices s) ws) [xs,ys,zs] = map mapIndexes [a,b,c] areConnected (y,x) (y',x') = abs (x-x') < 2 && abs (y-y') < 2 solve [] r = r solve (x:xs) r = let r' = solve' xs [x] in solve (foldr delete xs r') (if null (drop 2 r') then r else r':r) solve' vs r = let ys = filter (\y -> any (areConnected y) r) vs in if null ys then r else solve' (foldr delete vs ys) (ys ++ r)
Output Example:
*Main> objects 'x' 'y' 'z' example [("X",[[(7,0),(6,0),(5,0),(4,0)] ,[(3,4),(5,2),(5,3),(4,3),(2,2),(3,2),(2,1),(0,1),(1,0),(0,0)]]) ,("Y",[[(7,5),(6,4),(7,4),(6,3)],[(4,4),(4,5),(3,5),(2,5)] ,[(4,1),(3,0),(3,1),(0,4),(2,0),(0,3),(1,1),(1,2),(0,2)]]) ,("Z",[[(5,5),(6,5),(5,4)] ,[(7,2),(6,2),(5,1),(4,2),(3,3),(1,3),(2,3),(2,4),(1,4),(1,5),(0,5)]])] (0.02 secs, 1560072 bytes)