// template {{{
#include <bits/stdc++.h>
using namespace std;

// #define int long long

#define GET_MACRO(a, b, c, d, NAME, ...) NAME
#define REP2(i, n) REP3(i, 0, n)
#define REP3(i, a, b) REP4(i, a, b, 1)
#define REP4(i, a, b, s) for (ll i = (a); i < (ll)(b); i += s)
#define RREP2(i, n) RREP3(i, 0, n)
#define RREP3(i, a, b) for (ll i = (b) - 1; i >= (ll)(a); i--)

#define rep(...) GET_MACRO(__VA_ARGS__, REP4, REP3, REP2)(__VA_ARGS__)
#define rrep(...) GET_MACRO(__VA_ARGS__,, RREP3, RREP2)(__VA_ARGS__)
#define eb emplace_back
#define ef emplace_front
#define pb pop_back
#define pf pop_front
#define all(c) begin(c), end(c)
#define mp make_pair
#define mt make_tuple
#define fi first
#define se second
#define popcnt __builtin_popcountll

#ifdef DEBUG
	#define dump(x) cerr << #x " = " << x << endl;
#else
	#define dump(x)
#endif

using uint = unsigned;
using ll = long long;
using ull = unsigned long long;
using ld = long double;
using vi = vector<int>;
using vvi = vector<vi>;

template<typename T>
using maxheap = priority_queue<T, vector<T>, less<T>>;

template<typename T>
using minheap = priority_queue<T, vector<T>, greater<T>>;

const int INF = 1e9 + 10;
const ll LLINF = 1e18 + 10;

const int dx[] = {-1, 0, 1, 0, -1, 1, 1, -1};
const int dy[] = {0, -1, 0, 1, -1, -1, 1, 1};

template<typename T>
inline T sq(T x){
	return x * x;
}

template<typename T, typename U>
inline bool chmax(T &x, U y){
	if (x >= y) return false;
	x = y;
	return true;
}

template<typename T, typename U>
inline bool chmin(T &x, U y){
	if (x <= y) return false;
	x = y;
	return true;
}

template<typename T>
inline T& sort(T &c){
	sort(all(c));
	return c;
}

template<typename T>
inline T& reverse(T &c){
	reverse(all(c));
	return c;
}

template<typename T>
inline T& unique(T &c){
	sort(all(c));
	c.erase(unique(all(c)), end(c));
	return c;
}

template<typename T>
inline T sorted(const T &c){
	T d = c;
	return move(sort(d));
}

template<typename T>
inline T reversed(const T &c){
	T d = c;
	return move(reverse(d));
}

template<typename T>
inline T uniqued(const T &c){
	T d = c;
	return move(unique(d));
}

ll modpow(ll x, ll e, ll mod = 1000000007){
	ll res = 1;
	e %= mod - 1;
	while (e){
		if (e & 1) res = res * x;
		x = x * x;
		e >>= 1;
	}
	return res;
}

inline ll in(){
	ll x;
	scanf("%lld", &x);
	return x;
}

inline double inD(){
	double x;
	scanf("%lf", &x);
	return x;
}

inline string inS(){
	static char s[1 << 20];
	scanf("%s", s);
	return s;
}

pair<ll, ll> rot45(ll x, ll y){
	return mp(x + y, x - y);
}

pair<ll, ll> rot45inv(ll u, ll v){
	return mp((u + v) / 2, (u - v) / 2);
}

template<typename T, size_t N>
struct print_tuple {
	static void print(const T &t, ostream &os){
		print_tuple<T, N - 1>::print(t, os);
		os << " " << get<N - 1>(t);
	}
};

template<typename T>
struct print_tuple<T, 1> {
	static void print(const T &t, ostream &os){
		os << get<0>(t);
	}
};

template<typename ...Args>
ostream& operator<<(ostream &os, const tuple<Args...> &t){
	print_tuple<tuple<Args...>, tuple_size<tuple<Args...>>::value>::print(t, os);
}
// }}}
// graph {{{
#include <vector>

template<typename Weight>
class Edge {
public:
	using weight_t = Weight;
	
	int src, dst;
	weight_t weight;

