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

typedef long long ll;
typedef vector<ll> vll;
typedef vector<int> vi;
typedef pair<int, int> pii;
typedef vector<pii> vpii;
#define pb push_back
#define ff first
#define ss second
#define MOD 1000000007
#define endl '\n'

void fast_io()
{
	ios_base::sync_with_stdio(0);
	cin.tie(0);
}
ll gcd(ll a , ll b) {
	if (b == 0) return a;
	return gcd(b, a % b);
}

void dfs(vi g[], int vis[], int src, int a[]) {
	vis[src] = 1;
	for (int v : g[src]) {
		if (!vis[v]) {
			dfs(g, vis, v, a);
		}
	}
}
int cnt;
void dfs2(vi g[], int vis[], int src, int a[], int n) {
	vis[src] = 1;
	if (cnt >= (n - 1)) return;

	for (int v : g[src]) {
		if (!vis[v]) {
			cout << src  + 1 << " ";
			cout << v + 1 << endl;
			cnt++;
			dfs2(g, vis, v, a, n);
		}
	}
}
void bfs(vi g[], ll n, int dis[], int p[]) {
	int visi[n + 1];
	for (int i = 1; i <= n; i++) visi[i] = 0;
	queue<int> q;
	q.push(1); visi[1] = 1;
	p[1] = -1;
	while (!q.empty()) {
		int top = q.front(); q.pop();
		for (int v : g[top]) {
			if (!visi[v]) {
				q.push(v);
				visi[v] = 1;
				dis[v] = dis[top] + 1;
				p[v] = top;
			}
		}
	}
}
// bool vis[100010];
// int subtreesize[100010];
// vi adjacency_list[100010];
pair<ll, int> subtree_size_dfs(vi adjacency_list[], int node, bool vis[], int subtreesize[] ) {
	vis[node] = true;
	int cur = 1;
	ll mex = 0;
	for (int child : adjacency_list[node]) {
		if (!vis[child]) {
			// p[child] = node;
			auto tmp = subtree_size_dfs(adjacency_list, child, vis, subtreesize);
			mex = max(mex, tmp.first);
			cur += tmp.second;
		}
	}
	subtreesize[node] = cur;
	return {cur + mex, cur};

}

int dx[] = {1, -1, 0, 0};
int dy[] = {0, 0, 1, -1};
const int max_r = 2000;
const int max_c = 2000;
int bfs_grid(char grid[][max_c], int n, int m, int sx, int sy, vpii al[], int desx, int desy) {
	bool vis[n][m];
	int dis[n][m];
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			vis[i][j] = false;
			dis[i][j] = -1;
		}
	}
	int visc[26] = {0};
	for (int i = 0; i < 26; i++) {
		visc[i] = false;
	}
	queue<pii> q;
	q.push({sx, sy});
	vis[sx][sy] = true;
	dis[sx][sy] = 0;
	while (!q.empty()) {
		pii top = q.front(); q.pop();
		int nx = top.ff;
		int ny = top.ss;
		for (int i = 0; i < 4; i++) {
			int tx = top.ff + dx[i];
			int ty = top.ss + dy[i];

			if (tx >= 0 && tx < n && ty >= 0 && ty < m && !vis[tx][ty] && grid[tx][ty] != '#') {
				vis[tx][ty] = true;
				q.push({tx, ty});
				dis[tx][ty] = dis[top.ff][top.ss] + 1;
			}

		}
		if (grid[nx][ny] >= 'a' && grid[nx][ny] <= 'z' && !visc[grid[nx][ny] - 'a']) {
			int num = grid[nx][ny] - 'a';
			visc[num] = 1;
			for (int i = 0; i < (int)al[num].size(); i++) {
				int tx = al[num][i].ff;
				int ty = al[num][i].ss;
				if (tx >= 0 && tx < n && ty >= 0 && ty < m && !vis[tx][ty] && grid[tx][ty] != '#') {
					vis[tx][ty] = true;
					q.push({tx, ty});
					dis[tx][ty] = dis[nx][ny] + 1;
				}


			}
		}
	}
	return dis[desx][desy];

}
int main()
{
	fast_io();
#ifndef ONLINE_JUDGE
	freopen("input.txt", "r", stdin);
	freopen("output.txt", "w", stdout);
#endif

	int t = 1;
	// cin >> t;
	while (t--)
	{
		char grid[max_r][max_c];
		int n, m; cin >> n >> m;
		int sx, sy, desx, desy;
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				cin >> grid[i][j];
				if (grid[i][j] == 'S') {
					sx = i; sy = j;
				}
				if (grid[i][j] == 'G') {
					desx = i; desy = j;
				}
			}
		}

		vpii al[26];
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				if (grid[i][j] >= 'a' && grid[i][j] <= 'z') {
					int num = grid[i][j] - 'a';
					al[num].pb({i, j});
				}
			}
		}
		cout << bfs_grid(grid, n, m, sx, sy, al, desx, desy) << endl;












	}

}
#include <bits/stdc++.h>

