void main(){
  import std.stdio, std.string, std.conv, std.algorithm;
  import std.exception, std.typecons, std.container;

  int h, w; rd(h, w);
  auto c=new char[][](h, w);
  foreach(i; 0..h) c[i]=readln.chomp.to!(char[]);

  alias pair=Tuple!(int, int);
  int[pair] map;
  foreach(i; 0..h)foreach(j; 0..w) map[pair(i, j)]=map.length.to!(int);
  auto n=h*w;
  struct Edge{int to, cost;}
  auto g=new Edge[][](n);
  auto dir=[[1, 0], [-1, 0], [0, 1], [0, -1]];
  foreach(i; 0..h)foreach(j; 0..w){
    if(c[i][j]=='#') continue;
    foreach(dd; dir){
      auto ai=i+dd[0], aj=j+dd[1];
      if(ai<0 || ai>=h || aj<0 || aj>=w) continue;
      if(c[ai][aj]=='.'){
        g[map[pair(i, j)]]~=Edge(map[pair(ai, aj)], 1);
        g[map[pair(ai, aj)]]~=Edge(map[pair(i, j)], 1);
      }
    }
  }

  alias T=int;
  const inf=1e9.to!(T);
  T[] dijkstra(Edge[][] g, int s){
    auto d=new T[](n);
    fill(d, inf);
    struct P{int v; T d;}
    import std.container;
    auto Q=new RedBlackTree!(P, "a.d<b.d", true);
    Q.insert(P(s, 0)); d[s]=0;
    while(Q.empty==false){
      auto cur=Q.front; Q.removeFront;
      foreach(e; g[cur.v]){
        if(d[e.to]<=d[cur.v]+e.cost) continue;
        d[e.to]=d[cur.v]+e.cost;
        Q.insert(P(e.to, d[e.to]));
      }
    }
    return d;
  }

  auto d=dijkstra(g, map[pair(0, 0)]);

  if(d[map[pair(h-1, w-1)]]==inf){writeln(-1); return;}

  int bk=0;
  foreach(i; 0..h) bk+=count(c[i], '#');
  auto res=n-bk-(d[map[pair(h-1, w-1)]]+1);
  enforce(res>=0);
  writeln(res);
}
void rd(T...)(ref T x){
  import std.stdio, std.string, std.conv;
  auto l=readln.split;
  assert(l.length==x.length);
  foreach(i, ref e; x){
    e=l[i].to!(typeof(e));
  }
}
