import Control.Applicative
import Control.Monad
import Control.Monad.RWS as RWS
import Data.Array.IArray
import Data.Array.Unboxed
import Data.Array.IO

type Garden = UArray Position Char
type CheckField = IOUArray Position Bool
type Position = (Int, Int)

main = do
    [h,w] <- map read.words<$>getLine
    unless (h == 0) $ do
        garden <- getGarden h w
        checkfield <- newArray ((0,0),(h-1,w-1)) False
        print =<< fst <$> evalRWST (sepGarden (0,0) 0) garden checkfield
        main
        

getGarden :: Int -> Int -> IO Garden
getGarden h w = do
    fs <- replicateM h getLine
    return $ listArray ((0,0), (h-1,w-1)) $ concat fs

sepGarden :: Position -> Int -> RWST Garden String CheckField IO Int
sepGarden (x,y) i = do
    ((ax,ay),(bx,by)) <- bounds<$>RWS.ask
    case (x <= bx, y <= by) of
      (False, False) -> return i
      (True, False)  -> sepGarden (x+1, 0) i
      (False, True)  -> return i
      (True , True)  -> checkField (x,y) i >>= sepGarden (x, y+1)

checkField :: Position -> Int -> RWST Garden String CheckField IO Int
checkField (x,y) i = do
    checked <- isChecked (x,y)
    if checked then return i
               else do
                   checkAround (x,y)
                   return (i+1)

isChecked :: Position -> RWST Garden String CheckField IO Bool
isChecked (x,y) = do
    cf <- get
    liftIO $ readArray cf (x,y)

checkAround (x,y) = do
    cf <- get
    fruit  <- (! (x,y))<$>RWS.ask
    liftIO $ writeArray cf (x,y) True
    checkRight (x,y) fruit
    checkUnder (x,y) fruit

checkRight, checkUnder, checkLeft :: Position -> Char -> RWST Garden String CheckField IO ()
checkRight (x,y) f = do
    g <- RWS.ask
    let ((ax,ay),(bx, by)) = bounds g
    if bx >= x && by >= y+1
       then if g ! (x,y+1) == f
               then do
                   checked <- isChecked (x, y+1)
                   if not checked
                      then do
                          cf <- get
                          liftIO $ writeArray cf (x,y+1) True
                          checkRight (x,y+1) f
                          checkUnder (x,y+1) f
                      else return ()
               else return ()
       else return ()

checkUnder(x,y) f = do
    g <- RWS.ask
    let ((ax,ay),(bx, by)) = bounds g
    if bx >= x+1 && by >= y
       then if g ! (x+1,y) == f
               then do
                   checked <- isChecked (x+1,y)
                   if not checked
                      then do
                          cf <- get
                          liftIO $ writeArray cf (x+1,y) True
                          checkRight (x+1,y) f
                          checkUnder (x+1,y) f
                          checkLeft  (x+1,y) f
                      else return ()
               else return ()
       else return ()

checkLeft (x,y) f = do
    g <- RWS.ask
    let ((ax,ay),(bx, by)) = bounds g
    if ay <= y-1
       then if g ! (x,y-1) == f
               then do
                   cf <- get
                   liftIO $ writeArray cf (x,y-1) True
                   checkUnder (x,y-1) f
                   checkLeft  (x,y-1) f
               else return ()
       else return ()