diff --git a/Cargo.lock b/Cargo.lock index 4f44b51..b307929 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -190,6 +190,13 @@ dependencies = [ "criterion", ] +[[package]] +name = "day03" +version = "0.1.0" +dependencies = [ + "criterion", +] + [[package]] name = "either" version = "1.8.0" diff --git a/Cargo.toml b/Cargo.toml index d52cdc3..b5a41d5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,4 +2,5 @@ members = [ "day01", "day02", + "day03", ] diff --git a/day03/Cargo.toml b/day03/Cargo.toml new file mode 100644 index 0000000..442e67a --- /dev/null +++ b/day03/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "day03" +version = "0.1.0" +edition = "2021" + +[dev-dependencies] +criterion = "0.4.0" + +[[bench]] +name = "day03" +harness = false \ No newline at end of file diff --git a/day03/benches/day03.rs b/day03/benches/day03.rs new file mode 100644 index 0000000..3b48208 --- /dev/null +++ b/day03/benches/day03.rs @@ -0,0 +1,27 @@ +use criterion::{black_box, criterion_group, criterion_main, Criterion}; +use ::day03::{parse_input_part1, parse_input_part2, count_valid}; + +pub fn criterion_benchmark(c: &mut Criterion) { + let input = include_str!("../../input/day03.txt"); + c.bench_function("day03 parse_input_part1", |b| { + b.iter(|| parse_input_part1(black_box(input))) + }); + c.bench_function("day03 parse_input_part2", |b| { + b.iter(|| parse_input_part2(black_box(input))) + }); + let input_part1 = parse_input_part1(input); + c.bench_function("day03 solve_part1", |b| { + b.iter(|| count_valid(black_box(&input_part1))) + }); + let input_part2 = parse_input_part2(input); + c.bench_function("day03 solve_part2", |b| { + b.iter(|| count_valid(black_box(&input_part2))) + }); +} + +criterion_group!{ + name = benches; + config = Criterion::default().sample_size(1000); + targets = criterion_benchmark +} +criterion_main!(benches); diff --git a/day03/src/lib.rs b/day03/src/lib.rs new file mode 100644 index 0000000..8d51629 --- /dev/null +++ b/day03/src/lib.rs @@ -0,0 +1,63 @@ +pub struct Triangle { + a: u16, + b: u16, + c: u16, +} + +impl Triangle { + fn new(a: u16, b: u16, c: u16) -> Self { + Triangle { a, b, c } + } + fn is_valid(&self) -> bool { + (self.a + self.b > self.c) && (self.a + self.c > self.b) && (self.b + self.c > self.a) + } +} + +pub fn parse_input_part1(input: &str) -> Vec { + input + .lines() + .map(|line| { + let sides = std::str::from_utf8(line.as_bytes()) + .unwrap() + .split_whitespace() + .filter_map(|s| s.parse().ok()) + .collect::>(); + match sides.as_slice() { + [a, b, c] => Triangle::new(*a, *b, *c), + _ => panic!("Parse error"), + } + }) + .collect() +} + +pub fn parse_input_part2(input: &str) -> Vec { + let mut sides = [[0u16; 3]; 3]; + input + .lines() + .enumerate() + .flat_map(|(i, line)| { + let numbers: Vec = line + .split_whitespace() + .map(|n| n.parse().unwrap()) + .collect(); + + numbers.iter().enumerate().for_each(|(j, number)| { + sides[i % 3][j] = *number; + }); + + if i % 3 == 2 { + let triangles: Vec = (0..3) + .map(|j| Triangle::new(sides[0][j], sides[1][j], sides[2][j])) + .collect(); + + return triangles.into_iter(); + } + + Vec::new().into_iter() + }) + .collect() +} + +pub fn count_valid(triangles: &[Triangle]) -> u16 { + triangles.iter().filter(|t| t.is_valid()).count() as u16 +} diff --git a/day03/src/main.rs b/day03/src/main.rs new file mode 100644 index 0000000..897fd35 --- /dev/null +++ b/day03/src/main.rs @@ -0,0 +1,34 @@ +use ::day03::{parse_input_part1, parse_input_part2, count_valid}; + +fn main() { + let input = include_str!("../../input/day03.txt"); + let part1_input = parse_input_part1(input); + let part1 = count_valid(&part1_input); + println!("Part1: {}", part1); + let part2_input = parse_input_part2(input); + let part2 = count_valid(&part2_input); + println!("Part2: {}", part2); +} + +#[cfg(test)] +mod day03 { + use ::day03::{parse_input_part1, parse_input_part2, count_valid}; + + const INPUT1: &str = "5 10 25"; + const INPUT2: &str = r#"101 301 501 +102 302 502 +103 303 503 +201 401 601 +202 402 602 +203 403 603"#; + + #[test] + fn part1_test() { + assert_eq!(count_valid(&parse_input_part1(INPUT1)), 0); + } + + #[test] + fn part2_test() { + assert_eq!(count_valid(&parse_input_part2(INPUT2)), 6); + } +}