Skip to content

Commit

Permalink
Improvement: Year 2015: Day 01, and more benchmarks
Browse files Browse the repository at this point in the history
  • Loading branch information
joshleaves committed Mar 28, 2024
1 parent 97d52fb commit 54418ea
Show file tree
Hide file tree
Showing 9 changed files with 302 additions and 193 deletions.
224 changes: 148 additions & 76 deletions benches/year_2015.rs

Large diffs are not rendered by default.

60 changes: 48 additions & 12 deletions benches/year_2015_day_01.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,36 +75,72 @@ fn day_01_v2_fast(input: impl Into<String>) -> i16 {
0
}

fn day_01_v2_flash(input: impl Into<String>) -> i16 {
unsafe { mem::transmute::<String, Vec<u16>>(input.into()) }
.iter()
.try_fold((0, 0), |mut acc, pair| {
match (acc.0, pair) {
// Case for ")" or "))" or "()"
(0, 41) | (0, 10537) | (0, 10281) => return Err((acc.1) + 1),

// Case for "("
(_, 40) => acc.0 += 1,
// Case for ")"
(_, 41) => acc.0 -= 1,
// Case for "(("
(_, 10280) => acc.0 += 2,
// Case for "))"
(_, 10537) => acc.0 -= 2,
// Case for ")(" or "()"
(_, 10536) | (_, 10281) => (),
_ => (),
}
acc.1 += 2;
Ok(acc)
})
.and::<i16>(Err(0))
.unwrap_err()
}

fn bench_year_2015_day_01_v1(c: &mut Criterion) {
let input = include_str!("../inputs/year_2015/day_01_input");
assert_eq!(day_01::day_01_v1(input), 138);
assert_eq!(day_01_v1_naive(input), 138);
assert_eq!(day_01_v1_fast(input), 138);

let mut group = c.benchmark_group("year_2015::day_01_v1");
group.warm_up_time(Duration::from_millis(100));
let input = include_str!("../inputs/year_2015/day_01_input");
group.bench_with_input(BenchmarkId::new("Base", input.len()), input, |b, input| {
b.iter(|| day_01::day_01_v1(input))
});

group.bench_with_input(BenchmarkId::new("Naive", input.len()), input, |b, input| {
b.iter(|| day_01_v1_naive(input))
});
group.bench_with_input(
BenchmarkId::new("Normal", input.len()),
input,
|b, input| b.iter(|| day_01::day_01_v1(input)),
);
group.bench_with_input(BenchmarkId::new("Fast", input.len()), input, |b, input| {
b.iter(|| day_01_v1_fast(input))
});
group.finish();
}

fn bench_year_2015_day_01_v2(c: &mut Criterion) {
let input = include_str!("../inputs/year_2015/day_01_input");
assert_eq!(day_01::day_01_v2(input), 1_771);
assert_eq!(day_01_v2_fast(input), 1_771);
assert_eq!(day_01_v2_flash(input), 1_771);

let mut group = c.benchmark_group("year_2015::day_01_v2");
group.warm_up_time(Duration::from_millis(100));
let input = include_str!("../inputs/year_2015/day_01_input");
group.bench_with_input(
BenchmarkId::new("Normal", input.len()),
input,
|b, input| b.iter(|| day_01::day_01_v2(input)),
);

group.bench_with_input(BenchmarkId::new("Base", input.len()), input, |b, input| {
b.iter(|| day_01::day_01_v2(input))
});
group.bench_with_input(BenchmarkId::new("Fast", input.len()), input, |b, input| {
b.iter(|| day_01_v2_fast(input))
});
group.bench_with_input(BenchmarkId::new("Flash", input.len()), input, |b, input| {
b.iter(|| day_01_v2_flash(input))
});
group.finish();
}

Expand Down
32 changes: 6 additions & 26 deletions benches/year_2017_day_01.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,43 +44,23 @@ fn day_01_v2_zip(input: impl Into<String>) -> u16 {
.sum()
}

// fn bench_year_2017_day_01_v1(c: &mut Criterion) {
// let mut group = c.benchmark_group("year_2017::day_01_v1");
// group.warm_up_time(Duration::from_millis(100));
// let input = include_str!("../inputs/year_2017/day_01_input");
// group.bench_with_input(BenchmarkId::new("Naive", input.len()), input, |b, input| {
// b.iter(|| day_01_v1_naive(input))
// });
// assert_eq!(day_01::day_01_v1(input), 1_069);
// group.bench_with_input(
// BenchmarkId::new("Normal", input.len()),
// input,
// |b, input| b.iter(|| day_01::day_01_v1(input)),
// );
// group.bench_with_input(BenchmarkId::new("Fast", input.len()), input, |b, input| {
// b.iter(|| day_01_v1_fast(input))
// });
// group.finish();
// }

