#include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define NUM 500

struct LOC{
	void set(int arg_row,int arg_col){
		row = arg_row;
		col = arg_col;
	}
	int row,col;
};

struct Info{
	LOC loc;
	int to_goal,to_spring;
	bool is_floor;
};

struct State{
	State(int arg_row,int arg_col,int arg_sum_dist){
		row = arg_row;
		col = arg_col;
		sum_dist = arg_sum_dist;
	}
	bool operator<(const struct State &arg) const{
		return sum_dist > arg.sum_dist;
	}
	int row,col,sum_dist;
};

char base_map[NUM][NUM+1];
int W,H;
int floor_num;
int diff_row[4] = {-1,0,0,1},diff_col[4] = {0,-1,1,0};
int goal_table[NUM][NUM],spring_table[NUM][NUM];
LOC start,goal;
Info info[NUM][NUM];



bool rangeCheck(int row,int col){
	if(row >= 0 && row <= H-1 && col >= 0 && col <= W-1)return true;
	else{
		return false;
	}
}


int main(){

	scanf("%d %d",&W,&H);

	for(int row = 0; row < H; row++){
		for(int col = 0; col < W; col++){
			info[row][col].loc.set(row,col);
			info[row][col].is_floor = false;
		}
	}

	floor_num = 0;

	for(int row = 0; row < H; row++){
		scanf("%s",base_map[row]);
		for(int col = 0; col < W; col++){
			switch(base_map[row][col]){
			case '.':
				info[row][col].is_floor = true;
				floor_num++;
				break;
			case 's':
				info[row][col].is_floor = true;
				start.set(row,col);
				floor_num++;
				base_map[row][col] = '.';
				break;
			case 'g':
				goal.set(row,col);
				break;
			case '#':
				//Do nothing
				break;
			case '*':
				//Do nothing
				break;
			}
		}
	}

	for(int row = 0; row < H; row++){
		for(int col = 0; col < W; col++)goal_table[row][col] = BIG_NUM;
	}

	priority_queue<State> Q;
	goal_table[goal.row][goal.col] = 0;

	Q.push(State(goal.row,goal.col,0));

	int adj_row,adj_col,next_dist;

	while(!Q.empty()){

		for(int i = 0; i < 4; i++){
			adj_row = Q.top().row+diff_row[i];
			adj_col = Q.top().col+diff_col[i];

			if(rangeCheck(adj_row,adj_col) == false || base_map[adj_row][adj_col] != '.')continue;

			next_dist = Q.top().sum_dist+1;
			if(goal_table[adj_row][adj_col] > next_dist){
				goal_table[adj_row][adj_col] = next_dist;
				Q.push(State(adj_row,adj_col,next_dist));
			}
		}
		Q.pop();
	}

	for(int row = 0; row < H; row++){
		for(int col = 0; col < W; col++)spring_table[row][col] = BIG_NUM;
	}

	for(int row = 0; row < H; row++){
		for(int col = 0; col < W; col++){
			if(base_map[row][col] != '*')continue;

			spring_table[row][col] = 0;
			Q.push(State(row,col,0));

			while(!Q.empty()){

				for(int i = 0; i < 4; i++){
					adj_row = Q.top().row+diff_row[i];
					adj_col = Q.top().col+diff_col[i];

					if(rangeCheck(adj_row,adj_col) == false || base_map[adj_row][adj_col] != '.')continue;

					next_dist = Q.top().sum_dist+1;
					if(spring_table[adj_row][adj_col] > next_dist){
						spring_table[adj_row][adj_col] = next_dist;
						Q.push(State(adj_row,adj_col,next_dist));
					}
				}
				Q.pop();
			}
		}
	}

	int maximum = 0;
	map<pair<int,int>,int> MAP;

	for(int row = 0;row < H;row++){
		for(int col = 0; col < W; col++){
			if(info[row][col].is_floor){
				info[row][col].to_goal = goal_table[row][col];
				if(info[row][col].to_goal != BIG_NUM){
					maximum = max(maximum,info[row][col].to_goal);
				}
				info[row][col].to_spring = spring_table[row][col];
				MAP[make_pair(goal_table[row][col],spring_table[row][col])]++;
			}
		}
	}

	long double E = INFINITY;
    for(int value = 0; value <= maximum; value++){

    	long double a = 0;
    	long double b = 0;

    	for(auto it: MAP){

    		int to_goal,to_spring;
    		to_goal = it.first.first;
    		to_spring = it.first.second;

    		int count = it.second;

    		long double possib = count/(long double)floor_num;

    		if(to_goal == BIG_NUM){
    			a += possib;
    			b += possib*to_spring;
    		}else if(to_spring == BIG_NUM){
    			b += possib*to_goal;
    		}else{
    			if(to_goal <= to_spring+value){
    				b += possib*to_goal;
    			}else{
    				a += possib;
    				b += possib*to_spring;
    			}
    		}
    	}
    	E = min(E,b/(1-a));
    }

    long double ans;
    if(info[start.row][start.col].to_goal == BIG_NUM){
    	ans = info[start.row][start.col].to_spring+E;
    }else if(info[start.row][start.col].to_spring == BIG_NUM){
    	ans = info[start.row][start.col].to_goal;
    }else{
    	ans = min<long double>(info[start.row][start.col].to_goal,info[start.row][start.col].to_spring+E);
    }

    printf("%.10Lf\n",ans);

	return 0;
}



Measured memory_bytes: 18056