#include <bits/stdc++.h>

#ifdef DEBUG
#define PRINT(x)\
    cout<<"func "<<__func__<<": line "<<__LINE__<<": "<<#x<<" = "<<(x)<<endl;
#define PRINTA(a,first,last)\
    cout<<"func "<<__func__<<": line "<<__LINE__<<": "<<#a<<"["<<(first)<<", "<<(last)<<")"<<endl;\
    for (int i=(first);i<(last);++i){cout<<#a<<"["<<i<<"] = "<<(a)[i]<<endl;}
#else
#define PRINT(x)
#define PRINTA(a,first,last)
#endif

#define FOR(i,a,b) for (int i=(a);i<(b);i++)
#define RFOR(i,a,b) for (int i=(b)-1;i>=(a);i--)
#define REP(i,n) for (int i=0;i<(n);i++)
#define RREP(i,n) for (int i=(n)-1;i>=0;i--)
#define pb push_back
#define mp make_pair
#define all(a) (a).begin(),(a).end()
#define MOD 1000000007

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;

template <class T, class U> void amax(T& x, U y) {if (x < y) x = y;}
template <class T, class U> void amin(T& x, U y) {if (x > y) x = y;}


template <class T>
struct edge
{
    int to;
    T cost;
    edge(int t, T c = 0) : to(t), cost(c) {}
};

template <class T>
class graph
{
    private:
        const int number_of_nodes;
    public:
        T inf;
        vector<edge<T> > *edges;
        vector<vector<T> > connected;
        graph(int n) : number_of_nodes(n) {
            edges = new vector<edge<T> >[n];
        }
        ~graph() {
            delete[] edges;
        }
        int size() const {return number_of_nodes;}
        void make_edge(int u, int v, T cost, bool is_undirected=false) {
            edges[u].push_back(edge<T>(v, cost));
            if (is_undirected) {
                edges[v].push_back(edge<T>(u, cost));
            }
        }
};

template <class T>
vector<T> dijkstra(const graph<T> &g, int start)
{
    vector<T> dist(g.size());
    bool *used = new bool[g.size()];
    fill(used, used + g.size(), false);
    priority_queue<pair<T, int>, vector<pair<T, int> >, greater<pair<T, int> > > q;
    REP(i, g.size()) dist[i] = INT_MAX;
    dist[start] = 0;
    q.push(pair<T, int>(0, start));
    used[start] = true;
    while(!q.empty()) {
        pair<T, int> p = q.top();
        q.pop();
        int from = p.second;
        if (dist[from] < p.first) {
            continue;
        }
        for (int i = 0; i < g.edges[from].size(); ++i) {
            int to = g.edges[from][i].to;
            T cost = g.edges[from][i].cost;
            if (!used[to]) {
                dist[to] = dist[from] + cost;
                q.push(pair<T, int>(dist[to], to));
                used[to] = true;
            }
            else if (dist[to] > dist[from] + cost) {
                dist[to] = dist[from] + cost;
                q.push(pair<T, int>(dist[to], to));
            }
        }
    }
    delete[] used;
    return dist;
}



int main(void)
{
    const int H_MAX = 50;
    int H, W;
    string s[H_MAX];
    cin >> H >> W;
    REP(i, H) cin >> s[i];
    graph<int> g(H * W);
    int nwhites = 0;
    REP(i, H) REP(j, W) {
        if (s[i][j] == '#') {
            continue;
        }
        ++nwhites;
        if (i + 1 < H && s[i + 1][j] == '.') {
            g.make_edge(i*W + j, (i+1)*W + j, 1);
        }
        if (i - 1 >= 0 && s[i - 1][j] == '.') {
            g.make_edge(i*W + j, (i-1)*W + j, 1);
        }
        if (j + 1 < W && s[i][j + 1] == '.') {
            g.make_edge(i*W + j, i*W + j+1, 1);
        }
        if (j - 1 >= 0 && s[i][j - 1] == '.') {
            g.make_edge(i*W + j, i*W + j-1, 1);
        }
    }
    vector<int> dist = dijkstra(g, 0);
    int d = dist[(H - 1) * W + W - 1];
    if (d == INT_MAX) {
        cout << -1 << endl;
    } else {
        cout << nwhites - d - 1 << endl;
    }
    return 0;
}


Measured memory_bytes: 384