#include <cstdio>
#include <vector>
#include <queue>

const int N = 2000 + 5;

const int d[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};

#define toint(ch) ((int)((ch) - 'a' + 1))

char a[N][N];
int n, m;
int stx, sty, edx, edy;

struct Point { int x, y; };
std::vector<Point> tos[30];
std::queue<Point> q;

int dis[N][N];

bool visch[30];

int main() {
	std::scanf("%d%d", &n, &m);
	for(int i = 1; i <= n; i++) {
		std::scanf("%s", a[i] + 1);
		for(int j = 1; j <= m; j++) {
			if('a' <= a[i][j] && a[i][j] <= 'z')
				tos[toint(a[i][j])].push_back({i, j});
			else if(a[i][j] == 'S') stx = i, sty = j;
			else if(a[i][j] == 'G') edx = i, edy = j;
		}
	}
	q.push({stx, sty});
	dis[stx][sty] = 1; // dis[][] is also vis[][]
	while(!q.empty()) {
		int px = q.front().x, py = q.front().y;
		char pc = a[px][py];
		q.pop();
		if('a' <= pc && pc <= 'z' && !visch[toint(pc)]) {
			for(const Point &d : tos[toint(pc)]) {
				int dx = d.x, dy = d.y;
				if(!(1 <= dx && dx <= n && 1 <= dy && dy <= m && a[dx][dy] != '#' && !dis[dx][dy])) continue;
				dis[dx][dy] = dis[px][py] + 1;
				q.push({dx, dy});
			}
			visch[toint(pc)] = true;
		}
		for(int i = 0; i < 4; i++) {
			int dx = px + d[i][0], dy = py + d[i][1];
			if(!(1 <= dx && dx <= n && 1 <= dy && dy <= m && a[dx][dy] != '#' && !dis[dx][dy])) continue;
			dis[dx][dy] = dis[px][py] + 1;
			q.push({dx, dy});
		}
	}
	// for(int i = 1; i <= n; i++)
	// 	for(int j = 1; j <= m; j++)
	// 		std::printf("%2d%c", dis[i][j] - 1, j == m ? '\n' : ' ');
	std::printf("%d\n", (dis[edx][edy] == 0 ? -1 : dis[edx][edy] - 1));
	return 0;
}
#include<iostream>
#include<vector>
#include<deque>
using namespace std;

template<typename T>class Graph{
    public:
    struct edge{int to;T cost;};
    int Vertex_num,Edge_num;
    vector<edge>*g;

    const T INF=1000000000;

    Graph(int V){//0～V-1
        Vertex_num=V;
        g=new vector<edge>[V];
    }

    Graph(int V,int E){//0～V-1
        Vertex_num=V;
        Edge_num=E;
        g=new vector<edge>[V];
    }

    void emplace_back(int from,int to,T cost){
        edge e={to,cost};
        g[from].push_back(e);
        //edges->push_back(e);//for Bellman-Ford
    }

    void input(bool direct,bool weight){
        int from,to;
        T cost;
        for(int i=0;i<Edge_num;i++){
            cin>>from>>to;
            from--,to--;
            if(weight)cin>>cost;
            else cost=1;
            this->emplace_back(from,to,cost);
            if(!direct)this->emplace_back(to,from,cost);
        }
    }

    void check(){
        for(int i=0;i<Vertex_num;i++){
            cout<<"Vertex "<<i<<endl;
            for(auto x:g[i])cout<<x.to<<" "<<x.cost<<endl;
        }
    }
};

template<typename T>vector<T>bfs(Graph<T>graph,int start){
    vector<T>dist(graph.Vertex_num,-1);//訪問:startからの距離 未訪問:-1
    deque<int>q;
    q.push_front(start);
    dist[start]=0;
    while(!q.empty()){
        int p=q.front();q.pop_front();
        for(auto x:graph.g[p])if(dist[x.to]==-1){
            dist[x.to]=dist[p]+x.cost;
            if(x.cost)q.push_back(x.to);
            else q.push_front(x.to);
        }
        //visited[]の更新はpushするときにやらないとqueueがあふれる↑
    }
    return dist;
}

int H,W,S,G;
int main(){
    cin>>H>>W;
    char a[H][W];
    for(int i=0;i<H*W;i++)cin>>a[i/W][i%W];

    int d4[5]={1,0,-1,0,1};
    Graph<int>g(H*W+26);
    for(int i=0;i<H;i++){
        for(int j=0;j<W;j++){
            if(a[i][j]=='#')continue;
            if(a[i][j]=='S')S=i*W+j;
            if(a[i][j]=='G')G=i*W+j;
            if('a'<=a[i][j]&&a[i][j]<='z'){
                g.emplace_back(i*W+j,H*W+a[i][j]-'a',1);
                g.emplace_back(H*W+a[i][j]-'a',i*W+j,0);
                g.Edge_num+=2;
            }
            for(int k=0;k<4;k++){
                int x=i+d4[k],y=j+d4[k+1];
                if (x<0||x>=H||y<0||y>=W||a[x][y]=='#')continue;
                g.emplace_back(i*W+j,x*W+y,1);
                g.Edge_num++;
            }
        }
    }
    auto d=bfs(g,S);
    cout<<d[G]<<endl;
    return 0;
}