	Edge(){}
	Edge(int dst): src(-1), dst(dst), weight(1){}
	Edge(int dst, weight_t weight): dst(dst), weight(weight){}
	Edge(int src, int dst, weight_t weight): src(src), dst(dst), weight(weight){}
};

template<typename Weight, bool Undirected = false>
class Graph {
public:
	using weight_t = Weight;
	using edge_t = Edge<Weight>;
	static const bool undirected = Undirected;

	Graph(): n(0){}
	Graph(int n): n(n), es(n){}

	int size() const {
		return n;
	}

	void addEdge(int src, int dst, weight_t weight = 1){
		es[src].emplace_back(src, dst, weight);
		if (undirected){
			es[dst].emplace_back(dst, src, weight);
		}
	}

	const std::vector<edge_t>& operator[](int v) const {
		return es[v];
	}

	typename std::vector<std::vector<edge_t>>::const_iterator begin() const {
		return std::begin(es);
	}

	typename std::vector<std::vector<edge_t>>::const_iterator end() const {
		return std::end(es);
	}

private:
	int n;
	std::vector<std::vector<edge_t>> es;
};
// }}}
// grid graph {{{
#include <vector>
#include <string>
#include <tuple>
#include <algorithm>
#include <cstring>
#include <utility>

template<typename Strings, typename Weight>
Graph<Weight, false> buildGridGraph(const Strings &s, const std::vector<std::tuple<char, char, Weight>> &es, int height, int width)
{
	Graph<Weight, false> g(height * width);
	auto to1d = [&](int i, int j){ return i * width + j; };
	
	static Weight w[256][256];
	bool f[256][256] = {};

	for (const auto &e : es){
		w[std::get<0>(e)][std::get<1>(e)] = std::get<2>(e);
		f[std::get<0>(e)][std::get<1>(e)] = true;
	}

	for (int i = 0; i < height; i++){
		for (int j = 0; j < width; j++){
			if (i + 1 < height){
				if (f[s[i][j]][s[i + 1][j]]){
					g.addEdge(to1d(i, j), to1d(i + 1, j), w[s[i][j]][s[i + 1][j]]);
				}
				if (f[s[i + 1][j]][s[i][j]]){
					g.addEdge(to1d(i + 1, j), to1d(i, j), w[s[i + 1][j]][s[i][j]]);
				}
			}
			if (j + 1 < width){
				if (f[s[i][j]][s[i][j + 1]]){
					g.addEdge(to1d(i, j), to1d(i, j + 1), w[s[i][j]][s[i][j + 1]]);
				}
				if (f[s[i][j + 1]][s[i][j]]){
					g.addEdge(to1d(i, j + 1), to1d(i, j), w[s[i][j + 1]][s[i][j]]);
				}
			}
		}
	}

	return std::move(g);
}

template<typename Weight>
Graph<Weight, false> buildGridGraph(const std::vector<std::string> &s, const std::vector<std::tuple<char, char, Weight>> &es)
{
	return buildGridGraph(s, es, s.size(), s[0].size());
}
// }}}
// union find {{{
#include <vector>

struct UnionFind {
	UnionFind(int n = 0): cnt(n), par(n, -1){}
	int root(int x){ return par[x] < 0 ? x : (par[x] = root(par[x])); }
	bool same(int x, int y){ return root(x) == root(y); }
	int count(){ return cnt; }
	int size(int x){ return -par[root(x)]; }
	bool unite(int x, int y){
		x = root(x);
		y = root(y);
		if (x == y) return false;
		if (par[x] > par[y]) swap(x, y);
		par[x] += par[y];
		par[y] = x;
		cnt--;
		return true;
	}
private:
	int cnt;
	std::vector<int> par;
};
// }}}

int main()
{
	const vector<tuple<char, char, int>> T = {
		mt('#', '#', 1),
		mt('*', '*', 1),
		mt('@', '@', 1)
	};

	int h, w;
	while (cin >> h >> w, h){
		vector<string> s(h);
		for (auto &r : s) cin >> r;
		auto g = buildGridGraph(s, T);
		UnionFind uf(g.size());
		for (auto &&es : g) for (auto &&e : es){
			uf.unite(e.src, e.dst);
		}
		cout << uf.count() << endl;
	}
}

Measured memory_bytes: 3924