#include <iostream>
#include <string>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <numeric>
#include <regex>
#include <climits>

#define FOR(i, f, n) for(int (i) = (f); (i) < (n); (i)++)
#define RFOR(i, f, n) for(int (i) = (f); (i) >= (n); (i)--)
#define REP(i, n) for(int (i) = 0; (i) < (n); (i)++)
#define RREP(i, n) for(int (i) = (n); (i) >= 0; (i)--)
#define rep(i, n) for(int (i) = 0; (i) < (n); (i)++)
#define rrep(i, n) for(int (i) = (n); (i) >= 0; (i)--)
#define forin(i, a) for(auto i: (a))
#define p(...) printf(__VA_ARGS__); cout << endl;
#define in(...) __VA_ARGS__; input__(__VA_ARGS__);
#define input(...) in(__VA_ARGS__)
#define out(...) output__(__VA_ARGS__);
#define output(...) out(__VA_ARGS__)
#define list_input(x, n) x[(n)]; for(int (i) = 0; (i) < (n); (i)++) cin >> x[i];
#define lambda(a, b, c) [](auto const &a, auto const &b){ return c ;}
#define key(t, x, compare) [](const t &a, const t &b){ return a x compare b x ;}
#define unless(a) if(!(a))

using namespace std;

using pii = pair<int, int>;

template <class... T>
void input__(T &...a) {
  for(auto v: {&a...}) {
    cin >> *v;
  }
}

void output__(){
  cout << endl;
}

template <class Head, class... T>
void output__(Head const &v, T const &...a) {
  if(sizeof...(a) == 0) {
    cout << v;
  } else {
    cout << v << " ";
  }
  output__(a...);
}
int h, w;
string maze[50];

struct Args {
  int x, y, cnt;
};

struct Node {
  int to, cost;
};

Args d[] = {
  {0, 1}, {0, -1}, {1, 0}, {-1, 0}
};

Args n2c(int n) {
  return {n % w, n / w};
}

int c2n(Args c) {
  return c.y * w + c.x;
}

Args start, goal;

int min_node(vector<int> opt_nodes, vector<long long> costs) {
  long long min_value = LLONG_MAX;
  int result = -1;
  for(int i: opt_nodes) {
    if(min_value > costs[i]) {
      min_value = costs[i];
      result = i;
    }
  }
  return result;
}

long long min_track(int node_num, vector<Node> *graph) {
  int now = c2n(start);
  vector<long long> costs = vector<long long>(node_num, LLONG_MAX);
  vector<bool> visited = vector<bool>(node_num, false);
  vector<int> opt_nodes;

  visited[now] = true;
  costs[now] = 0;

  rep(i, node_num) {
    for(Node node : graph[now]) {
      if(visited[node.to]) {
        continue;
      }

      opt_nodes.push_back(node.to);
      costs[node.to] = min(costs[node.to], costs[now] + 1);
    }

    if((now = min_node(opt_nodes, costs)) == -1) {
      break;
    }

    visited[now] = true;
    opt_nodes.erase(remove(opt_nodes.begin(), opt_nodes.end(), now), opt_nodes.end());
  }
  return costs[c2n(goal)];
}

int main(){
  int in(h_, w_);
  h = h_; w = w_;

  int result = 0;
  rep(i, h) {
    cin >> maze[i];
    rep(j, w) {
      if(maze[i][j] == '.') result++;
    }
  }

  start = {0, 0};
  goal = {w - 1, h - 1};

  vector<Node> graph[h * w];
  rep(i, h) rep(j, w) rep(k, 4) {
    int nx = j + d[k].y, ny = i + d[k].x;
    int now = c2n({j, i});
    if(0 <= nx and nx < w and 0 <= ny and ny < h and maze[ny][nx] == '.' and maze[i][j] == '.') {
      graph[now].push_back({c2n({nx, ny}), 1});
    }
  }
  long long tmp = min_track(h * w, graph);
  if(tmp == LLONG_MAX) {
    out(-1);
  } else {
    out(result - tmp - 1);
  }
}


Measured memory_bytes: 512