#include<iostream>
#include <list>
#include<stack>
#include<queue>
#include <vector>
#include <set>
#include<algorithm>
#include<math.h>
#include<stdlib.h>
#include<string>
#include <functional>
#include<fstream>
#include<iomanip>

#define FOR(k,m,n) for(int (k)=(m);(k)<(n);(k)++)
#define REP(i,n) FOR((i),0,(n))
#define LL long long
#define CLR(a) memset((a),0,sizeof(a))
#define SZ(x) (int((x).size()))
#define WAITING(str) int str;std::cin>>str;
#define DEBUGING(str) cout<<str<<endl
using namespace std;

const LL MOD = 1000000007;// 10^9+7
const int INF = (1 << 30);








//計算
using pii = pair<int, int>;

template<typename T>
using v = vector<T>;

template<typename T>
using vv = vector<vector<T>>;


bool judge_go(const int& nowDist, const pii& next, const vv<bool>& can, const vv<int>& dist)
{
	int H = can.size();
	int W = can[0].size();

	// there
	if (next.first < 0 || H <= next.first)return false;
	if (next.second < 0 || W <= next.second)return false;

	//could
	if (!can[next.first][next.second])return false;

	//best
	int nextDist = dist[next.first][next.second];

	if (nowDist + 1 <  nextDist) return true;

	return false;
}


void step(
	const int& nowDist,
	const pii& next, 
	const vv<bool>& can,
	vv<int>& dist,
	queue<pii>& q) 
{
	if (judge_go(nowDist, next, can, dist)) {
		dist[next.first][next.second] = nowDist + 1;
		q.push(next);
	}
}


vv<int>min_dist(const vv<bool>& can, pii start)
{
	int H = can.size();
	int W = can[0].size();
	vv<int> dist = vv<int>(H, v<int>(W, INF));
	queue<pii> q;

	dist[start.first][start.second] = 0;
	q.push(start);

	while (!q.empty()) {
		pii now = q.front(); q.pop();
		pii next = now;
		int nowDist = dist[now.first][now.second];

		//up
		next.first--;
		step(nowDist, next, can, dist, q);
		next.first++;

		//down
		next.first++;
		step(nowDist, next, can, dist, q);
		next.first--;

		//left
		next.second--;
		step(nowDist, next, can, dist, q);
		next.second++;

		//right
		next.second++;
		step(nowDist, next, can, dist, q);
		next.second--;
	}
	return dist;
}

bool approach(const vv<int>& dist, const vector<pii>& dusts)
{
	for (auto dust : dusts) {
		if (dist[dust.first][dust.second] == INF) {
			return false;
		}
	}
	return true;
}

int measure_dist(
	const vv<int>& baseDist,
	const v<vv<int>>& dists,
	const v<pii>& dusts,
	const v<int>& routes)
{
	pii now = dusts[routes.front()];
	int res = baseDist[now.first][now.second];
	
	REP(i, (int)routes.size() - 1) {
		int now = routes[i];
		pii next = dusts[routes[i + 1]];
		res += dists[now][next.first][next.second];
	}
	return res;
}

void calc(const vv<bool>& can, const vector<pii>& dusts, pii start)
{
	//distance data
	auto baseDist = min_dist(can, start);//from robot
	v<vv<int>> dists;//from dust
	for (auto dust : dusts) {
		dists.push_back(min_dist(can, dust));
	}

	//exception
	if (!approach(baseDist, dusts)) {
		cout << -1 << endl;
		return;
	}

	//route data
	int ans = INF;
	v<int> route;
	REP(i, dusts.size())route.push_back(i);
	do {
		ans = min(ans, measure_dist(baseDist, dists, dusts, route));
	} while (next_permutation(route.begin(), route.end()));

	cout << ans << endl;
	/*
	for (auto row : baseDist) {
		for (int col : row) {
			if (col == INF)cerr << "  .";
			else cerr << setw(3) << col;
		}
		cerr << endl;
	}
	*/
}


//デバッグ
void debug()
{
	int N;
	cin>>N;
}


//メイン関数
int main()
{
	while (true) {
		int H, W;
		pii start;
		vv<bool> can;
		vector<pii> dusts;

		cin >> W >> H;
		if (H == 0)break;

		REP(i, H) {
			v<bool> v;
			string s;
			cin >> s;

			REP(j,W){
				char c = s[j];
				v.push_back(c != 'x');
				if (c == 'o') {
					start = { i,j };
				}
				if (c == '*') {
					dusts.push_back({ i,j });
				}
			}
			can.push_back(v);
		}
		calc(can, dusts, start);
	}
	//debug();
	return 0;
}



Measured memory_bytes: 3072