#pragma once
#include <string.h>
#include <stdio.h>
#include <sstream>
#include <string>
#include <vector>
#include <map>
#include <algorithm>
#include <iostream>
#include <utility>
#include <set>
#include <cctype>
#include <queue>
#include <stack>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <deque>
using namespace std;
#define INF 1000000007
typedef long long ll;
typedef pair<int, int> pii;
int t[101];
int pri[26];
int res = 0;
ll gcd(ll a, ll b) {
	if (b == 0) return a;
	return gcd(b, a % b);
}
int pr[100010];
void uini(int n) {
	for (size_t i = 0; i <= n; i++)
	{
		pr[i] = i;
	}
}

int parent(int x) {
	if (x == pr[x]) return x;
	return pr[x] = parent(pr[x]);
}

bool unit(int x, int y) {
	int px = parent(x);
	int py = parent(y);

	if (px == py) return false;
	if (px < py) {
		pr[y] = px;
	}
	else {
		pr[x] = py;
	}
	return true;
}

// dinic
struct max_flow {
	struct edge { int to, cap, rev;
	edge(int _to, int _cap, int _rev) : to(_to), cap(_cap), rev(_rev) {}
	};
	int V;
	vector<vector<edge>> G;
	vector<int> itr, level;

	max_flow(int V) : V(V) { G.assign(V, vector<edge>()); }

	void add_edge(int from, int to, int cap) {
		G[from].push_back(edge (to, cap, (int)G[to].size() ));
		G[to].push_back(edge (from, 0, (int)G[from].size() - 1 ));
	}

	void bfs(int s) {
		level.assign(V, -1);
		queue<int> q;
		level[s] = 0; q.push(s);
		while (!q.empty()) {
			int v = q.front(); q.pop();
			for (auto &e : G[v]) {
				if (e.cap > 0 and level[e.to] < 0) {
					level[e.to] = level[v] + 1;
					q.push(e.to);
				}
			}
		}
	}

	int dfs(int v, int t, int f) {
		if (v == t) return f;
		for (int& i = itr[v]; i < (int)G[v].size(); ++i) {
			edge& e = G[v][i];
			if (e.cap > 0 && level[v] < level[e.to]) {
				int d = dfs(e.to, t, min(f, e.cap));
				if (d > 0) {
					e.cap -= d;
					G[e.to][e.rev].cap += d;
					return d;
				}
			}
		}
		return 0;
	}

	int run(int s, int t) {
		int ret = 0, f;
		while (bfs(s), level[t] >= 0) {
			itr.assign(V, 0);
			while ((f = dfs(s, t, INF)) > 0) ret += f;
		}
		return ret;
	}
};
vector<vector<int> > calcNext(const string &S) {
	int n = (int)S.size();
	vector<vector<int> > res(n + 1, vector<int>(26, n));
	for (int i = n - 1; i >= 0; --i) {
		for (int j = 0; j < 26; ++j) res[i][j] = res[i + 1][j];
		res[i][S[i] - 'a'] = i;
	}
	return res;
}

const int MOD = 1000000007;
// mod 1000000007 の世界で a += b する関数
void add(long long &a, long long b) {
	a += b;
	if (a >= MOD) a -= MOD;
}


string ta[55];
ll memo[55][55];
int h, w;
int dx[] = { 1,0,-1,0 };
int dy[] = { 0,1,0,-1 };
int d[55][55];
void rec() {
	for (size_t i = 0; i < 55; i++)
	{
		for (size_t j = 0; j < 55; j++)
		{
			d[i][j] = INF;
		}
	}
	d[0][0] = 0;
	priority_queue<pair<int, vector<int>>,vector<pair<int, vector<int>>>,greater<pair<int, vector<int>>>> q;
	q.push(pair<int, vector<int>>(0, { 0,0 }));
	while (!q.empty())
	{
		pair<int, vector<int>> p = q.top();
		q.pop();
		int px = p.second[0];
		int py = p.second[1];
		if (d[px][py] < p.first) continue;
		for (size_t i = 0; i < 4; i++)
		{
			int nx = px + dx[i];
			int ny = py + dy[i];
			if (nx < 0 || nx >= h || ny < 0 || ny >= w) continue;
			if (ta[nx][ny] == '#') continue;

			if (d[nx][ny] > d[px][py] + 1) {
				d[nx][ny] = d[px][py] + 1;
				q.push(pair<int, vector<int>>(d[nx][ny], {nx,ny}));
			}
		}
	}
}
void solv() {
	cin >> h >> w;
	for (size_t i = 0; i < h; i++)
	{
		cin >> ta[i];
	}
	int c = 0;
	for (size_t i = 0; i < h; i++)
	{
		for (size_t j = 0; j < w; j++)
		{
			c += ta[i][j] == '#';
		}
	}


	rec();
	ll v = d[h - 1][w - 1];
	if (v == INF) {
		cout << -1 << endl;
		return;
	}
	ll res = h * w - (v + 1) - c;
	cout << res << endl;
}


int main() {
	solv();

	return 0;
}


Measured memory_bytes: 256