hi clubby

This commit is contained in:
nora 2024-12-01 13:34:16 +01:00
parent 3490086a7f
commit 1b194e4f1c
5 changed files with 187 additions and 1 deletions

7
2024/Cargo.lock generated
View file

@ -119,6 +119,7 @@ dependencies = [
"divan", "divan",
"helper", "helper",
"nom", "nom",
"rustc-hash",
] ]
[[package]] [[package]]
@ -229,6 +230,12 @@ version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a" checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a"
[[package]]
name = "rustc-hash"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497"
[[package]] [[package]]
name = "rustix" name = "rustix"
version = "0.38.41" version = "0.38.41"

View file

@ -9,6 +9,7 @@ edition = "2021"
nom.workspace = true nom.workspace = true
helper.workspace = true helper.workspace = true
divan.workspace = true divan.workspace = true
rustc-hash = "2.1.0"
[[bench]] [[bench]]
name = "benches" name = "benches"

View file

@ -1,4 +1,7 @@
use helper::{Day, IteratorExt, Variants}; use std::{collections::HashMap, hash::BuildHasherDefault};
use helper::{Day, IteratorExt, NoHasher, Variants};
use rustc_hash::FxHashMap;
pub fn main() { pub fn main() {
helper::main::<Day01>(include_str!("../input.txt")); helper::main::<Day01>(include_str!("../input.txt"));
@ -13,6 +16,11 @@ helper::define_variants! {
} }
part2 { part2 {
basic => crate::part2; basic => crate::part2;
hash => crate::part2_hash;
hash_no_hash => crate::part2_hash_nohash;
faster_parsing => crate::part2_parsing;
array => crate::part2_array;
μopt_parsing => crate::part2_μopt_parsing;
} }
} }
@ -61,6 +69,150 @@ fn part2(input: &str) -> u64 {
score score
} }
fn part2_hash(input: &str) -> u64 {
let (left, right) = parse(input);
let mut right_map = FxHashMap::<u64, u32>::default();
for number in right {
*right_map.entry(number).or_default() += 1;
}
let mut score = 0;
for number in left {
let occurs = right_map.get(&number).copied().unwrap_or_default();
score += number * (occurs as u64);
}
score
}
fn part2_hash_nohash(input: &str) -> u64 {
let (left, right) = parse(input);
let mut right_map = HashMap::<u64, u32, BuildHasherDefault<NoHasher>>::default();
for number in right {
*right_map.entry(number).or_default() += 1;
}
let mut score = 0;
for number in left {
let occurs = right_map.get(&number).copied().unwrap_or_default();
score += number * (occurs as u64);
}
score
}
fn part2_parsing(input: &str) -> u64 {
let mut right_map = FxHashMap::<u64, u32>::with_capacity_and_hasher(
input.len() / 8,
rustc_hash::FxBuildHasher::default(),
);
let mut left = Vec::with_capacity(input.len() / 8);
let mut input = input;
loop {
let Some(space) = input.as_bytes().iter().position(|b| *b == b' ') else {
break;
};
let number = input[..space].parse::<u64>().unwrap();
left.push(number);
input = &input[(space + 3)..];
let Some(newline) = input.as_bytes().iter().position(|b| *b == b'\n') else {
break;
};
let number = input[..space].parse::<u64>().unwrap();
*right_map.entry(number).or_default() += 1;
input = &input[newline..];
// handle lack of trailing newline
if !input.is_empty() {
input = &input[1..];
}
}
let mut score = 0;
for number in left {
let occurs = right_map.get(&number).copied().unwrap_or_default();
score += number * (occurs as u64);
}
score
}
fn part2_array(input: &str) -> u64 {
const BIGGEST_ELEMENT: usize = 100_000;
let mut right_map = vec![0_u16; BIGGEST_ELEMENT];
let mut left = Vec::with_capacity(input.len() / 8);
let mut input = input;
loop {
let Some(space) = input.as_bytes().iter().position(|b| *b == b' ') else {
break;
};
let number = input[..space].parse::<u64>().unwrap();
left.push(number);
input = &input[(space + 3)..];
let Some(newline) = input.as_bytes().iter().position(|b| *b == b'\n') else {
break;
};
let number = input[..space].parse::<u64>().unwrap();
right_map[number as usize] += 1;
input = &input[newline..];
// handle lack of trailing newline
if !input.is_empty() {
input = &input[1..];
}
}
let mut score = 0;
for number in left {
let occurs = right_map[number as usize];
score += number * (occurs as u64);
}
score
}
fn part2_μopt_parsing(input: &str) -> u64 {
const BIGGEST_ELEMENT: usize = 100_000;
let mut right_map = vec![0_u16; BIGGEST_ELEMENT];
let mut left = Vec::with_capacity(input.len() / 8);
let mut input = input;
loop {
let Some(space) = input.as_bytes().iter().position(|b| *b == b' ') else {
break;
};
let number = input[..space].parse::<u64>().unwrap();
left.push(number);
input = &input[(space + 3)..];
let Some(newline) = input.as_bytes().iter().position(|b| *b == b'\n') else {
break;
};
let number = input[..space].parse::<u64>().unwrap();
right_map[number as usize] += 1;
input = &input[newline..];
// handle lack of trailing newline
if !input.is_empty() {
input = &input[1..];
}
}
let mut score = 0;
for number in left {
let occurs = right_map[number as usize];
score += number * (occurs as u64);
}
score
}
helper::tests! { helper::tests! {
day01 Day01; day01 Day01;
part1 { part1 {

24
helper/src/hash.rs Normal file
View file

@ -0,0 +1,24 @@
use std::hash::Hasher;
#[derive(Default)]
pub struct NoHasher {
value: u64,
}
impl Hasher for NoHasher {
fn finish(&self) -> u64 {
self.value
}
fn write_u32(&mut self, i: u32) {
self.value = i as u64;
}
fn write_u64(&mut self, i: u64) {
self.value = i;
}
fn write(&mut self, _: &[u8]) {
unimplemented!()
}
}

View file

@ -1,10 +1,12 @@
mod cmd; mod cmd;
mod ext; mod ext;
mod hash;
use std::{borrow::Cow, fmt::Debug}; use std::{borrow::Cow, fmt::Debug};
pub use self::cmd::main; pub use self::cmd::main;
pub use self::ext::*; pub use self::ext::*;
pub use self::hash::*;
pub type Solution = fn(&str) -> u64; pub type Solution = fn(&str) -> u64;