#include <iostream>
#include <iomanip>
#include <vector>
#include <algorithm>
#include <utility>
#include <string>
#include <queue>
#include <stack>
#include <unordered_map>

using namespace std;

typedef long long int ll;
typedef pair<int, int> Pii;

const ll mod = 1000000007;

int main() {
  cin.tie(0);
  ios::sync_with_stdio(false);

  int h, w;
  cin >> h >> w;
  vector<string> a(h);
  for (auto &x: a) cin >> x;

  unordered_map<char, vector<Pii> > teleporterLocation;
  Pii start;
  Pii goal;
  for (int i = 0; i < h; i++) {
    for (int j = 0; j < w; j++) {
      if ('a' <= a[i][j] && a[i][j] <= 'z') teleporterLocation[a[i][j]].emplace_back(i, j);
      else if (a[i][j] == 'S') start = Pii(i, j);
      else if (a[i][j] == 'G') goal = Pii(i, j);
    }
  }

  vector<vector<bool> > visited(h, vector<bool>(w));
  unordered_map<char, bool> teleporterVisited;
  queue<vector<int> > que;
  que.push(vector<int>({start.first, start.second, 0}));
  int ans = -1;
  while (!que.empty()) {
    auto now = que.front();
    que.pop();
    if (visited[now[0]][now[1]]) continue;
    visited[now[0]][now[1]] = true;
    if (now[0] == goal.first && now[1] == goal.second) {
      ans = now[2];
      break;
    }
    if ('a' <= a[now[0]][now[1]] && a[now[0]][now[1]] <= 'z') {
      if (!teleporterVisited[a[now[0]][now[1]]]) {
        teleporterVisited[a[now[0]][now[1]]] = true;
        for (auto &x: teleporterLocation[a[now[0]][now[1]]]) {
          if (!visited[x.first][x.second]) que.push(vector<int>({x.first, x.second, now[2]+1}));
        }
      }
    }
    if (now[0] > 0) {
      if (a[now[0]-1][now[1]] != '#' && !visited[now[0]-1][now[1]]) que.push(vector<int>({now[0]-1, now[1], now[2]+1}));
    }
    if (now[0] < h-1) {
      if (a[now[0]+1][now[1]] != '#' && !visited[now[0]+1][now[1]]) que.push(vector<int>({now[0]+1, now[1], now[2]+1}));
    }
    if (now[1] > 0) {
      if (a[now[0]][now[1]-1] != '#' && !visited[now[0]][now[1]-1]) que.push(vector<int>({now[0], now[1]-1, now[2]+1}));
    }
    if (now[1] < w-1) {
      if (a[now[0]][now[1]+1] != '#' && !visited[now[0]][now[1]+1]) que.push(vector<int>({now[0], now[1]+1, now[2]+1}));
    }
  }

  cout << ans << endl;

  return 0;
}

#include<bits/stdc++.h>
using namespace std;
#define vi vector<int>
#define ff first
#define ss second
#define pb push_back
#define mp make_pair
#define pi 3.141592653589793238
#define rep(i,a,b) for (int i = a; i <= b; i++)
#define zip(i,a,b) for(int i=a;i<b;i++)
#define rzip(i,a,b) for(int i=a;i>=b;i--)
#define ll unsigned int
#define test int t;cin>>t; while(t--)
#define en '\n'
typedef pair<int, int>     pii;
typedef pair<char, int>    pci;
typedef pair<char, char>   pcc;
typedef vector<pii>       vii;
typedef long double ld;
#define all(v) v.begin(), v.end()
#define rall(v) v.rbegin(),v.rend()
#define sz(x) (int)x.size()
#define INF (1e18+5)
#define inf (1e9+5)
#define mod 1000000007


