92 lines
2.2 KiB
Rust
92 lines
2.2 KiB
Rust
use std::fs;
|
|
|
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
let input = fs::read_to_string("input")?;
|
|
let slope = parse_slope(&input)?;
|
|
|
|
// Part 1
|
|
let encounters = count_encounters(&slope, (1, 3));
|
|
println!("{}", encounters);
|
|
|
|
// Part 2
|
|
let encounters: usize = [(1, 1), (1, 3), (1, 5), (1, 7), (2, 1)]
|
|
.iter()
|
|
.map(|angle| count_encounters(&slope, *angle))
|
|
.product();
|
|
println!("{}", encounters);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn parse_slope(input: &str) -> Result<Vec<Vec<usize>>, String> {
|
|
input
|
|
.lines()
|
|
.map(|line| {
|
|
line.chars()
|
|
.map(|c| match c {
|
|
'.' => Ok(0),
|
|
'#' => Ok(1),
|
|
other => Err(format!("Invalid slope; contains character: {}", other)),
|
|
})
|
|
.collect()
|
|
})
|
|
.collect()
|
|
}
|
|
|
|
fn count_encounters(input: &Vec<Vec<usize>>, angle: (usize, usize)) -> usize {
|
|
input
|
|
.iter()
|
|
.enumerate()
|
|
.step_by(angle.0)
|
|
.map(|(i, row)| row[(i * angle.1 / angle.0) % row.len()])
|
|
.sum()
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use indoc::indoc;
|
|
|
|
#[test]
|
|
fn test_simple() -> Result<(), Box<dyn std::error::Error>> {
|
|
let example = indoc!(
|
|
"..##.......
|
|
#...#...#..
|
|
.#....#..#.
|
|
..#.#...#.#
|
|
.#...##..#.
|
|
..#.##.....
|
|
.#.#.#....#
|
|
.#........#
|
|
#.##...#...
|
|
#...##....#
|
|
.#..#...#.#"
|
|
);
|
|
|
|
let parsed = parse_slope(example)?;
|
|
assert_eq!(count_encounters(&parsed, (1, 3)), 7);
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn test_simple2() -> Result<(), Box<dyn std::error::Error>> {
|
|
let example = indoc!(
|
|
"..##.......
|
|
#...#...#..
|
|
.#....#..#.
|
|
..#.#...#.#
|
|
.#...##..#.
|
|
..#.##.....
|
|
.#.#.#....#
|
|
.#........#
|
|
#.##...#...
|
|
#...##....#
|
|
.#..#...#.#"
|
|
);
|
|
|
|
let parsed = parse_slope(example)?;
|
|
assert_eq!(count_encounters(&parsed, (2, 1)), 2);
|
|
Ok(())
|
|
}
|
|
}
|