Add trait and macro to automamte some day setup
This commit is contained in:
Родитель
e311b0cbdf
Коммит
44021d0b1e
|
@ -5,6 +5,9 @@ version = 3
|
|||
[[package]]
|
||||
name = "aoc-lib"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"paste",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
|
@ -314,6 +317,12 @@ version = "11.1.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0744126afe1a6dd7f394cb50a716dbe086cb06e255e53d8d0185d82828358fb5"
|
||||
|
||||
[[package]]
|
||||
name = "plotters"
|
||||
version = "0.3.1"
|
||||
|
|
|
@ -6,3 +6,4 @@ edition = "2021"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
paste = "1.0.6"
|
||||
|
|
|
@ -1,3 +1,63 @@
|
|||
pub use paste::paste;
|
||||
use std::fmt::Display;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! aoc_setup {
|
||||
($type:ident $(, test $index:literal: $test_result:expr)*) => {
|
||||
// TODO: pub use another macro that creates benchmarks?
|
||||
|
||||
fn main() {
|
||||
aoc_lib::run($type);
|
||||
}
|
||||
|
||||
$(
|
||||
aoc_lib::paste! {
|
||||
#[test]
|
||||
fn [<solve_sample_part_ $index>]() {
|
||||
let input = include_str!("../sample.txt");
|
||||
let parsed = $type::parse_input(input);
|
||||
assert_eq!($test_result, $type::[< solve_ $index >](&parsed));
|
||||
}
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
pub trait AdventOfCode {
|
||||
type Input;
|
||||
type Output;
|
||||
|
||||
fn parse_input(s: &str) -> Self::Input;
|
||||
fn solve_1(input: &Self::Input) -> Self::Output;
|
||||
fn solve_2(input: &Self::Input) -> Self::Output;
|
||||
}
|
||||
|
||||
/// Run and time just part 1 of a. AdventOfCode solution.
|
||||
pub fn run_part_1<T: AdventOfCode<Output = impl Display>>(_: T) {
|
||||
let input = read_stdin();
|
||||
let (parsed, parsed_time) = time(|| T::parse_input(&input));
|
||||
let (solve_1, solve_1_time) = time(|| T::solve_1(&parsed));
|
||||
|
||||
println!("Solution to part 1: {}", solve_1);
|
||||
|
||||
println!("Parsing took: {:?}", parsed_time);
|
||||
println!("Solving part 1 took: {:?}", solve_1_time);
|
||||
}
|
||||
|
||||
pub fn run<T: AdventOfCode<Output = impl Display>>(_: T) {
|
||||
let input = read_stdin();
|
||||
let (parsed, parsed_time) = time(|| T::parse_input(&input));
|
||||
let (solve_1, solve_1_time) = time(|| T::solve_1(&parsed));
|
||||
let (solve_2, solve_2_time) = time(|| T::solve_2(&parsed));
|
||||
|
||||
println!("Solution to part 1: {}", solve_1);
|
||||
println!("Solution to part 2: {}", solve_2);
|
||||
|
||||
println!("Parsing took: {:?}", parsed_time);
|
||||
println!("Solving part 1 took: {:?}", solve_1_time);
|
||||
println!("Solving part 2 took: {:?}", solve_2_time);
|
||||
}
|
||||
|
||||
/// Executes some code and records the time it took to run
|
||||
pub fn time<T, F>(fun: F) -> (T, std::time::Duration)
|
||||
where
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
use aoc_lib::AdventOfCode;
|
||||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||
|
||||
#[path = "../src/main.rs"]
|
||||
|
@ -8,32 +9,32 @@ mod main;
|
|||
fn bench_main(c: &mut Criterion) {
|
||||
c.bench_function("parse input", |b| {
|
||||
let input = include_str!("../input.txt");
|
||||
b.iter(|| main::parse_input(black_box(input)))
|
||||
b.iter(|| main::Day1::parse_input(black_box(input)))
|
||||
});
|
||||
|
||||
c.bench_function("solve 1", |b| {
|
||||
let input = main::parse_input(include_str!("../input.txt"));
|
||||
b.iter(|| main::solve_1(black_box(&input)))
|
||||
let input = main::Day1::parse_input(include_str!("../input.txt"));
|
||||
b.iter(|| main::Day1::solve_1(black_box(&input)))
|
||||
});
|
||||
|
||||
c.bench_function("solve 2", |b| {
|
||||
let input = main::parse_input(include_str!("../input.txt"));
|
||||
b.iter(|| main::solve_2(black_box(&input)))
|
||||
let input = main::Day1::parse_input(include_str!("../input.txt"));
|
||||
b.iter(|| main::Day1::solve_2(black_box(&input)))
|
||||
});
|
||||
|
||||
c.bench_function("parse sample input", |b| {
|
||||
let input = include_str!("../sample.txt");
|
||||
b.iter(|| main::parse_input(black_box(input)))
|
||||
b.iter(|| main::Day1::parse_input(black_box(input)))
|
||||
});
|
||||
|
||||
c.bench_function("solve 1 (sample input)", |b| {
|
||||
let input = main::parse_input(include_str!("../sample.txt"));
|
||||
b.iter(|| main::solve_1(black_box(&input)))
|
||||
let input = main::Day1::parse_input(include_str!("../sample.txt"));
|
||||
b.iter(|| main::Day1::solve_1(black_box(&input)))
|
||||
});
|
||||
|
||||
c.bench_function("solve 2 (sample input)", |b| {
|
||||
let input = main::parse_input(include_str!("../sample.txt"));
|
||||
b.iter(|| main::solve_2(black_box(&input)))
|
||||
let input = main::Day1::parse_input(include_str!("../sample.txt"));
|
||||
b.iter(|| main::Day1::solve_2(black_box(&input)))
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -1,41 +1,22 @@
|
|||
use aoc_lib::*;
|
||||
|
||||
fn main() {
|
||||
let input = read_stdin();
|
||||
let (parsed, parsed_time) = time(|| parse_input(&input));
|
||||
let (solve_1, solve_1_time) = time(|| solve_1(&parsed));
|
||||
let (solve_2, solve_2_time) = time(|| solve_2(&parsed));
|
||||
aoc_setup!(Day1, test 1: 7, test 2: 5);
|
||||
|
||||
println!("Solution to part 1: {}", solve_1);
|
||||
println!("Solution to part 2: {}", solve_2);
|
||||
pub struct Day1;
|
||||
|
||||
println!("Parsing took: {:?}", parsed_time);
|
||||
println!("Solving part 1 took: {:?}", solve_1_time);
|
||||
println!("Solving part 2 took: {:?}", solve_2_time);
|
||||
}
|
||||
|
||||
pub fn parse_input(s: &str) -> Vec<usize> {
|
||||
s.lines().map(|l| l.parse().unwrap()).collect()
|
||||
}
|
||||
|
||||
pub fn solve_1(input: &[usize]) -> usize {
|
||||
input.windows(2).filter(|w| w[0] < w[1]).count()
|
||||
}
|
||||
|
||||
pub fn solve_2(input: &[usize]) -> usize {
|
||||
input.windows(4).filter(|w| w[0] < w[3]).count()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_solve_1() {
|
||||
let input = include_str!("../sample.txt");
|
||||
let parsed = parse_input(input);
|
||||
assert_eq!(7, solve_1(&parsed));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_solve_2() {
|
||||
let input = include_str!("../sample.txt");
|
||||
let parsed = parse_input(input);
|
||||
assert_eq!(5, solve_2(&parsed));
|
||||
impl AdventOfCode for Day1 {
|
||||
type Input = Vec<usize>;
|
||||
type Output = usize;
|
||||
|
||||
fn parse_input(s: &str) -> Self::Input {
|
||||
s.lines().map(|l| l.parse().unwrap()).collect()
|
||||
}
|
||||
|
||||
fn solve_1(input: &Self::Input) -> Self::Output {
|
||||
input.windows(2).filter(|w| w[0] < w[1]).count()
|
||||
}
|
||||
|
||||
fn solve_2(input: &Self::Input) -> Self::Output {
|
||||
input.windows(4).filter(|w| w[0] < w[3]).count()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
use aoc_lib::*;
|
||||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||
|
||||
#[path = "../src/main.rs"]
|
||||
|
@ -8,32 +9,32 @@ mod main;
|
|||
fn bench_main(c: &mut Criterion) {
|
||||
c.bench_function("parse input", |b| {
|
||||
let input = include_str!("../input.txt");
|
||||
b.iter(|| main::parse_input(black_box(input)))
|
||||
b.iter(|| main::Day2::parse_input(black_box(input)))
|
||||
});
|
||||
|
||||
c.bench_function("solve 1", |b| {
|
||||
let input = main::parse_input(include_str!("../input.txt"));
|
||||
b.iter(|| main::solve_1(black_box(&input)))
|
||||
let input = main::Day2::parse_input(include_str!("../input.txt"));
|
||||
b.iter(|| main::Day2::solve_1(black_box(&input)))
|
||||
});
|
||||
|
||||
c.bench_function("solve 2", |b| {
|
||||
let input = main::parse_input(include_str!("../input.txt"));
|
||||
b.iter(|| main::solve_2(black_box(&input)))
|
||||
let input = main::Day2::parse_input(include_str!("../input.txt"));
|
||||
b.iter(|| main::Day2::solve_2(black_box(&input)))
|
||||
});
|
||||
|
||||
c.bench_function("parse sample input", |b| {
|
||||
let input = include_str!("../sample.txt");
|
||||
b.iter(|| main::parse_input(black_box(input)))
|
||||
b.iter(|| main::Day2::parse_input(black_box(input)))
|
||||
});
|
||||
|
||||
c.bench_function("solve 1 (sample input)", |b| {
|
||||
let input = main::parse_input(include_str!("../sample.txt"));
|
||||
b.iter(|| main::solve_1(black_box(&input)))
|
||||
let input = main::Day2::parse_input(include_str!("../sample.txt"));
|
||||
b.iter(|| main::Day2::solve_1(black_box(&input)))
|
||||
});
|
||||
|
||||
c.bench_function("solve 2 (sample input)", |b| {
|
||||
let input = main::parse_input(include_str!("../sample.txt"));
|
||||
b.iter(|| main::solve_2(black_box(&input)))
|
||||
let input = main::Day2::parse_input(include_str!("../sample.txt"));
|
||||
b.iter(|| main::Day2::solve_2(black_box(&input)))
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
use aoc_lib::*;
|
||||
|
||||
aoc_setup!(Day2, test 1: 150, test 2: 900);
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum Direction {
|
||||
Forward,
|
||||
|
@ -7,69 +9,48 @@ pub enum Direction {
|
|||
Up,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let input = read_stdin();
|
||||
let (parsed, parsed_time) = time(|| parse_input(&input));
|
||||
let (solve_1, solve_1_time) = time(|| solve_1(&parsed));
|
||||
let (solve_2, solve_2_time) = time(|| solve_2(&parsed));
|
||||
pub struct Day2;
|
||||
|
||||
println!("Solution to part 1: {}", solve_1);
|
||||
println!("Solution to part 2: {}", solve_2);
|
||||
impl AdventOfCode for Day2 {
|
||||
type Input = Vec<(Direction, isize)>;
|
||||
type Output = isize;
|
||||
|
||||
println!("Parsing took: {:?}", parsed_time);
|
||||
println!("Solving part 1 took: {:?}", solve_1_time);
|
||||
println!("Solving part 2 took: {:?}", solve_2_time);
|
||||
}
|
||||
|
||||
pub fn parse_input(s: &str) -> Vec<(Direction, isize)> {
|
||||
s.lines()
|
||||
.map(|line| {
|
||||
let mut split = line.split(' ');
|
||||
(
|
||||
match split.next().unwrap() {
|
||||
"forward" => Direction::Forward,
|
||||
"down" => Direction::Down,
|
||||
"up" => Direction::Up,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
split.next().unwrap().parse().unwrap(),
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn solve_1(input: &[(Direction, isize)]) -> isize {
|
||||
let sub = input
|
||||
.into_iter()
|
||||
.fold((0, 0), |sub, &(dir, dist)| match dir {
|
||||
Direction::Forward => (sub.0 + dist, sub.1),
|
||||
Direction::Down => (sub.0, sub.1 + dist),
|
||||
Direction::Up => (sub.0, sub.1 - dist),
|
||||
});
|
||||
sub.0 * sub.1
|
||||
}
|
||||
|
||||
pub fn solve_2(input: &[(Direction, isize)]) -> isize {
|
||||
let sub = input
|
||||
.into_iter()
|
||||
.fold((0, 0, 0), |sub, &(dir, dist)| match dir {
|
||||
Direction::Forward => (sub.0 + dist, sub.1 + sub.2 * dist, sub.2),
|
||||
Direction::Down => (sub.0, sub.1, sub.2 + dist),
|
||||
Direction::Up => (sub.0, sub.1, sub.2 - dist),
|
||||
});
|
||||
sub.0 * sub.1
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_solve_1() {
|
||||
let input = include_str!("../sample.txt");
|
||||
let parsed = parse_input(input);
|
||||
assert_eq!(150, solve_1(&parsed));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_solve_2() {
|
||||
let input = include_str!("../sample.txt");
|
||||
let parsed = parse_input(input);
|
||||
assert_eq!(900, solve_2(&parsed));
|
||||
fn parse_input(s: &str) -> Self::Input {
|
||||
s.lines()
|
||||
.map(|line| {
|
||||
let mut split = line.split(' ');
|
||||
(
|
||||
match split.next().unwrap() {
|
||||
"forward" => Direction::Forward,
|
||||
"down" => Direction::Down,
|
||||
"up" => Direction::Up,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
split.next().unwrap().parse().unwrap(),
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn solve_1(input: &Self::Input) -> Self::Output {
|
||||
let sub = input
|
||||
.into_iter()
|
||||
.fold((0, 0), |sub, &(dir, dist)| match dir {
|
||||
Direction::Forward => (sub.0 + dist, sub.1),
|
||||
Direction::Down => (sub.0, sub.1 + dist),
|
||||
Direction::Up => (sub.0, sub.1 - dist),
|
||||
});
|
||||
sub.0 * sub.1
|
||||
}
|
||||
|
||||
fn solve_2(input: &Self::Input) -> Self::Output {
|
||||
let sub = input
|
||||
.into_iter()
|
||||
.fold((0, 0, 0), |sub, &(dir, dist)| match dir {
|
||||
Direction::Forward => (sub.0 + dist, sub.1 + sub.2 * dist, sub.2),
|
||||
Direction::Down => (sub.0, sub.1, sub.2 + dist),
|
||||
Direction::Up => (sub.0, sub.1, sub.2 - dist),
|
||||
});
|
||||
sub.0 * sub.1
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
use aoc_lib::AdventOfCode;
|
||||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||
|
||||
#[path = "../src/main.rs"]
|
||||
|
@ -8,32 +9,32 @@ mod main;
|
|||
fn bench_main(c: &mut Criterion) {
|
||||
c.bench_function("parse input", |b| {
|
||||
let input = include_str!("../input.txt");
|
||||
b.iter(|| main::parse_input(black_box(input)))
|
||||
b.iter(|| main::Day3::parse_input(black_box(input)))
|
||||
});
|
||||
|
||||
c.bench_function("solve 1", |b| {
|
||||
let input = main::parse_input(include_str!("../input.txt"));
|
||||
b.iter(|| main::solve_1(black_box(&input)))
|
||||
let input = main::Day3::parse_input(include_str!("../input.txt"));
|
||||
b.iter(|| main::Day3::solve_1(black_box(&input)))
|
||||
});
|
||||
|
||||
c.bench_function("solve 2", |b| {
|
||||
let input = main::parse_input(include_str!("../input.txt"));
|
||||
b.iter(|| main::solve_2(black_box(&input)))
|
||||
let input = main::Day3::parse_input(include_str!("../input.txt"));
|
||||
b.iter(|| main::Day3::solve_2(black_box(&input)))
|
||||
});
|
||||
|
||||
c.bench_function("parse sample input", |b| {
|
||||
let input = include_str!("../sample.txt");
|
||||
b.iter(|| main::parse_input(black_box(input)))
|
||||
b.iter(|| main::Day3::parse_input(black_box(input)))
|
||||
});
|
||||
|
||||
c.bench_function("solve 1 (sample input)", |b| {
|
||||
let input = main::parse_input(include_str!("../sample.txt"));
|
||||
b.iter(|| main::solve_1(black_box(&input)))
|
||||
let input = main::Day3::parse_input(include_str!("../sample.txt"));
|
||||
b.iter(|| main::Day3::solve_1(black_box(&input)))
|
||||
});
|
||||
|
||||
c.bench_function("solve 2 (sample input)", |b| {
|
||||
let input = main::parse_input(include_str!("../sample.txt"));
|
||||
b.iter(|| main::solve_2(black_box(&input)))
|
||||
let input = main::Day3::parse_input(include_str!("../sample.txt"));
|
||||
b.iter(|| main::Day3::solve_2(black_box(&input)))
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -1,51 +1,44 @@
|
|||
use aoc_lib::*;
|
||||
|
||||
pub struct Input(usize, Vec<usize>);
|
||||
aoc_setup!(Day3, test 1: 198, test 2: 230);
|
||||
|
||||
fn main() {
|
||||
let input = read_stdin();
|
||||
let (parsed, parsed_time) = time(|| parse_input(&input));
|
||||
let (solve_1, solve_1_time) = time(|| solve_1(&parsed));
|
||||
let (solve_2, solve_2_time) = time(|| solve_2(&parsed));
|
||||
pub struct Day3;
|
||||
|
||||
println!("Solution to part 1: {}", solve_1);
|
||||
println!("Solution to part 2: {}", solve_2);
|
||||
impl AdventOfCode for Day3 {
|
||||
type Input = (usize, Vec<usize>);
|
||||
type Output = usize;
|
||||
|
||||
println!("Parsing took: {:?}", parsed_time);
|
||||
println!("Solving part 1 took: {:?}", solve_1_time);
|
||||
println!("Solving part 2 took: {:?}", solve_2_time);
|
||||
fn parse_input(s: &str) -> Self::Input {
|
||||
(
|
||||
s.lines().next().unwrap().len(),
|
||||
s.lines()
|
||||
.map(|l| usize::from_str_radix(l, 2).unwrap())
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
|
||||
fn solve_1(input: &Self::Input) -> Self::Output {
|
||||
let mask = (1 << input.0) - 1;
|
||||
let half_len = input.1.len() / 2;
|
||||
|
||||
let gamma = (0..input.0)
|
||||
.map(|i| (i, get_one_count_at_location(input.1.iter(), i) > half_len))
|
||||
.fold(0, |acc, (i, set)| if set { acc | (1 << i) } else { acc });
|
||||
|
||||
let epsilon = (!gamma) & mask;
|
||||
|
||||
gamma * epsilon
|
||||
}
|
||||
|
||||
fn solve_2(input: &Self::Input) -> Self::Output {
|
||||
let part1 = solve_2_sub(input, false);
|
||||
let part2 = solve_2_sub(input, true);
|
||||
|
||||
part1 * part2
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_input(s: &str) -> Input {
|
||||
Input(
|
||||
s.lines().next().unwrap().len(),
|
||||
s.lines()
|
||||
.map(|l| usize::from_str_radix(l, 2).unwrap())
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn solve_1(input: &Input) -> usize {
|
||||
let mask = (1 << input.0) - 1;
|
||||
let half_len = input.1.len() / 2;
|
||||
|
||||
let gamma = (0..input.0)
|
||||
.map(|i| (i, get_one_count_at_location(input.1.iter(), i) > half_len))
|
||||
.fold(0, |acc, (i, set)| if set { acc | (1 << i) } else { acc });
|
||||
|
||||
let epsilon = (!gamma) & mask;
|
||||
|
||||
gamma * epsilon
|
||||
}
|
||||
|
||||
pub fn solve_2(input: &Input) -> usize {
|
||||
let part1 = solve_2_sub(input, false);
|
||||
let part2 = solve_2_sub(input, true);
|
||||
|
||||
part1 * part2
|
||||
}
|
||||
|
||||
fn solve_2_sub(input: &Input, reverse: bool) -> usize {
|
||||
fn solve_2_sub(input: &(usize, Vec<usize>), reverse: bool) -> usize {
|
||||
let full_mask = (1 << input.0) - 1;
|
||||
let mut pattern = 0;
|
||||
let mut pattern_len = 0;
|
||||
|
@ -91,17 +84,3 @@ fn solve_2_sub(input: &Input, reverse: bool) -> usize {
|
|||
fn get_one_count_at_location<'a>(items: impl Iterator<Item = &'a usize>, i: usize) -> usize {
|
||||
items.filter(|&&n| (n & (1 << i)) > 0).count()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_solve_1() {
|
||||
let input = include_str!("../sample.txt");
|
||||
let parsed = parse_input(input);
|
||||
assert_eq!(198, solve_1(&parsed));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_solve_2() {
|
||||
let input = include_str!("../sample.txt");
|
||||
let parsed = parse_input(input);
|
||||
assert_eq!(230, solve_2(&parsed));
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
use aoc_lib::AdventOfCode;
|
||||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||
|
||||
#[path = "../src/main.rs"]
|
||||
|
@ -8,32 +9,32 @@ mod main;
|
|||
fn bench_main(c: &mut Criterion) {
|
||||
c.bench_function("parse input", |b| {
|
||||
let input = include_str!("../input.txt");
|
||||
b.iter(|| main::parse_input(black_box(input)))
|
||||
b.iter(|| main::Day4::parse_input(black_box(input)))
|
||||
});
|
||||
|
||||
c.bench_function("solve 1", |b| {
|
||||
let input = main::parse_input(include_str!("../input.txt"));
|
||||
b.iter(|| main::solve_1(black_box(&input)))
|
||||
let input = main::Day4::parse_input(include_str!("../input.txt"));
|
||||
b.iter(|| main::Day4::solve_1(black_box(&input)))
|
||||
});
|
||||
|
||||
c.bench_function("solve 2", |b| {
|
||||
let input = main::parse_input(include_str!("../input.txt"));
|
||||
b.iter(|| main::solve_2(black_box(&input)))
|
||||
let input = main::Day4::parse_input(include_str!("../input.txt"));
|
||||
b.iter(|| main::Day4::solve_2(black_box(&input)))
|
||||
});
|
||||
|
||||
c.bench_function("parse sample input", |b| {
|
||||
let input = include_str!("../sample.txt");
|
||||
b.iter(|| main::parse_input(black_box(input)))
|
||||
b.iter(|| main::Day4::parse_input(black_box(input)))
|
||||
});
|
||||
|
||||
c.bench_function("solve 1 (sample input)", |b| {
|
||||
let input = main::parse_input(include_str!("../sample.txt"));
|
||||
b.iter(|| main::solve_1(black_box(&input)))
|
||||
let input = main::Day4::parse_input(include_str!("../sample.txt"));
|
||||
b.iter(|| main::Day4::solve_1(black_box(&input)))
|
||||
});
|
||||
|
||||
c.bench_function("solve 2 (sample input)", |b| {
|
||||
let input = main::parse_input(include_str!("../sample.txt"));
|
||||
b.iter(|| main::solve_2(black_box(&input)))
|
||||
let input = main::Day4::parse_input(include_str!("../sample.txt"));
|
||||
b.iter(|| main::Day4::solve_2(black_box(&input)))
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
use std::ops::IndexMut;
|
||||
|
||||
use aoc_lib::*;
|
||||
use itertools::Itertools;
|
||||
use std::ops::IndexMut;
|
||||
|
||||
aoc_setup!(Day4, test 1: 4512, test 2: 1924);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Input(Vec<u8>, Vec<Board>);
|
||||
|
@ -43,130 +44,109 @@ impl Board {
|
|||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let input = read_stdin();
|
||||
let (parsed, parsed_time) = time(|| parse_input(&input));
|
||||
let (solve_1, solve_1_time) = time(|| solve_1(&parsed));
|
||||
let (solve_2, solve_2_time) = time(|| solve_2(&parsed));
|
||||
pub struct Day4;
|
||||
|
||||
println!("Solution to part 1: {}", solve_1);
|
||||
println!("Solution to part 2: {}", solve_2);
|
||||
impl AdventOfCode for Day4 {
|
||||
type Input = Input;
|
||||
type Output = usize;
|
||||
|
||||
println!("Parsing took: {:?}", parsed_time);
|
||||
println!("Solving part 1 took: {:?}", solve_1_time);
|
||||
println!("Solving part 2 took: {:?}", solve_2_time);
|
||||
}
|
||||
fn parse_input(s: &str) -> Self::Input {
|
||||
let mut iter = s.lines().filter(|line| line.len() > 0);
|
||||
|
||||
pub fn parse_input(s: &str) -> Input {
|
||||
let mut iter = s.lines().filter(|line| line.len() > 0);
|
||||
let x = iter
|
||||
.next()
|
||||
.unwrap()
|
||||
.split(',')
|
||||
.map(|s| s.parse::<u8>().unwrap())
|
||||
.collect();
|
||||
|
||||
let x = iter
|
||||
.next()
|
||||
.unwrap()
|
||||
.split(',')
|
||||
.map(|s| s.parse::<u8>().unwrap())
|
||||
.collect();
|
||||
|
||||
let boards = iter
|
||||
.chunks(5)
|
||||
.into_iter()
|
||||
.map(|chunk| {
|
||||
let mut numbers = [0; 5 * 5];
|
||||
for (i, n) in chunk.into_iter().enumerate() {
|
||||
n.split(' ')
|
||||
.filter(|x| x.len() > 0)
|
||||
.enumerate()
|
||||
.for_each(|(j, s)| {
|
||||
numbers[i * 5 + j] = s.parse::<u8>().unwrap();
|
||||
});
|
||||
}
|
||||
Board(numbers)
|
||||
})
|
||||
.collect();
|
||||
|
||||
Input(x, boards)
|
||||
}
|
||||
|
||||
pub fn solve_1(input: &Input) -> usize {
|
||||
let mut solve_mask = vec![0u32; input.1.len()];
|
||||
let mut last_num = 0;
|
||||
|
||||
let board_index = input
|
||||
.0
|
||||
.iter()
|
||||
.find_map(|&num| {
|
||||
input.1.iter().enumerate().find_map(|(i, board)| {
|
||||
board.update_mask(num, solve_mask.index_mut(i));
|
||||
if Board::is_solved(solve_mask[i]) {
|
||||
last_num = num as usize;
|
||||
Some(i)
|
||||
} else {
|
||||
None
|
||||
let boards = iter
|
||||
.chunks(5)
|
||||
.into_iter()
|
||||
.map(|chunk| {
|
||||
let mut numbers = [0; 5 * 5];
|
||||
for (i, n) in chunk.into_iter().enumerate() {
|
||||
n.split(' ')
|
||||
.filter(|x| x.len() > 0)
|
||||
.enumerate()
|
||||
.for_each(|(j, s)| {
|
||||
numbers[i * 5 + j] = s.parse::<u8>().unwrap();
|
||||
});
|
||||
}
|
||||
Board(numbers)
|
||||
})
|
||||
})
|
||||
.unwrap();
|
||||
.collect();
|
||||
|
||||
input.1[board_index].get_unmarked_sum(solve_mask[board_index]) * last_num
|
||||
}
|
||||
Input(x, boards)
|
||||
}
|
||||
|
||||
pub fn solve_2(input: &Input) -> usize {
|
||||
let mut solve_mask = vec![0u32; input.1.len()];
|
||||
let mut last_num = 0;
|
||||
let mut solved_list = vec![0usize; (input.1.len() / (usize::BITS as usize)) + 1];
|
||||
let mut last_solved = 0;
|
||||
let mut last_mask = 0;
|
||||
let mut solved_count = 0; // i'm too lazy to write a check against solved_list
|
||||
fn solve_1(input: &Self::Input) -> Self::Output {
|
||||
let mut solve_mask = vec![0u32; input.1.len()];
|
||||
let mut last_num = 0;
|
||||
|
||||
input
|
||||
.0
|
||||
.iter()
|
||||
.filter_map(|&num| {
|
||||
input
|
||||
.1
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(i, board)| {
|
||||
let board_index = input
|
||||
.0
|
||||
.iter()
|
||||
.find_map(|&num| {
|
||||
input.1.iter().enumerate().find_map(|(i, board)| {
|
||||
board.update_mask(num, solve_mask.index_mut(i));
|
||||
if Board::is_solved(solve_mask[i]) {
|
||||
last_num = num as usize;
|
||||
Some(i)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let solved_ref = solved_list.index_mut(i / (usize::BITS as usize));
|
||||
let solved_bit_idx = i % (usize::BITS as usize);
|
||||
input.1[board_index].get_unmarked_sum(solve_mask[board_index]) * last_num
|
||||
}
|
||||
|
||||
if ((*solved_ref) & (1 << solved_bit_idx)) == 0 {
|
||||
if Board::is_solved(solve_mask[i]) {
|
||||
last_num = num as usize;
|
||||
last_solved = i;
|
||||
last_mask = solve_mask[last_solved];
|
||||
*solved_ref |= 1 << solved_bit_idx;
|
||||
solved_count += 1;
|
||||
fn solve_2(input: &Self::Input) -> Self::Output {
|
||||
let mut solve_mask = vec![0u32; input.1.len()];
|
||||
let mut last_num = 0;
|
||||
let mut solved_list = vec![0usize; (input.1.len() / (usize::BITS as usize)) + 1];
|
||||
let mut last_solved = 0;
|
||||
let mut last_mask = 0;
|
||||
let mut solved_count = 0; // i'm too lazy to write a check against solved_list
|
||||
|
||||
// check if everything is solved
|
||||
if solved_count == input.1.len() {
|
||||
return Some(());
|
||||
input
|
||||
.0
|
||||
.iter()
|
||||
.filter_map(|&num| {
|
||||
input
|
||||
.1
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(i, board)| {
|
||||
board.update_mask(num, solve_mask.index_mut(i));
|
||||
|
||||
let solved_ref = solved_list.index_mut(i / (usize::BITS as usize));
|
||||
let solved_bit_idx = i % (usize::BITS as usize);
|
||||
|
||||
if ((*solved_ref) & (1 << solved_bit_idx)) == 0 {
|
||||
if Board::is_solved(solve_mask[i]) {
|
||||
last_num = num as usize;
|
||||
last_solved = i;
|
||||
last_mask = solve_mask[last_solved];
|
||||
*solved_ref |= 1 << solved_bit_idx;
|
||||
solved_count += 1;
|
||||
|
||||
// check if everything is solved
|
||||
if solved_count == input.1.len() {
|
||||
return Some(());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
})
|
||||
.next()
|
||||
})
|
||||
.next()
|
||||
.unwrap();
|
||||
None
|
||||
})
|
||||
.next()
|
||||
})
|
||||
.next()
|
||||
.unwrap();
|
||||
|
||||
input.1[last_solved].get_unmarked_sum(last_mask) * last_num
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_solve_1() {
|
||||
let input = include_str!("../sample.txt");
|
||||
let parsed = parse_input(input);
|
||||
assert_eq!(4512, solve_1(&parsed));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_solve_2() {
|
||||
let input = include_str!("../sample.txt");
|
||||
let parsed = parse_input(input);
|
||||
assert_eq!(1924, solve_2(&parsed));
|
||||
input.1[last_solved].get_unmarked_sum(last_mask) * last_num
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче