use std::io::BufRead;

pub struct StdinReader<R: BufRead> {
    pub buf_reader: R,
    pub buf: String,
}
impl<R: BufRead> StdinReader<R> {
    pub fn new(r: R) -> Self {
        StdinReader {
            buf_reader: r,
            buf: String::with_capacity(10000),
        }
    }
}

#[macro_export]
macro_rules! input {
    ($reader : expr, $t : ty) => { // one variable
        match &mut $reader {
            reader => {
                use std::io::BufRead;
                reader.buf_reader.read_line(&mut reader.buf).unwrap();
                let tmp_var: $t = reader.buf.trim().parse().unwrap(); 
                reader.buf.clear();
                tmp_var
            },
        }
    };
    ($reader : expr, $t0 : ty, $t1 : ty) => { // 2 tuple
        match &mut $reader {
            reader => {
                use std::io::BufRead;
                reader.buf_reader.read_line(&mut reader.buf).unwrap();
                let tmp_var: Vec<$t0> = reader.buf.trim().split_whitespace().map(|a| a.parse().unwrap()).collect();
                reader.buf.clear();
                (tmp_var[0], tmp_var[1])
            }
        }
    };
    ($reader : expr, $t0 : ty, $t1 : ty, $t2 : ty) => { // 3 tuple
        match &mut $reader {
            reader => {
                use std::io::BufRead;
                reader.buf_reader.read_line(&mut reader.buf).unwrap();
                let tmp_var: Vec<$t0> = reader.buf.trim().split_whitespace().map(|a| a.parse().unwrap()).collect();
                reader.buf.clear();
                (tmp_var[0], tmp_var[1], tmp_var[2])
            }
        }
    };
    ($reader : expr, $t : ty, $size : expr) => { // Vector
        match &mut $reader {
            reader => {
                use std::io::BufRead;
                reader.buf_reader.read_line(&mut reader.buf).unwrap();
                let tmp_var: $t = reader.buf.trim().split_whitespace().map(|a| a.parse().unwrap()).collect();
                reader.buf.clear();
                tmp_var
            }
        }
    };
}
#[derive(Debug, Clone, Copy)]
struct Point {
    x: usize,
    y: usize,
    distance: usize,
}
impl Eq for Point {}
impl PartialEq for Point {
    fn eq(&self, other: &Self) -> bool {
        if self.x == other.x && self.y == other.y { true }
        else { false }
    }
}
impl Point {
    fn new(x: usize, y: usize, distance: usize) -> Point {
        Point { x: x, y: y, distance: distance }
    }
}
fn main() {
    let handle = std::io::stdin();
    let mut r = StdinReader::new(handle.lock());
    let (h, w) = input!(r, usize, usize);
    let mut map: Vec<Vec<char>> = Vec::with_capacity(h);
    let mut white_panel = 0;
    for _ in 0..h {
        let line: String = input!(r, String);
        white_panel += line.chars().filter(|a| *a == '.').count();
        map.push(line.chars().collect());
    }
    let mut have_been_map: Vec<Vec<bool>> = vec![vec![false; w]; h];
    use std::collections::VecDeque;
    let mut queue: VecDeque<Point> = VecDeque::with_capacity(h * w);

    queue.push_back(Point { x: 0, y: 0, distance: 0 });
    have_been_map[0][0] = true;
    let mut can_reach = false;
    let mut distance = std::usize::MAX;
    while queue.len() != 0 {
        let now = queue.pop_front().unwrap();
        if now.x+1 == h && now.y+1 == w {
            can_reach = true;
            distance = now.distance;
            break;
        }
        if now.x != 0 && map[now.x-1][now.y] != '#' && (!have_been_map[now.x-1][now.y]) {
            have_been_map[now.x-1][now.y] = true;
            queue.push_back(Point { x: now.x-1, y: now.y, distance: now.distance+1 });
        }
        if now.y != 0 && map[now.x][now.y-1] != '#' && (!have_been_map[now.x][now.y-1]) {
            have_been_map[now.x][now.y-1] = true;
            queue.push_back(Point { x: now.x, y: now.y-1, distance: now.distance+1 });
        }
        if now.x+1 != h && map[now.x+1][now.y] != '#' && (!have_been_map[now.x+1][now.y]) {
            have_been_map[now.x+1][now.y] = true;
            queue.push_back(Point { x: now.x+1, y: now.y, distance: now.distance+1 });
        }
        if now.y+1 != w && map[now.x][now.y+1] != '#' && (!have_been_map[now.x][now.y+1]) {
            have_been_map[now.x][now.y+1] = true;
            queue.push_back(Point { x: now.x, y: now.y+1, distance: now.distance+1 });
        }
    }
    if can_reach {
        println!("{}", white_panel - distance -1);
    } else {
        println!("{}", -1);
    }
}


Measured memory_bytes: 4352