use std::io;
use std::str::FromStr;

fn main() {
    let hw = reads(&get_line());
    let mut cells = vec![];
    for _ in 0..hw[0] {
        cells.extend(get_line().trim().chars().map(|x| Cell::from_char(&x)));
    }
    let mut f = Field {
        cells: cells,
        size: (hw[1], hw[0]),
    };
    let c = f.search();
    let ans = c.map(|cost| f.size.0 * f.size.1 - 1 - f.walls() - cost as usize);
    match ans {
        Some(n) => println!("{}", n),
        None => println!("-1"),
    }
}

#[derive(Debug)]
struct Field {
    cells: Vec<Cell>,
    size: (usize, usize),
}

impl Field {
    fn at_mut(&mut self, loc: &usize) -> &mut Cell {
        &mut self.cells[*loc]
    }
    fn search(&mut self) -> Option<u32> {
        let mut paths: Vec<usize> = vec![0];
        let mut cost = 0;
        loop {
            let mut paths_n = vec![];
            if paths.is_empty() {
                return None;
            }
            for &path in &paths {
                if self.at_mut(&path).arrive(cost).is_some() {
                    if path == self.size.0 * self.size.1 - 1 {
                        // reached the goal
                        return Some(cost);
                    }
                    paths_n.extend(&self.neighbours(path));
                }
            }
            cost += 1;
            paths = paths_n;
        }
    }

    fn report(&self) -> () {
        for (i, cell) in self.cells.iter().enumerate() {
            let cha = match *cell {
                Cell::Path { cost: Some(x) } => format!("{:>4}", x),
                Cell::Path { cost: None } => "....".to_string(),
                Cell::Wall => "####".to_string(),
            };
            print!("{}", cha);
            if (i + 1) % self.size.0 == 0 {
                print!("\n");
            }
        }
    }

    //     fn step(&mut self, paths: &[usize], cost: u32) -> Option<u32> {
    //         if paths.is_empty() {
    //             return None;
    //         }
    //         let mut path_n = vec![];
    //         None
    //     }

    fn neighbours(&self, c: usize) -> Vec<usize> {
        // need more succinct expressions
        let w = self.size.0 as i32;
        let h = self.size.1 as i32;
        let (x, y) = (c as i32 % w, c as i32 / w);
        let mut nbs = vec![];
        for &(p, q) in &[(x - 1, y), (x + 1, y), (x, y - 1), (x, y + 1)] {
            if 0 <= p && p < w && 0 <= q && q < h {
                nbs.push((p + w * q) as usize);
            }
        }
        nbs
    }

    fn walls(&self) -> usize {
        self.cells
            .iter()
            .filter(|&c| match *c {
                Cell::Wall => true,
                _ => false,
            })
            .count()
    }
}

#[derive(Debug)]
enum Cell {
    Path { cost: Option<u32> },
    Wall,
}

impl Cell {
    fn from_char(c: &char) -> Self {
        match *c {
            '.' => Cell::Path { cost: None },
            '#' => Cell::Wall,
            _ => panic!("else"),
        }
    }
    fn arrive(&mut self, cost: u32) -> Option<u32> {
        match *self {
            Cell::Path { cost: ref mut c } => {
                // TODO:understand
                match *c {
                    None => {
                        *c = Some(cost);
                        Some(cost)
                    }
                    Some(_) => None,
                }
            }
            _ => None,
        }
    }
}

fn get_line() -> String {
    let mut inp = String::new();
    io::stdin().read_line(&mut inp).expect("read error");
    inp.trim().to_string()
}

fn reads<T>(input: &str) -> Vec<T>
where
    T: FromStr,
    T::Err: std::fmt::Debug,
{
    input
        .trim()
        .split_whitespace()
        .map(|n| n.parse().unwrap())
        .collect()
}


Measured memory_bytes: 4352