using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace atcoder
{
	class Program
	{
		static int In => int.Parse(Console.ReadLine());
		static int[] Ins => Console.ReadLine().Split(' ').Select(int.Parse).ToArray();
		static void Out(bool b) => Console.WriteLine(b ? "Yes" : "No");

		static string[] map;
		static int H, W;

		static void Main(string[] args)
		{
			var input = Ins;
			H = input[0];
			W = input[1];
			map = new string[input[0]];
			for(int i = 0;i < input[0];i++)
			{
				map[i] = Console.ReadLine();
			}
			
			Node n = new Node(new IntPoint(1, 1), 0,new IntPoint[0]);
			Node ans = (Node)DijkstrasAlgorithm(n);
			if (ans == null) Console.WriteLine(-1);
			else
			{
				List<IntPoint> li = new List<IntPoint>(ans.route);
				int sum = 0;
				for (int i = 0; i < H; i++)
				{
					for (int j = 0; j < W; j++)
					{
						if (map[i][j] == '.')
						{
							int id = li.IndexOf(new IntPoint(j + 1, i + 1));
							if (id == -1) sum++;
						}
					}
				}
				Console.WriteLine(sum);
			}
		}

		/// <summary>
		/// ダイクストラのアルゴリズム
		/// </summary>
		/// <param name="start"></param>
		/// <param name="max">最大化問題を解く</param>
		/// <returns></returns>
		public static INodeEv DijkstrasAlgorithm(INodeEv start, bool max = false)
		{
			var pque = new PriorityQueue<INodeEv>(max);
			var visited = new HashSet<Node>();
			pque.Push(start);
			visited.Add((Node)start);
			while (pque.Length != 0)
			{
				var item = pque.Pop();
				if (item.IsGoal()) return item;
				foreach (var next in item.GetNext())
				{
					if (!visited.Contains(next))
					{
						visited.Add((Node)next);
						pque.Push(next);
					}
				}
			}
			return null;
		}

		public class Node : INodeEv
		{
			IntPoint p;
			int dis;
			public IntPoint[] route;

			public override bool Equals(object obj)
			{
				return this.p.X == ((Node)obj).p.X && this.p.Y == ((Node)obj).p.Y;
			}

			public Node(IntPoint pp,int d,IntPoint[] r)
			{
				p = pp;
				dis = d;
				List<IntPoint> li = new List<IntPoint>(r);
				li.Add(pp);
				route = li.ToArray();
			}

			public int CompareTo(object obj)
			{
				var i = dis.CompareTo(((Node)obj).dis);
				if (i == 0) return p.CompareTo(((Node)obj).p);
				else return i;
			}

			public override int GetHashCode()
			{
				return this.p.GetHashCode();
			}

			public bool Equals(INodeEv x, INodeEv y)
			{
				return ((Node)x).p.Equals(((Node)y).p);
			}

			public int GetHashCode(INodeEv obj)
			{
				return p.GetHashCode();
			}

			public IEnumerable<INodeEv> GetNext()
			{
				var pp = p + new IntPoint(0, 1);
				if (isin(pp)) yield return new Node(pp, dis + 1,route);
				pp = p + new IntPoint(0, -1);
				if (isin(pp)) yield return new Node(pp, dis + 1,route);
				pp = p + new IntPoint(1, 0);
				if (isin(pp)) yield return new Node(pp, dis + 1,route);
				pp = p + new IntPoint(-1, 0);
				if (isin(pp)) yield return new Node(pp, dis + 1,route);
			}

			bool isin(IntPoint pos)
			{
				return 1 <= pos.X && pos.X <= W && 1 <= pos.Y && pos.Y <= H && map[pos.Y-1][pos.X-1] != '#';
			}

			public bool IsGoal()
			{
				return p.X == W && p.Y == H;
			}
		}

		public interface INodeEv : IComparable, IEqualityComparer<INodeEv>
		{
			bool IsGoal();
			IEnumerable<INodeEv> GetNext();
		}
	}

	/// <summary>
	/// 優先度付きキューを提供する
	/// </summary>
	/// <typeparam name="T"></typeparam>
	public class PriorityQueue<T> where T : IComparable
	{
		#region member
		private List<T> list;
		private bool reverse;
		#endregion

		#region constructor
		/// <summary>
		/// 
		/// </summary>
		/// <param name="isReverse">定義された順序の逆で評価する</param>
		public PriorityQueue(bool isReverse = false)
		{
			list = new List<T>();
			reverse = isReverse;
		}
		#endregion

		#region private method
		private bool compare(T a, T b)
		{
			return reverse ^ a.CompareTo(b) > 0;
		}

		private void swap(int a, int b)
		{
			T tmp = list[a];
			list[a] = list[b];
			list[b] = tmp;
		}
		#endregion

		#region public method
		/// <summary>
		/// 要素を追加する
		/// </summary>
		/// <param name="item">追加する要素</param>
		public void Push(T item)
		{
			if (Length < list.Count) list[Length] = item;
			else list.Add(item);
			var pos = Length++;
			while (pos != 0)
			{
				var parent = (pos + 1) / 2 - 1;
				if (compare(list[pos], list[parent])) break;
				swap(pos, parent);
				pos = parent;
			}
		}

		/// <summary>
		/// 要素を追加する
		/// </summary>
		/// <param name="items">追加する要素の列</param>
		public void Push(IEnumerable<T> items)
		{
			foreach (var item in items)
			{
				Push(item);
			}
		}

		/// <summary>
		/// 値を確認する
		/// </summary>
		/// <returns></returns>
		public T Peek()
		{
			return list[0];
		}

		/// <summary>
		/// 値を取り出す
		/// </summary>
		/// <returns></returns>
		public T Pop()
		{
			var ret = Peek();
			var pos = 0;
			list[0] = list[--Length];
			while (2 * pos + 1 < Length)
			{
				var child = 2 * pos + 1;
				var child_other = 2 * pos + 2;
				if (child_other < Length && compare(list[child], list[child_other]))
				{
					child = child_other;
				}
				if (compare(list[child], list[pos])) break;
				swap(pos, child);
				pos = child;
			}
			return ret;
		}

		/// <summary>
		/// クリアする
		/// </summary>
		public void Clear()
		{
			list.Clear();
		}
		#endregion

		#region property
		/// <summary>
		/// 要素の長さを取得する
		/// </summary>
		public int Length
		{
			get;
			private set;
		}
		#endregion
	}

	public class IntPoint : IComparable, ICloneable
	{
		#region member
		public int X
		{
			get;
			private set;
		}
		public int Y
		{
			get;
			private set;
		}
		#endregion

		#region constructor
		public IntPoint(int x, int y)
		{
			X = x;
			Y = y;
		}

		public IntPoint()
		{
			X = 0;
			Y = 0;
		}
		#endregion

		#region operator
		public static IntPoint operator +(IntPoint a, IntPoint b)
		{
			return new IntPoint(a.X + b.X, a.Y + b.Y);
		}

		public static IntPoint operator -(IntPoint a, IntPoint b)
		{
			return new IntPoint(a.X - b.X, a.Y - b.Y);
		}
		public static bool operator ==(IntPoint a, IntPoint b)
		{
			return a.X == b.X && a.Y == b.Y;
		}
		public static bool operator !=(IntPoint a, IntPoint b)
		{
			return !(a == b);
		}
		public static bool operator >(IntPoint a, IntPoint b)
		{
			if (a.X != b.X) return a.X > b.Y;
			else return a.Y > b.Y;
		}
		public static bool operator >=(IntPoint a, IntPoint b)
		{
			return a == b || (a > b);
		}
		public static bool operator <(IntPoint a, IntPoint b)
		{
			return !(a >= b);
		}
		public static bool operator <=(IntPoint a, IntPoint b)
		{
			return !(a > b);
		}
		#endregion

		#region public method
		/// <summary>
		/// マンハッタン距離を取得する
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <returns></returns>
		public static int GetManhattanDistance(IntPoint a, IntPoint b)
		{
			return Math.Abs(a.X - b.X) + Math.Abs(a.Y - b.Y);
		}

		/// <summary>
		/// ユークリッド距離を取得する
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <returns></returns>
		public static double GetEuclideanDistance(IntPoint a, IntPoint b)
		{
			var tmp = a - b;
			return Math.Sqrt(tmp.X * tmp.X + tmp.Y * tmp.Y);
		}
		#endregion

		#region override or implementation
		public int CompareTo(object obj)
		{
			if (X != ((IntPoint)obj).X) return X.CompareTo(((IntPoint)obj).X);
			else return Y.CompareTo(((IntPoint)obj).Y);
		}

		public override bool Equals(object obj)
		{
			return this.X == ((IntPoint)obj).X && this.Y == ((IntPoint)obj).Y;
		}

		public override int GetHashCode()
		{
			return X.GetHashCode() + (Y.GetHashCode() << 1);
		}

		public object Clone()
		{
			return new IntPoint(X, Y);
		}
		#endregion
	}
}


Measured memory_bytes: 16976