#include<iostream>
#include<unordered_set>
#include<vector>
#include<queue>
using namespace std;
unordered_set<int> visited;
int n, m;
vector<vector<int>> direct = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
vector<vector<char>> graph;
struct node{
int xp, yp, xb, yb, s;
node(int xxp, int yyp, int xxb, int yyb, int ss){
xp = xxp, yp = yyp, xb = xxb, yb = yyb, s = ss;
}
};
bool valid(vector<int> dir, node cur, int n, int m){
int x = dir[0] + cur.xp, y = dir[1] + cur.yp;
int xxb = cur.xb, yyb = cur.yb;
if(x == cur.xb && y == cur.yb){
xxb += dir[0], yyb += dir[1];
}
if(x >= n || y >= m || x < 0 || y < 0 || xxb >= n || yyb >= m || xxb < 0 || yyb < 0){
return false;
}
else if(graph[x][y] == '#' || graph[xxb][yyb] == '#'){
return false;
}
else if(visited.find(x + y * 100 + xxb * 10000 + yyb * 1000000) != visited.end()){
return false;
}
return true;
}
int main(){
int n, m;
cin >> n >> m;
graph = vector<vector<char>>(n, vector<char>(m));
int xbox, ybox, xs, ys, xe, ye;
for(int i = 0; i < n; ++i){
for(int j = 0; j < m; ++j){
cin >> graph[i][j];
if(graph[i][j] == '0'){
xbox = i, ybox = j;
graph[i][j] = '.';
}
else if(graph[i][j] == 'S'){
xs = i, ys = j;
graph[i][j] = '.';
}
else if(graph[i][j] == 'E'){
xe = i, ye = j;
}
}
}
queue<node> q;
auto p = node(xs, ys, xbox, ybox, 0);
visited.insert(xs + ys * 100 + xbox * 10000 + ybox * 1000000);
q.push(p);
int ans = -1;
while(!q.empty()){
node cur = q.front();
q.pop();
if(cur.xb == xe && cur.yb == ye){
ans = cur.s;
break;
}
for(int i = 0; i < 4; ++i){
if(!valid(direct[i], cur, n, m)){
continue;
}
int xn = cur.xp + direct[i][0], yn = cur.yp + direct[i][1];
int xbn = cur.xb, ybn = cur.yb;
if(xn == cur.xb && yn == cur.yb){
xbn += direct[i][0], ybn += direct[i][1];
}
visited.insert(xn + yn * 100 + xbn * 10000 + ybn * 1000000);
q.push(node(xn, yn, xbn, ybn, cur.s + 1));
}
}
cout << ans << endl;
}