#include<iostream>
#include<algorithm>
#include<vector>
#include<cmath>
#include<map>
#include<cassert>
#include<climits>
#include<queue>

#define REP(i,s,n) for(int i=s;i<n;i++)
#define rep(i,n) REP(i,0,n)
#define inf (1<<29)
#define MAX 10

using namespace std;

struct P
{
  int x,y;
  P(int x=inf,int y=inf):x(x),y(y){}
  bool operator < (const P& a)const
  {
    if(x != a.x)return x < a.x;
    return y < a.y;
  }
};

struct Pox
{
  string field;
  P cur;
  short cost;
  Pox(string field="$",P cur = P(),short cost=SHRT_MAX):field(field),cur(cur),cost(cost){}
  bool operator < (const Pox& a)const
  {
    return cost > a.cost;
  }
};

map<string,short> mincost;
int H,W;
P st,ed;
vector<P> stone;
string field;
int dx[] = {-1,+0,+1,+0};
int dy[] = {+0,-1,+0,+1};

void compute()
{
  priority_queue<Pox> Q;
  Q.push(Pox(field,st,0));
  mincost.clear();
  mincost[field] = 0;

  while(!Q.empty())
    {
      Pox pox = Q.top(); Q.pop();
      int x = pox.cur.x;
      int y = pox.cur.y;
 
      if(field[y*W+x] == 'E')
	{
	  cout << pox.cost << endl;
	  return;
	}

      rep(i,4)
	{
	  int nx = x + dx[i];
	  int ny = y + dy[i];
	  string nfield = pox.field;
	  if(!(0 <= nx && nx < W && 0 <= ny && ny < H))continue;
	  if(pox.field[W*ny+nx] == 'c')
	    {
	      int sx = nx+dx[i], sy = ny+dy[i];
	      while(0 <= sx && sx < W && 0 <= sy && sy < H)
		{
		  if(pox.field[sy*W+sx] == 'c')break;
		  if(pox.field[sy*W+sx] == '#')break;
		  if(pox.field[sy*W+sx] == 'w')break;
		  sx += dx[i];
		  sy += dy[i];
		}

	      if(0 <= sx && sx < W && 0 <= sy && sy < H)
		{
		  if(pox.field[sy*W+sx] == 'w')
		    {
		      nfield[ny*W+nx] = '.';
		      nfield[sy*W+sx] = '.';
		      Q.push(Pox(nfield,pox.cur,pox.cost));
		      continue;
		    }
		}

	      sx -= dx[i],sy -= dy[i];
	      if(sx == nx && sy == ny)continue;//cannot move the stone

	      nfield[W*ny+nx] = '.';
	      if(ny == ed.y && nx == ed.x)nfield[W*ed.y+ed.x] = 'E';
	      nfield[W*sy+sx] = 'c';
	      Q.push(Pox(nfield,pox.cur,pox.cost));
	    }
	}

      
      rep(i,4)
	{
	  int nx = pox.cur.x + dx[i];
	  int ny = pox.cur.y + dy[i];
	  string nfield = pox.field;

	  if(!(0 <= nx && nx < W && 0 <= ny && ny < H))continue;
	  if(pox.field[W*ny+nx] == '#')continue;
	  if(pox.field[W*ny+nx] == 'w')continue;

	  if(pox.field[W*ny+nx] == 'c')continue;

	  nfield[y*W+x] = '.';

	  assert(nfield[ny*W+nx] == '.' || nfield[ny*W+nx] == 'E');
	  nfield[ny*W+nx] = '@';

	  if(mincost.find(nfield) == mincost.end())
	    {
	      mincost[nfield] = pox.cost + 1;
	      Q.push(Pox(nfield,P(nx,ny),pox.cost+1));
	    }
	  else
	    {
	      if(mincost[nfield] > pox.cost + 1)
		{
		  mincost[nfield] = pox.cost + 1;
		  Q.push(Pox(nfield,P(nx,ny),pox.cost+1));
		}
	    }
	}
      
    }
  cout << -1 << endl;
}

int main()
{
  while(cin >> H >> W,H|W)
    {
      st = P(inf,inf);
      field.clear();
      int dex = 0;
      rep(i,H)
	{
	  string line;
	  cin >> line;
	  field += line;
	  rep(j,W)
	    {
	      if(line[j] == '@')st = P(j,i),line[j] = '.';
	      if(line[j] == 'E')ed = P(j,i);
	      if(line[j] == 'c')stone.push_back(P(j,i));
	    }
	}
      
      assert(!(st.x == inf && st.y == inf));

      compute();

    }
  return 0;
}

/*
コンテナの動かす方法の解釈ミス

10 10
##########
#..#@#...#
#..#c#...#
#........#
#..cEc...#
#...#....#
#........#
#........#
#........#
##########
0 0

Ans : 7

10 10
##########
#........#
#..@.c..c#
#...c....#
#...ww.###
#........#
##.......#
#..####..#
#..wE#...#
##########
0 0

Ans : 31
 */

Measured memory_bytes: 11820