void __print(int x) {cerr << x;}
void __print(float x) {cerr << x;}
void __print(double x) {cerr << x;}
void __print(long double x) {cerr << x;}
void __print(char x) {cerr << '\'' << x << '\'';}
void __print(const char *x) {cerr << '\"' << x << '\"';}
void __print(const string &x) {cerr << '\"' << x << '\"';}
void __print(bool x) {cerr << (x ? "true" : "false");}
// You should only debug a pair of simple data types. For example,
// the debug won't work if one of pair's elements is collection type
// (std::vector, std::map, std::set...).
template<typename T, typename V>
void __print(const pair<T, V> &x) {cerr << '{'; __print(x.first); cerr << ','; __print(x.second); cerr << '}';}
template<typename T>
void __print(const T &x) {int f = 0; cerr << '{'; for (auto &i : x) cerr << (f++ ? "," : ""), __print(i); cerr << "}";}
void _print() {cerr << "]\n";}
template <typename T, typename... V>
void _print(T t, V... v) {__print(t); if (sizeof...(v)) cerr << ", "; _print(v...);}
#ifndef ONLINE_JUDGE
#define debug(x...) cerr << "[" << #x << "] = ["; _print(x)
#else
#define debug(x...)
#endif


// bool check_prime(int n)  return whether a number is prime or not O(sqrt(N));
// int BE(int x,int n,int m)  return x^n%m; O(logN);
// void sieve()  from number 1-1000001 saare prime store kar lega  in bool is_prime[1000001] array
// vector<int> z_array(string s)  return vector which is Z-array of string s;
// vector<int> lps(string s)      return vector which is lps array of string s;
// int power(int x,int n) return x^n; O(logN);
// using_ordered_set (template for using ordered set , replace first 2 lines of this page with this code..);
const int gf = 2e3 + 9;
int dx[4] = { -1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};

char s[gf][gf];
vii v[26];
bool vis[gf][gf];
int dis[gf][gf];
bool vis2[gf];
int32_t main()
{
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(0);
#ifndef ONLINE_JUDGE
	if (fopen("input.txt", "r"))
	{
		freopen ("input.txt" , "r" , stdin);
		freopen ("output.txt" , "w" , stdout);
	}
#endif
	//_______________________________-code starts-_______________________________________________

	int h, w;
	cin >> h >> w;
	pii source;
	pii dest;
	rep(i, 0, gf - 1)rep(j, 0, gf - 1)s[i][j] = '#';
	rep(i, 1, h)
	{
		rep(j, 1, w)
		{
			cin >> s[i][j];
			if (s[i][j] >= 'a' && s[i][j] <= 'z')
				v[s[i][j] - 'a'].pb({i, j});
			if (s[i][j] == 'S')
			{
				source = {i, j};
			}
			else if (s[i][j] == 'G')
			{
				dest = {i, j};
			}
		}
	}
	queue<pii>q;
	q.push(source);
	vis[source.ff][source.ss] = 1;
	while (sz(q))
	{
		pii node = q.front();
		q.pop();
		int x = node.ff;
		int y = node.ss;
		zip(i, 0, 4)
		{
			int x1 = x + dx[i];
			int y1 = y + dy[i];
			if (s[x1][y1] == '#')
				continue;
			if (vis[x1][y1])
				continue;
			vis[x1][y1] = 1;
			q.push({x1, y1});
			dis[x1][y1] = dis[x][y] + 1;
		}
		if (s[x][y] >= 'a' && s[x][y] <= 'z')
		{
			if (vis2[s[x][y] - 'a'])
				continue;
			for (pii p : v[s[x][y] - 'a'])
			{
				int x1 = p.ff;
				int y1 = p.ss;
				if (vis[x1][y1])
					continue;
				vis[x1][y1] = 1;
				q.push({x1, y1});
				dis[x1][y1] = dis[x][y] + 1;
				vis2[s[x][y] - 'a'] = 1;
			}
		}
	}
	if (!vis[dest.ff][dest.ss])
		cout << -1 << en;
	else
		cout << dis[dest.ff][dest.ss] << en;




	return 0;
}


