use std::env;
use std::io::BufRead;

#[derive(Debug, Copy, Clone)]
enum Tile {
    Blank,
    Tree,
}

struct Pairs<I> {
    inner: I,
}

impl<I> Pairs<I> {
    fn new(inner: I) -> Self {
        Pairs { inner: inner }
    }
}

impl<I> Iterator for Pairs<I>
where
    I: Iterator,
{
    type Item = (<I as Iterator>::Item, <I as Iterator>::Item);
    fn next(&mut self) -> Option<Self::Item> {
        let a = self.inner.next()?;
        let b = self.inner.next()?;
        Some((a, b))
    }
}

fn tile(c: char) -> Tile {
    match c {
        '.' => Tile::Blank,
        '#' => Tile::Tree,
        _ => panic!("Unrecognized tile"),
    }
}

fn trees_hit(grid: &Vec<Vec<Tile>>, dx: usize, dy: usize) -> u64 {
    let mut count = 0;
    let mut x = 0;
    for row in grid.iter().step_by(dy) {
        match row[x % row.len()] {
            Tile::Blank => {}
            Tile::Tree => {
                count += 1;
            }
        };
        x += dx;
    }
    count
}

fn main() {
    let args: Vec<_> = env::args().collect();
    let grid: Vec<Vec<Tile>> = std::io::BufReader::new(std::fs::File::open(&args[1]).unwrap())
        .lines()
        .map(Result::unwrap)
        .map(|l| l.chars().map(tile).collect())
        .collect();
    let slopes: Vec<(usize, usize)> =
        Pairs::new(args[2].split(",").map(|s| s.parse::<usize>().unwrap())).collect();

    println!(
        "{}",
        slopes
            .iter()
            .map(|(dx, dy)| trees_hit(&grid, *dx, *dy))
            .product::<u64>()
    );
}