#!/usr/bin/env run-cargo-script

#![allow(unused_imports)]

use std::cmp;
use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, VecDeque};
use std::fmt;
use std::io::{self, BufWriter, Read, StdinLock, Write};
use std::ops::{Add, Div, Mul, Sub};
use std::str::{self, FromStr};

fn solve(m: Vec<Vec<bool>>) -> Option<usize> {
    let (w, h) = (m[0].len(), m.len());
    let n = m.iter()
        .map(|l| l.iter().filter(|e| !**e).count())
        .sum::<usize>();
    let mut d = (0..h)
        .map(|_| (0..w).map(|_| None).collect::<Vec<_>>())
        .collect::<Vec<_>>();
    let mut ps = vec![(0, 0)];
    d[0][0] = Some(0);
    while !ps.is_empty() {
        let mut nps = vec![];
        for (x, y) in ps.into_iter() {
            let c = d[y][x].unwrap_or_else(|| unreachable!());
            if x == w - 2 && y == h - 1 || x == w - 1 && y == h - 2 {
                return Some(n - c - 2);
            }
            if x < w - 1 && should_go(c, x + 1, y, &m, &d) {
                d[y][x + 1] = Some(c + 1);
                if !nps.contains(&(x + 1, y)) {
                    nps.push((x + 1, y));
                }
            }
            if 0 < x && should_go(c, x - 1, y, &m, &d) {
                d[y][x - 1] = Some(c + 1);
                if !nps.contains(&(x - 1, y)) {
                    nps.push((x - 1, y));
                }
            }
            if y < h - 1 && should_go(c, x, y + 1, &m, &d) {
                d[y + 1][x] = Some(c + 1);
                if !nps.contains(&(x, y + 1)) {
                    nps.push((x, y + 1));
                }
            }
            if 0 < y && should_go(c, x, y - 1, &m, &d) {
                d[y - 1][x] = Some(c + 1);
                if !nps.contains(&(x, y - 1)) {
                    nps.push((x, y - 1));
                }
            }
        }
        ps = nps;
    }
    None
}

fn should_go(
    c: usize,
    x: usize,
    y: usize,
    m: &Vec<Vec<bool>>,
    d: &Vec<Vec<Option<usize>>>,
) -> bool {
    match d[y][x] {
        Some(n) => c < n + 1 && !m[y][x],
        None => !m[y][x],
    }
}

fn main() {
    let stdin = io::stdin();
    let mut sc = Scanner::new(stdin.lock().bytes());
    let (h, _) = (sc.next(), sc.next::<usize>());
    match solve(sc.strings_as_mat(h, |c| c == b'#')) {
        Some(x) => println!("{}", x),
        None => println!("-1"),
    }
}

struct Scanner<R: Read> {
    buf: Vec<u8>,
    bytes: io::Bytes<R>,
}

#[allow(dead_code)]
impl<R: Read> Scanner<R> {
    fn new(bytes: io::Bytes<R>) -> Self {
        Scanner {
            buf: Vec::with_capacity(1024),
            bytes: bytes,
        }
    }

    fn next<T: FromStr>(&mut self) -> T
    where
        <T as FromStr>::Err: fmt::Debug,
    {
        let buf = &mut self.buf;
        buf.clear();
        self.bytes
            .by_ref()
            .map(Result::unwrap)
            .skip_while(|&c| c == ' ' as u8 || c == '\n' as u8)
            .take_while(|&c| !(c == ' ' as u8 || c == '\n' as u8))
            .foreach(|c| buf.push(c));
        str::from_utf8(&buf).unwrap().parse().unwrap()
    }

    fn vec<T: FromStr>(&mut self, n: usize) -> Vec<T>
    where
        <T as FromStr>::Err: fmt::Debug,
    {
        (0..n).map(|_| self.next()).collect()
    }

    fn pairs<T1: FromStr, T2: FromStr>(&mut self, n: usize) -> Vec<(T1, T2)>
    where
        <T1 as FromStr>::Err: fmt::Debug,
        <T2 as FromStr>::Err: fmt::Debug,
    {
        (0..n).map(|_| (self.next(), self.next())).collect()
    }

    fn trios<T1: FromStr, T2: FromStr, T3: FromStr>(&mut self, n: usize) -> Vec<(T1, T2, T3)>
    where
        <T1 as FromStr>::Err: fmt::Debug,
        <T2 as FromStr>::Err: fmt::Debug,
        <T3 as FromStr>::Err: fmt::Debug,
    {
        (0..n)
            .map(|_| (self.next(), self.next(), self.next()))
            .collect()
    }

    fn mat<T: FromStr>(&mut self, m: usize, n: usize) -> Vec<Vec<T>>
    where
        <T as FromStr>::Err: fmt::Debug,
    {
        (0..m).map(|_| self.vec(n)).collect()
    }

    fn strings_as_mat<T, F: FnMut(u8) -> T>(&mut self, h: usize, mut f: F) -> Vec<Vec<T>> {
        (0..h)
            .map(|_| {
                self.bytes
                    .by_ref()
                    .map(Result::unwrap)
                    .skip_while(|&c| c == ' ' as u8 || c == '\n' as u8)
                    .take_while(|&c| !(c == ' ' as u8 || c == '\n' as u8))
                    .map(&mut f)
                    .collect()
            })
            .collect()
    }
}

trait Foreach {
    type Item;
    fn foreach<F: FnMut(Self::Item)>(self, f: F);
}

impl<T, I: Iterator<Item = T>> Foreach for I {
    type Item = T;

    fn foreach<F: FnMut(T)>(self, mut f: F) {
        self.fold((), move |(), x| f(x));
    }
}


Measured memory_bytes: 4352