#include<bits/stdc++.h>

using namespace std;

struct cww{cww(){
    ios::sync_with_stdio(false);cin.tie(0);
    cout<<fixed<<setprecision(10);
}}init;

inline bool isWall(char c){return c=='#';}
inline bool isSpring(char c){return c=='*';}
inline bool isFloor(char c){return c=='.'||c=='s';}
inline bool isStart(char c){return c=='s';}
inline bool isGoal(char c){return c=='g';}
template<typename T>
istream& operator>>(istream& is,vector<T>& v){
    for(auto &it:v)is>>it;
    return is;
}
typedef long long LL;
using P=pair<int,int>;
typedef vector<LL> V;
typedef vector<V> VV;
const LL INF=1e12;
const int dir4[]={0,1,0,-1,0};
int main(){
    int R,C;
    cin>>C>>R;
    vector<string> maze(R);
    int sr,sc,gr,gc,M=0;
    cin>>maze;
    
    queue<P> que;
    VV dG(R,V(C,INF));
    VV dB(R,V(C,INF));
    for(int r=0;r<R;r++)
        for(int c=0;c<C;c++){
            if(isSpring(maze[r][c])){
                dB[r][c]=0;
                que.push(P(r,c));
            }
            if(isFloor(maze[r][c])){
                M++;
            }
            if(isStart(maze[r][c])){
                sr=r,sc=c;
            }
            if(isGoal(maze[r][c])){
                gr=r,gc=c;
            }
        }
    while(que.size()){
        int r,c;
        tie(r,c)=que.front();
        for(int i=0;i<4;i++){
            int nr=r+dir4[i];
            int nc=c+dir4[i+1];
            if(isWall(maze[nr][nc]))continue;
            if(dB[nr][nc]>dB[r][c]+1){
                dB[nr][nc]=dB[r][c]+1;
                que.push(P(nr,nc));
            }
        }
        que.pop();
    }
    que.push(P(gr,gc));
    dG[gr][gc]=0;
    while(que.size()){
        int r,c;
        tie(r,c)=que.front();
        for(int i=0;i<4;i++){
            int nr=r+dir4[i];
            int nc=c+dir4[i+1];
            if(isWall(maze[nr][nc])||isSpring(maze[nr][nc]))continue;
            if(dG[nr][nc]>dG[r][c]+1){
                dG[nr][nc]=dG[r][c]+1;
                que.push(P(nr,nc));
            }
        }
        que.pop();
    }
    vector<P> fs;
    auto b=[&](P p){return max(0ll,min(INF,dG[p.first][p.second]-dB[p.first][p.second]));};
    for(int r=0;r<R;r++)
        for(int c=0;c<C;c++)
            if(isFloor(maze[r][c])){
                fs.push_back(P(r,c));
            }
    sort(fs.begin(),fs.end(),[&](P p,P q){return b(p)<b(q);});
    LL K=0;
    int B=M;
    for(int i=0,sz=fs.size();i<sz;i++){
        K+=dB[fs[i].first][fs[i].second];
    }
    double res=INF;
    K-=dB[fs[0].first][fs[0].second];
    K+=dG[fs[0].first][fs[0].second];
    B--;
    LL prev=b(fs[0]);
    for(int i=1,sz=fs.size();i<sz;i++){
        LL now=b(fs[i]);
        if(now!=prev){
            double b=1.0-B/(double)M;
            b=(K/(double)M)/b;
            if(prev<=b&&b<=now){
                res=min(res,b);
            }
        }
        K-=dB[fs[i].first][fs[i].second];
        K+=dG[fs[i].first][fs[i].second];
        B--;
        prev=now;
    }
    if(prev<INF){
        double b=1.0-B/(double)M;
        b=(K/(double)M)/b;
        if(prev<=b&&b<=INF){
            res=min(res,b);
        }
    }
    cout<<min((double)dG[sr][sc],dB[sr][sc]+res)<<endl;
    return 0;
}