unittest
{

assert( q"INPUT
3 3
..#
#..
...
INPUT".split( '\n' ).parse.expand.solve == 2 );

assert( q"INPUT
10 37
.....................................
...#...####...####..###...###...###..
..#.#..#...#.##....#...#.#...#.#...#.
..#.#..#...#.#.....#...#.#...#.#...#.
.#...#.#..##.#.....#...#.#.###.#.###.
.#####.####..#.....#...#..##....##...
.#...#.#...#.#.....#...#.#...#.#...#.
.#...#.#...#.##....#...#.#...#.#...#.
.#...#.####...####..###...###...###..
.....................................
INPUT".split( '\n' ).parse.expand.solve == 209 );

assert( q"INPUT
3 5
.#...
.#.#.
...#.
INPUT".split( '\n' ).parse.expand.solve == 0 );		// 追加ケース

assert( q"INPUT
3 3
...
###
...
INPUT".split( '\n' ).parse.expand.solve == -1 );		// 追加ケース

}



import std.conv;
import std.range;
import std.stdio;
import std.typecons;

void main()
{
	stdin.byLineCopy.parse.expand.solve.writeln;
}

auto parse( Range )( Range input )
if( isInputRange!Range && is( ElementType!Range == string ) )
{
	auto hw = input.front.split.to!( long[] );
	auto sss = new string[ hw[ 0 ] ];
	foreach( ref ss; sss )
	{
		input.popFront;
		ss = input.front;
	}
	return tuple( sss );
}

auto solve( string[] sss )
{
writefln( "\nsolve( %s )", sss );
	// 最短距離を計算
	auto dss = sss.bfs2d( 0, 0 );
	if( dss[ $ - 1 ][ $ - 1 ] == long.max ) return -1;
	
	// スタート地点と最短距離分のマス以外を全て黒で塗りつぶす（ルートは気にしなくてよい）
	auto ans = -1 - dss[ $ - 1 ][ $ - 1 ];
	foreach( ss; sss )
	{
		foreach( s; ss )
		{
			ans += ( s == '.' );
		}
	}
writefln( "ans = %s", ans );
	return ans;
}

// 2Dマップの始点指定最短経路探索（幅優先探索）
auto bfs2d( dchar w = '#' )( string[] css, long sy, long sx )
{
	import std.container.dlist;
	
	auto dss = new long[][]( css.length, css[ 0 ].length );
	foreach( ref ds; dss ) ds[] = long.max;
	dss[ sy ][ sx ] = 0;
	auto queue = make!DList( tuple( sy, sx ) );
	while( !queue.empty )
	{
		auto fy = queue.front[ 0 ];
		auto fx = queue.front[ 1 ];
		queue.removeFront();
		
		auto d = dss[ fy ][ fx ] + 1;
		foreach( f; [ tuple( fy - 1, fx ), tuple( fy + 1, fx ), tuple( fy, fx - 1 ), tuple( fy, fx + 1 ) ] )
		{
			if( f[ 0 ] < 0 || css.length      <= f[ 0 ] ||
			    f[ 1 ] < 0 || css[ 0 ].length <= f[ 1 ] ||
			    css[ f[ 0 ] ][ f[ 1 ] ] == w ||
			    dss[ f[ 0 ] ][ f[ 1 ] ] < long.max ) continue;
			dss[ f[ 0 ] ][ f[ 1 ] ] = d;
			queue.insertBack( f );
		}
	}
	return dss;
}
