1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
|
use anyhow::Context as _;
struct Map {
grid: Vec<Vec<bool>>,
}
impl Map {
fn parse(s: &[u8]) -> anyhow::Result<Self> {
let mut grid = vec![];
let mut current_row = vec![];
for c in s {
match c {
b'#' => {
current_row.push(true);
}
b'.' => {
current_row.push(false);
}
b'\n' => {
grid.push(current_row);
current_row = vec![];
}
_ => {
return Err(anyhow::anyhow!("invalid map char: '{}'", c));
}
}
}
if !current_row.is_empty() {
grid.push(current_row);
}
Ok(Self { grid })
}
fn rows(&self) -> usize {
self.grid.len()
}
fn tree_at(&self, x: usize, y: usize) -> anyhow::Result<bool> {
// unwrap safe because cycle().nth() can never fail
Ok(*self
.grid
.get(y)
.context("row too large")?
.iter()
.cycle()
.nth(x)
.unwrap())
}
fn trees_for_slope(
&self,
x_incr: usize,
y_incr: usize,
) -> anyhow::Result<usize> {
let mut trees = 0;
for r in 0..self.rows() / y_incr {
let x = r * x_incr;
let y = r * y_incr;
if self.tree_at(x, y)? {
trees += 1;
}
}
Ok(trees)
}
}
pub fn part1() -> anyhow::Result<()> {
let map = read_map()?;
println!("{}", map.trees_for_slope(3, 1)?);
Ok(())
}
pub fn part2() -> anyhow::Result<()> {
let map = read_map()?;
println!(
"{}",
map.trees_for_slope(1, 1)?
* map.trees_for_slope(3, 1)?
* map.trees_for_slope(5, 1)?
* map.trees_for_slope(7, 1)?
* map.trees_for_slope(1, 2)?
);
Ok(())
}
fn read_map() -> anyhow::Result<Map> {
let map_str = crate::util::read_file("data/3.txt")?;
Map::parse(&map_str)
}
|