fn bench_year_2017_day_01_v2(c: &mut Criterion) {
let mut group = c.benchmark_group("year_2017::day_01_v2");
group.warm_up_time(Duration::from_millis(100));
let input = include_str!("../inputs/year_2017/day_01_input");
assert_eq!(day_01_v2_naive(input), 1_268);
assert_eq!(day_01_v2_zip(input), 1_268);
assert_eq!(day_01::day_01_v2(input), 1_268);

let mut group = c.benchmark_group("year_2017::day_01_v2");
group.warm_up_time(Duration::from_millis(100));
group.bench_with_input(BenchmarkId::new("Naive", input.len()), input, |b, input| {
b.iter(|| day_01_v2_naive(input))
});
group.bench_with_input(BenchmarkId::new("Zip", input.len()), input, |b, input| {
b.iter(|| day_01_v2_zip(input))
});
group.bench_with_input(
BenchmarkId::new("Normal", input.len()),
input,
|b, input| b.iter(|| day_01::day_01_v2(input)),
);
group.bench_with_input(BenchmarkId::new("Base", input.len()), input, |b, input| {
b.iter(|| day_01::day_01_v2(input))
});

group.finish();
}
Expand Down
8 changes: 3 additions & 5 deletions benches/year_2017_day_02.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,9 @@ fn bench_year_2017_day_02_v1(c: &mut Criterion) {
group.bench_with_input(BenchmarkId::new("Naive", input.len()), input, |b, input| {
b.iter(|| day_02_v1_naive(input))
});
group.bench_with_input(
BenchmarkId::new("Normal", input.len()),
input,
|b, input| b.iter(|| day_02::day_02_v1(input)),
);
group.bench_with_input(BenchmarkId::new("Base", input.len()), input, |b, input| {
b.iter(|| day_02::day_02_v1(input))
});

group.finish();
}
Expand Down
9 changes: 4 additions & 5 deletions benches/year_2017_day_04.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ fn bench_year_2017_day_04_v1(c: &mut Criterion) {
assert_eq!(day_04_v1_naive(input), 466);
assert_eq!(day_04_v1_sorted(input), 466);
assert_eq!(day_04_v1_with_set(input), 466);

group.bench_with_input(BenchmarkId::new("Base", input.len()), input, |b, input| {
b.iter(|| day_04::day_04_v1(input))
});
group.bench_with_input(BenchmarkId::new("Naive", input.len()), input, |b, input| {
b.iter(|| day_04_v1_naive(input))
});
Expand All @@ -71,11 +75,6 @@ fn bench_year_2017_day_04_v1(c: &mut Criterion) {
input,
|b, input| b.iter(|| day_04_v1_with_set(input)),
);
group.bench_with_input(
BenchmarkId::new("Normal", input.len()),
input,
|b, input| b.iter(|| day_04::day_04_v1(input)),
);

group.finish();
}
Expand Down
8 changes: 3 additions & 5 deletions benches/year_2017_day_13.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,9 @@ fn bench_year_2017_day_13_v2(c: &mut Criterion) {
group.bench_with_input(BenchmarkId::new("Sieve", input.len()), input, |b, input| {
b.iter(|| day_13_v2_sieve(input))
});
group.bench_with_input(
BenchmarkId::new("Normal", input.len()),
input,
|b, input| b.iter(|| day_13::day_13_v2(input)),
);
group.bench_with_input(BenchmarkId::new("Base", input.len()), input, |b, input| {
b.iter(|| day_13::day_13_v2(input))
});

group.finish();
}
Expand Down
60 changes: 34 additions & 26 deletions src/year_2015/day_01.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@
//! >
//! > Your puzzle answer was ~~`REDACTED`~~.
//!
//! # Implementation tricks
//!
//!
/// Solve exercise for year 2015, day 1 (part 1).
///
Expand Down Expand Up @@ -87,17 +90,17 @@
/// assert_eq!(day_01::day_01_v1(")))"), -3);
/// assert_eq!(day_01::day_01_v1(")())())"), -3);
/// ```
pub fn day_01_v1(input: impl Into<String>) -> i16 {
let mut lvl: i16 = 0;
for chr in input.into().bytes() {
match chr {
b'(' => lvl += 1,
b')' => lvl -= 1,
_ => panic!("Invalid character: {}", chr),
}
}
lvl
pub fn day_01_v1(input: impl Into<String>) -> i16 {
input
.into()
.bytes()
.map(|chr| match chr {
b'(' => 1,
b')' => -1,
_ => 0,
})
.sum()
}

/// Solve exercise for year 2015, day 1 (part 2).
Expand All @@ -122,8 +125,8 @@ pub fn day_01_v1(input: impl Into<String>) -> i16 {
/// - If `level` reaches `-1`, return current `index` multipled by `2` (compound
/// size) and add `1` (because `index` started at `0`).
///
/// Advantage: Impossible to use the "Naive" implementation, and "Normal" is not
/// a huge time loss either.
/// Advantage: Impossible to use the "Naive" implementation, and "Base" is not a
/// huge time loss either.
///
/// # Samples
/// ```
Expand All @@ -133,20 +136,23 @@ pub fn day_01_v1(input: impl Into<String>) -> i16 {
/// assert_eq!(day_01::day_01_v2(")"), 1);
/// assert_eq!(day_01::day_01_v2("()())"), 5);
/// ```
pub fn day_01_v2(input: impl Into<String>) -> i16 {
let mut lvl: i16 = 0;
for (idx, chr) in input.into().bytes().enumerate() {
match chr {
b'(' => lvl += 1,
b')' => lvl -= 1,
_ => panic!("Invalid character: {}", chr),
}
if lvl < 0 {
return idx as i16 + 1;
}
}
0
pub fn day_01_v2(input: impl Into<String>) -> i16 {
input
.into()
.bytes()
.try_fold((0, 0), |mut acc, chr| {
acc.1 += 1;
match (acc.0, chr) {
(0, b')') => return Err(acc.1),
(_, b'(') => acc.0 += 1,
(_, b')') => acc.0 -= 1,
_ => (),
}
Ok(acc)
})
.and::<i16>(Err(0))
.unwrap_err()
}

solvable!(day_01, day_01_v1, day_01_v2, i16);
Expand Down Expand Up @@ -175,11 +181,13 @@ mod tests {

#[test]
fn works_with_samples_v2() {
let sample_two: [(&str, i16); 2] = [
let sample_two: [(&str, i16); 3] = [
("(())", 0),
(")", 1),
("()())", 5),
];
for (sample, result) in sample_two.iter() {
println!("Test: {}", sample);
assert_eq!(day_01_v2(*sample), *result);
}
}
Expand Down
68 changes: 43 additions & 25 deletions src/year_2015/day_04.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,36 +18,54 @@
//! >
//! > Your puzzle answer was ~~`REDACTED`~~.
//!
//! # Implementation tricks
//!
//! Since the [md-5 crate](https://crates.io/crates/md-5) used returns hashes as
//! an array of hex(`u4`) values joined by two into a single `u8`, we can either
//! turn the hash into a string and check for leading `0` characters, which will
//! be costly, or we can limit ourselves to checking the first three `u8``.
//!
//! To match the first '00' hexadecimal pair, we can match it to `0u8`. Same will
//! go for the second pair.
//!
//! For the third one, we're in a bit of a pickle: we must match either one part
//! of the number, or all of it. The most obvious approach is using bitmasks, or
//! we can simply compare the value of the hash. Since the only values producing
//! a hash starting with (at least one) zero are all inferior to `0x10` (`16` in
//! an u8 format), we can match with any number inferior to `16`.
//!
//! # Samples
//! ```
//! /// Import the module
//! use advent_rs::year_2015::day_04;
//!
//! assert_eq!(day_04::day_04_v1("abcdef"), 609_043);
//! assert_eq!(day_04::day_04_v1("pqrstuv"), 1_048_970);
//! assert_eq!(day_04::day_04_v2("abcdef"), 6_742_839);
//! ```
use md5::{Digest, Md5};

#[mutants::skip] // Don't even try this hahaha
fn loop_until_hash(input: &str, stop_value: u8) -> u32 {
let mut starter: u32 = 0;
let mut hasher = Md5::new();
hasher.update(input);
loop {
let mut hasher_num = hasher.clone();
hasher_num.update(starter.to_string());
let hash = hasher_num.finalize();
if hash[..2] == [0, 0] && hash[2] <= stop_value {
return starter;
}
use md5::Digest;
use md5::Md5;

starter += 1;
}
fn find_hash(input: &str, stop_value: u8) -> u32 {
let mut md5 = Md5::new();
md5.update(input);
(0..=u32::MAX)
.find(|counter| {
let mut hasher = md5.clone();
hasher.update(&counter.to_string());
let hash = hasher.finalize();
hash[0] == 0 && hash[1] == 0 && hash[2] < stop_value
})
.unwrap()
}

pub fn day_04_v1(input: impl Into<String>) -> u32 {
let input_str = input.into();
let clean_str = input_str.trim_end();
loop_until_hash(clean_str, 15)
find_hash(input.into().trim_end(), 16)
}

pub fn day_04_v2(input: impl Into<String>) -> u32 {
let input_str = input.into();
let clean_str = input_str.trim_end();
loop_until_hash(clean_str, 0)
find_hash(input.into().trim_end(), 1)
}

solvable!(day_04, day_04_v1, day_04_v2, u32);
Expand All @@ -60,8 +78,8 @@ mod tests {
#[ignore = "Too slow for CI"]
fn works_with_samples_v1() {
let sample_one: [(&str, u32); 2] = [
("abcdef", 609043),
("pqrstuv", 1048970),
("abcdef", 609_043),
("pqrstuv", 1_048_970),
];
for (sample, result) in sample_one.iter() {
assert_eq!(day_04_v1(*sample), *result);
Expand All @@ -71,6 +89,6 @@ mod tests {
#[test]
#[ignore = "Too slow for CI"]
fn works_with_samples_v2() {
assert_eq!(day_04_v2("abcdef"), 6742839);
assert_eq!(day_04_v2("abcdef"), 6_742_839);
}
}
Loading

0 comments on commit 54418ea

Please sign in to comment.