advent-of-code/2020/src/bin/day03.rs

143 lines
3.6 KiB
Rust
Raw Normal View History

2020-12-03 10:24:03 +01:00
#![feature(iter_map_while)]
2020-12-03 08:54:04 +01:00
#![feature(test)]
extern crate test;
use itertools::Itertools;
2020-12-08 11:32:59 +01:00
use std::{env, iter};
2020-12-03 08:54:04 +01:00
2020-12-03 10:24:03 +01:00
#[derive(Debug, PartialEq, Copy, Clone)]
2020-12-03 08:54:04 +01:00
enum Tile {
Free,
Tree,
}
type Forest = Vec<Vec<Tile>>;
const STEP_RIGHT: [usize; 5] = [1, 3, 5, 7, 1];
const STEP_DOWN: [usize; 5] = [1, 1, 1, 1, 2];
2020-12-04 18:36:43 +01:00
const TREE: u8 = b'#';
const FREE: u8 = b'.';
2020-12-03 08:54:04 +01:00
2020-12-04 14:23:48 +01:00
impl From<u8> for Tile {
#[inline]
2020-12-04 14:23:48 +01:00
fn from(b: u8) -> Self {
match b {
FREE => Tile::Free,
TREE => Tile::Tree,
2020-12-03 08:54:04 +01:00
_ => unreachable!(),
}
}
}
fn read_input() -> String {
2020-12-10 12:44:07 +01:00
std::fs::read_to_string(
env::args()
.nth(1)
.filter(|n| n != "--bench")
.unwrap_or_else(|| String::from("inputs/day03")),
)
.unwrap()
2020-12-03 08:54:04 +01:00
}
fn parse_input(raw: &str) -> Forest {
2020-12-04 14:23:48 +01:00
raw.lines().map(|l| l.bytes().map_into().collect()).collect()
2020-12-03 08:54:04 +01:00
}
fn count_all_paths(forest: &Forest) -> usize {
2020-12-03 10:24:03 +01:00
STEP_RIGHT
.iter()
.zip(STEP_DOWN.iter())
2020-12-03 08:54:04 +01:00
.map(|(&r, &d)| count_trees(forest, r, d))
.product()
}
fn count_trees(forest: &Forest, step_right: usize, step_down: usize) -> usize {
2020-12-04 11:08:06 +01:00
iter::successors(Some((0, 0)), |(y, x)| {
Some((
y + step_down,
Some(x + step_right)
.filter(|&it| it < forest[0].len())
2020-12-08 11:32:59 +01:00
.unwrap_or_else(|| (x + step_right) - forest[0].len()),
2020-12-04 11:08:06 +01:00
))
})
.map_while(|(y, x)| forest.get(y).map(|r| r[x]))
.filter(|&t| t == Tile::Tree)
.count()
2020-12-03 08:54:04 +01:00
}
fn main() {
let forest = parse_input(&read_input());
let p1 = count_trees(&forest, STEP_RIGHT[1], STEP_DOWN[1]);
println!("Part 1: {}", p1);
let p2 = count_all_paths(&forest);
println!("Part 2: {}", p2);
}
2020-12-03 11:32:32 +01:00
#[allow(unused)]
2020-12-03 08:54:04 +01:00
mod tests {
use super::*;
2020-12-10 14:01:25 +01:00
use aoc2020::*;
use paste::paste;
2020-12-03 11:32:32 +01:00
use test::{self, black_box};
2020-12-03 08:54:04 +01:00
2020-12-10 14:01:25 +01:00
const TEST_INPUT: &str = "..##.......
2020-12-03 08:54:04 +01:00
#...#...#..
.#....#..#.
..#.#...#.#
.#...##..#.
..#.##.....
.#.#.#....#
.#........#
#.##...#...
#...##....#
.#..#...#.#";
2020-12-03 11:32:32 +01:00
fn count_trees_imperative(forest: &Forest, step_right: usize, step_down: usize) -> usize {
let mut x = 0;
let mut y = 0;
let mut trees = 0;
let width = forest[0].len();
while y < forest.len() {
trees += (forest[y][x] == Tile::Tree) as usize;
y += step_down;
2020-12-04 14:23:48 +01:00
x += step_right;
// branch-free version of if x >= width { x -= width }
x -= width * ((x >= width) as usize);
2020-12-03 11:32:32 +01:00
}
2020-12-04 18:36:43 +01:00
trees
2020-12-03 11:32:32 +01:00
}
2020-12-10 14:01:25 +01:00
test!(count_all_paths == 336);
bench!(count_all_paths == 4723283400);
bench_input!(len == 323);
2020-12-03 08:54:04 +01:00
#[test]
2020-12-03 11:32:32 +01:00
fn part1_test_functional() {
2020-12-10 14:01:25 +01:00
let forest = parse_input(TEST_INPUT);
2020-12-03 10:24:03 +01:00
assert_eq!(count_trees(&forest, STEP_RIGHT[1], STEP_DOWN[1]), 7);
2020-12-03 08:54:04 +01:00
}
2020-12-03 11:32:32 +01:00
#[test]
fn part1_test_imperative() {
2020-12-10 14:01:25 +01:00
let forest = parse_input(TEST_INPUT);
2020-12-03 11:32:32 +01:00
assert_eq!(count_trees_imperative(&forest, STEP_RIGHT[1], STEP_DOWN[1]), 7);
}
#[bench]
fn bench_part_1_functional(b: &mut test::Bencher) {
let forest = parse_input(&read_input());
2020-12-03 11:47:19 +01:00
b.iter(|| assert_eq!(count_trees(black_box(&forest), STEP_RIGHT[1], STEP_DOWN[1]), 187));
2020-12-03 11:32:32 +01:00
}
#[bench]
fn bench_part_1_imperative(b: &mut test::Bencher) {
let forest = parse_input(&read_input());
2020-12-03 11:47:19 +01:00
b.iter(|| assert_eq!(count_trees_imperative(black_box(&forest), STEP_RIGHT[1], STEP_DOWN[1]), 187));
2020-12-03 11:32:32 +01:00
}
#[bench]
fn bench_part_2(b: &mut test::Bencher) {
let forest = parse_input(&read_input());
2020-12-03 11:47:19 +01:00
b.iter(|| assert_eq!(count_all_paths(black_box(&forest)), 4723283400));
2020-12-03 11:32:32 +01:00
}
2020-12-03 08:54:04 +01:00
}