require 'pp'
# IS_DEBUG = true
IS_DEBUG = false
def dputs str
	if(IS_DEBUG)
		puts str
	end
end
def dpp str
	if(IS_DEBUG)
		pp str
	end
end

class Maze
  ROOT='.'; WALL='#'; START='1'; GOAL='2'

  def initialize(map=nil, vec=nil)
    self.parseMap(map) if map
    unless vec
      vec = []
      for i in 0..3
        j = i%3==0 ? 1 : -1
        vec[i] = { :x=>(i+1)%2*j, :y=>i%2*j }
      end
    end
    @vec = vec
  end

  # マップ文字列を展開する
  def parseMap(map)
    @map = map.split("\n").map{|line| line.split }
    @size = Hash[*[[:x,:y],@map.shift.map{|val|val.to_i}].transpose.flatten]
    @map.each_with_index do |line,i|
      line.each_with_index do |val,j|
        @start = {:x=>j, :y=>i} if val==START
        @goal  = {:x=>j, :y=>i} if val==GOAL
      end
    end
  end

  # 探索開始
  def search()
    self.openNode(nil, pos=@start, cost=0)
    loop do
      cost += 1
      @vec.each do |vec|
        newPos = { :x=>pos[:x]+vec[:x], :y=>pos[:y]+vec[:y] }
        self.openNode(@map[pos[:y]][pos[:x]], newPos, cost)
        return true if newPos==@goal
      end
      self.closeNode(pos)
      return false unless pos=self.getNextPos()
    end
  end

  # OPENノードからコストが最小のノードを選ぶ
  def getNextPos()
    minScore = nil
    minNode = []
    for j in 0..@size[:y]-1
      for i in 0..@size[:x]-1
        if @map[j][i].is_a?(AStar) && @map[j][i].status===true then
          if !minScore || minScore>@map[j][i].score then
            minScore = @map[j][i].score
            minNode = [{ :x=>i, :y=>j }]
          elsif minScore==@map[j][i].score then
            minNode.push({ :x=>i, :y=>j })
          end
        end
      end
    end
    return minNode.length ? minNode[rand(minNode.length)] : false
  end

  # ノードを開く
  def openNode(parent, pos, cost)
    x=pos[:x]; y=pos[:y]
    return false if x<0 || y<0 || x>=@size[:x] || y>=@size[:y]
    return false if @map[y][x].is_a?(AStar) || @map[y][x]==WALL
    @map[y][x] = AStar.new(parent, cost, self.calcHeuristic(pos), pos)
    return true
  end

  # ノードを閉じる
  def closeNode(pos)
    @map[pos[:y]][pos[:x]].status = false
  end

  # ヒューリスティックコストを計算する
  def calcHeuristic(pos)
    x = pos[:x] - @goal[:x]
    y = pos[:y] - @goal[:y]
    return Math.sqrt(x*x+y*y).to_i
  end

  # スタートからゴールまでの道筋を辿る
  def getRoot()
    root=[]; node=@map[@goal[:y]][@goal[:x]]
    loop do
      return root.reverse unless node
      return false unless node.is_a?(AStar)
      root.push(node.pos)
      node = node.parent
    end
  end

  def getMap()
  	@map
  end
end

class AStar
  attr_accessor :status, :cost, :heuristic, :pos, :score, :parent

  def initialize(parent, cost, heuristic, pos)
    @status = true
    @parent=parent; @cost=cost; @heuristic=heuristic; @pos=pos
    self.calcScore()
  end

  def calcScore
    @score = @cost + @heuristic
  end
end

INT_MAX = 1000000001

H,W=gets.chomp.split(' ').map{|n| n.to_i}
S=Array.new(H){Array.new(W){0}}
0.upto(H-1){|i|
	S[i]=gets.chomp.split('').map{|n| n}
}
dp=Array.new(H){Array.new(W){INT_MAX }}

# 「.」のマス数
sum = 0
0.upto(H-1){|i|
	sum += (S[i].count{|i|i=="."})
}
# puts sum

S[0][0]=1
S[H-1][W-1]=2
map = <<EOM
#{W} #{H}
#{S.map{|a|a.join(" ")}.join("\n")}
EOM
#p map
maze = Maze.new(map)
# p maze.getMap()
maze.search()
path = maze.getRoot()
if(!path)
	puts "-1"
else
	p sum - path.size
end







Measured memory_bytes: 3964