#define ll long long
#define map unordered_map
#define set unordered_set
#define l_l pair<ll, ll>
#define P pair<ll, ll>
#define vll vector<ll>
#define mll map<ll, ll>
#define mp make_pair
#define rep(i, n) for (int i = 0, i##_len = (n); i < i##_len; ++i)
#define reps(i, n) for (int i = 1, i##_len = (n); i <= i##_len; ++i)
#define rev(i, n) for (int i = ((int)(n)-1); i >= 0; --i)
#define revs(i, n) for (int i = ((int)(n)); i > 0; --i)
// template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return 1; } return 0; }
// template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return 1; } return 0; }

using namespace std;

const ll MOD = 1000000007LL;
const ll INF = (1LL << 60LL);

// template <class T> void plus_mod(T &a, const T &b) {a = (a + b) % MOD;}

vector<P> warps[30];

ll warp_points[2010][2010];

ll maze[2010][2010];

vector<P> get_warp(ll y, ll x) {
  ll wid = warp_points[y][x];

  return warps[wid];

  // auto point1 = warps[wid][0];
  // auto point2 = warps[wid][1];

  // if (point1.first == y && point1.second == x) {
  //   return point2;
  // } else {
  //   return point1;
  // }
}

int main() {
  // std::cout << std::fixed << std::setprecision(10);

  ll H, W;
  scanf("%lld %lld", &H, &W);

  fill(maze[0], maze[2005], -1);

  ll sy, sx, gy, gx;

  // インデックス1開始なので注意
  reps(y, H) {
    string line;
    cin >> line;

    reps(x, line.size()) {
      char ch = line[x - 1];
      if (ch == '#') {
        maze[y][x] = -1;
      } else if (ch == '.') {
        maze[y][x] = INF;
      } else if (ch == 'S') {
        sy = y;
        sx = x;
        maze[y][x] = 0;
      } else if (ch == 'G') {
        gy = y;
        gx = x;
        maze[y][x] = INF;
      } else {
        // ワープ
        ll wid = ch - 'a' + 1;
        warps[wid].emplace_back(mp(y, x));
        warp_points[y][x] = wid;

        maze[y][x] = INF;
      }
    }
  }

  //--------------------------------------------------

  deque<l_l> que;
  que.emplace_back(mp(sy, sx));
  maze[sy][sx] = 0;

  for (;;) {
    if (que.empty()) {
      break;
    }
    auto pos = que.front();
    que.pop_front();
    ll y = pos.first;
    ll x = pos.second;

    // cout << "y:" << (y) << ",x:" << (x) << endl;

    ll c = maze[y][x];

    for (auto e : {mp(y - 1, x), mp(y, x - 1), mp(y + 1, x), mp(y, x + 1)}) {
      if (maze[e.first][e.second] == -1) {
        continue;
      }
      if (maze[e.first][e.second] <= c + 1) {
        continue;
      }
      maze[e.first][e.second] = c + 1;
      que.emplace_back(make_pair(e.first, e.second));
    }

    if (warp_points[y][x]) {
      ll wid = warp_points[y][x];

      auto warp_list = get_warp(y, x);

      rep(i, warp_list.size()) {
        auto next = warp_list[i];

        warp_points[next.first][next.second] = 0;

        if (maze[next.first][next.second] > c + 1) {
          // cout << "WARP!:"
          //      << "next.first:" << (next.first) << ",next.second:" << (next.second) << endl;
          maze[next.first][next.second] = c + 1;
          que.emplace_front(make_pair(next.first, next.second));
        }

        warp_points[next.first][next.second] = 0;
      }
    }
  }

  ll ans = maze[gy][gx];

  if (ans == INF) {
    cout << (-1) << endl;
    return 0;
  }
  cout << ans << endl;
}
