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 void Main(string[] args)
		{
			var input = Ins;
			string[] map = new string[input[0]];
			int count = 0;
			for (int i = 0; i < input[0]; i++)
			{
				map[i] = Console.ReadLine();
				count += map[i].Count(c => c == '.');
			}
			SquaresMap sm = new SquaresMap(map);
			var ans = sm.GetShortestPath(new IntPoint(), new IntPoint(sm.Width - 1, sm.Height - 1));
			if(ans == null) Console.WriteLine(-1);
			else Console.WriteLine(count - ans.Length);
		}
	}

	public class SquaresMap
	{
		private const char ObstacleChar = '#';
		private static IntPoint[] near4 = new IntPoint[] { new IntPoint(-1, 0), new IntPoint(1, 0), new IntPoint(0, -1), new IntPoint(0, 1) };
		private static IntPoint[] nearSlan = new IntPoint[] { new IntPoint(-1, -1), new IntPoint(-1, 1), new IntPoint(1, -1), new IntPoint(1, 1) };

		private string[] _map;

		public SquaresMap(string[] map)
		{
			_map = new string[map.Length];
			for (int i = 0; i < map.Length; i++) _map[i] = (string)map[i].Clone();
		}

		private bool IsIn(IntPoint p)
		{
			return IsIn(p.X, p.Y);
		}

		private bool IsIn(int x, int y)
		{
			return 0 <= x && x < Width && 0 <= y && y < Height;
		}

		private bool IsRegular(IntPoint p)
		{
			return IsIn(p) && _map[p.Y][p.X] != ObstacleChar;
		}

		public IntPoint[] GetShortestPath(IntPoint s, IntPoint t)
		{
			IntPoint Unreached = new IntPoint(-1, -1);
			IntPoint[][] previousPoint = new IntPoint[Height][];
			for (int i = 0; i < Height; i++)
			{
				previousPoint[i] = new IntPoint[Width];
				for (int j = 0; j < Width; j++) previousPoint[i][j] = Unreached;
			}
			var queue = new Queue<IntPoint>();
			if (IsRegular(s))
			{
				queue.Enqueue(s);
				previousPoint[s.Y][s.X] = new IntPoint();
			}
			else return null;
			while (queue.Count != 0)
			{
				var item = queue.Dequeue();
				if (item == t) break;
				foreach (var next in GetNear4(item))
				{
					if (previousPoint[next.Y][next.X] == Unreached)
					{
						previousPoint[next.Y][next.X] = item;
						queue.Enqueue(next);
					}
				}
			}
			if (!IsRegular(t) || previousPoint[t.Y][t.X] == Unreached) return null;
			var list = new LinkedList<IntPoint>();
			list.AddFirst(t);
			IntPoint currentPoint = t;
			while (true)
			{
				var pre = previousPoint[currentPoint.Y][currentPoint.X];
				list.AddFirst(pre);
				if (pre == s) break;
				currentPoint = pre;
			}
			return list.ToArray();
		}

		public IEnumerable<IntPoint> GetNear4(IntPoint point)
		{
			foreach (var near in near4)
			{
				var n = point + near;
				if (IsRegular(n)) yield return n;
			}
		}

		public IEnumerable<IntPoint> GetNear8(IntPoint point)
		{
			foreach (var near in GetNear4(point)) yield return near;
			foreach (var near in nearSlan)
			{
				var n = point + near;
				if (IsRegular(n)) yield return n;
			}
		}

		public int Width
		{
			get
			{
				return _map[0].Length;
			}
		}

		public int Height
		{
			get
			{
				return _map.Length;
			}
		}
	}

	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: 13780