Started with aoc 2015, unable to make d4 part2 faster. Multi-threaded actually slower

This commit is contained in:
Fabian Schmidt 2024-10-28 11:39:18 +01:00
parent ae00eb4f80
commit 8370d27bea
15 changed files with 1411 additions and 0 deletions

9
Cargo.lock generated
View File

@ -2,9 +2,18 @@
# It is not intended for manual editing.
version = 4
[[package]]
name = "md5"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771"
[[package]]
name = "y2015"
version = "0.1.0"
dependencies = [
"md5",
]
[[package]]
name = "y2016"

View File

@ -4,3 +4,4 @@ version = "0.1.0"
edition = "2021"
[dependencies]
md5 = "0.7.0"

File diff suppressed because one or more lines are too long

1000
y2015/resources/2_input.txt Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

20
y2015/src/bin/d1.rs Normal file
View File

@ -0,0 +1,20 @@
use std::fs;
use y2015::days::d1;
fn main() {
part1();
part2();
}
fn part1() {
let root = env!("CARGO_MANIFEST_DIR");
let content = fs::read_to_string(format!("{root}/resources/1_input.txt")).unwrap();
println!("{}", d1::process_part1(&content));
}
fn part2() {
let root = env!("CARGO_MANIFEST_DIR");
let content = fs::read_to_string(format!("{root}/resources/1_input.txt")).unwrap();
println!("{}", d1::process_part2(&content));
}

20
y2015/src/bin/d2.rs Normal file
View File

@ -0,0 +1,20 @@
use std::fs;
use y2015::days::d2;
fn main() {
part1();
part2();
}
fn part1() {
let root = env!("CARGO_MANIFEST_DIR");
let content = fs::read_to_string(format!("{root}/resources/2_input.txt")).unwrap();
println!("{}", d2::process_part1(&content));
}
fn part2() {
let root = env!("CARGO_MANIFEST_DIR");
let content = fs::read_to_string(format!("{root}/resources/2_input.txt")).unwrap();
println!("{}", d2::process_part2(&content));
}

20
y2015/src/bin/d3.rs Normal file
View File

@ -0,0 +1,20 @@
use std::fs;
use y2015::days::d3;
fn main() {
part1();
part2();
}
fn part1() {
let root = env!("CARGO_MANIFEST_DIR");
let content = fs::read_to_string(format!("{root}/resources/3_input.txt")).unwrap();
println!("{}", d3::process_part1(&content));
}
fn part2() {
let root = env!("CARGO_MANIFEST_DIR");
let content = fs::read_to_string(format!("{root}/resources/3_input.txt")).unwrap();
println!("{}", d3::process_part2(&content));
}

20
y2015/src/bin/d4.rs Normal file
View File

@ -0,0 +1,20 @@
use std::time::Instant;
use y2015::days::d4;
fn main() {
part1();
part2();
}
fn part1() {
let now = Instant::now();
println!("{}", d4::process_part1("bgvyzdsv"));
println!("{}µs", now.elapsed().as_micros());
}
fn part2() {
let now = Instant::now();
println!("{}", d4::process_part2("bgvyzdsv"));
println!("{}µs", now.elapsed().as_micros());
}

74
y2015/src/days/d1.rs Normal file
View File

@ -0,0 +1,74 @@
use core::panic;
pub fn process_part1(input: &str) -> i32 {
input
.chars()
.map(|char| {
if char == '(' {
1
} else if char == ')' {
-1
} else if char == '\n' {
0
} else {
panic!("Expected '(' or ')'")
}
})
.sum()
}
pub fn process_part2(input: &str) -> i32 {
let mut floor = 0;
let mut pos = 0;
for char in input.chars() {
pos += 1;
if char == '(' {
floor += 1;
} else if char == ')' {
floor += -1;
} else if char == '\n' {
floor += 0;
} else {
panic!("Expected '(' or ')'")
}
if floor == -1 {
break;
}
}
pos
}
#[cfg(test)]
mod tests_1 {
use super::*;
#[test]
fn it_works() {
let result = process_part1("(())");
assert_eq!(result, 0);
let result = process_part1("(())");
assert_eq!(result, 0);
let result = process_part1("(((");
assert_eq!(result, 3);
let result = process_part1("(()(()(");
assert_eq!(result, 3);
let result = process_part1("))(((((");
assert_eq!(result, 3);
let result = process_part1("())");
assert_eq!(result, -1);
let result = process_part1("))(");
assert_eq!(result, -1);
let result = process_part1(")))");
assert_eq!(result, -3);
let result = process_part1(")())())");
assert_eq!(result, -3);
}
#[test]
fn part2() {
let result = process_part2(")(())))(");
assert_eq!(result, 1);
let result = process_part2("()()))))");
assert_eq!(result, 5);
}
}

57
y2015/src/days/d2.rs Normal file
View File

@ -0,0 +1,57 @@
pub fn process_part1(input: &str) -> i64 {
input
.lines()
.map(|line| {
line.split("x")
.map(|dimension| dimension.parse::<i64>().unwrap())
.collect::<Vec<i64>>()
})
.map(|dimension| {
let squares = (
dimension[0] * dimension[1],
dimension[0] * dimension[2],
dimension[1] * dimension[2],
);
squares.0.min(squares.1).min(squares.2) + squares.0 * 2 + squares.1 * 2 + squares.2 * 2
})
.sum()
}
pub fn process_part2(input: &str) -> i64 {
input
.lines()
.map(|line| {
line.split("x")
.map(|dimension| dimension.parse::<i64>().unwrap())
.collect::<Vec<i64>>()
})
.map(|dimension| {
let bow = dimension[0] * dimension[1] * dimension[2];
let ribbon = {
let largest = dimension[0].max(dimension[1]).max(dimension[2]);
dimension[0] * 2 + dimension[1] * 2 + dimension[2] * 2 - largest * 2
};
bow + ribbon
})
.sum()
}
#[cfg(test)]
mod tests_2 {
use super::*;
const INPUT: &str = "2x3x4
1x1x10";
#[test]
fn it_works() {
let result = process_part1(INPUT);
assert_eq!(result, 101);
}
#[test]
fn part2() {
let result = process_part2(INPUT);
assert_eq!(result, 48);
}
}

111
y2015/src/days/d3.rs Normal file
View File

@ -0,0 +1,111 @@
use core::panic;
use std::collections::HashSet;
pub fn process_part1(input: &str) -> i64 {
let mut visited_coords = HashSet::new();
let mut last_coord = (0, 0);
visited_coords.insert(last_coord);
input.chars().for_each(|char| {
if char == '^' {
last_coord.1 += 1;
visited_coords.insert(last_coord);
} else if char == '>' {
last_coord.0 += 1;
visited_coords.insert(last_coord);
} else if char == '<' {
last_coord.0 -= 1;
visited_coords.insert(last_coord);
} else if char == 'v' {
last_coord.1 -= 1;
visited_coords.insert(last_coord);
} else if char == '\n' {
println!("The end");
} else {
panic!("Could not parse direction");
}
});
visited_coords.len() as i64
}
pub fn process_part2(input: &str) -> i64 {
let mut visited_coords = HashSet::new();
let mut last_coord = (0, 0);
let mut is_robot = false;
let mut last_robo_coord = (0, 0);
visited_coords.insert(last_coord);
input.chars().for_each(|char| {
if is_robot {
if char == '^' {
last_robo_coord.1 += 1;
visited_coords.insert(last_robo_coord);
} else if char == '>' {
last_robo_coord.0 += 1;
visited_coords.insert(last_robo_coord);
} else if char == '<' {
last_robo_coord.0 -= 1;
visited_coords.insert(last_robo_coord);
} else if char == 'v' {
last_robo_coord.1 -= 1;
visited_coords.insert(last_robo_coord);
} else if char == '\n' {
println!("The end");
} else {
panic!("Could not parse direction");
}
} else if char == '^' {
last_coord.1 += 1;
visited_coords.insert(last_coord);
} else if char == '>' {
last_coord.0 += 1;
visited_coords.insert(last_coord);
} else if char == '<' {
last_coord.0 -= 1;
visited_coords.insert(last_coord);
} else if char == 'v' {
last_coord.1 -= 1;
visited_coords.insert(last_coord);
} else if char == '\n' {
println!("The end");
} else {
panic!("Could not parse direction");
}
is_robot = !is_robot;
});
visited_coords.len() as i64
}
#[cfg(test)]
mod tests_3 {
use super::*;
const INPUT: &str = ">
^v
^>v<
^v^v^v^v^v";
#[test]
fn it_works() {
let mut lines = INPUT.lines();
let result = process_part1(lines.next().unwrap());
assert_eq!(result, 2);
let result = process_part1(lines.next().unwrap());
assert_eq!(result, 2);
let result = process_part1(lines.next().unwrap());
assert_eq!(result, 4);
let result = process_part1(lines.next().unwrap());
assert_eq!(result, 2);
}
#[test]
fn part2() {
let mut lines = INPUT.lines();
let result = process_part2(lines.next().unwrap());
assert_eq!(result, 2);
let result = process_part2(lines.next().unwrap());
assert_eq!(result, 3);
let result = process_part2(lines.next().unwrap());
assert_eq!(result, 3);
let result = process_part2(lines.next().unwrap());
assert_eq!(result, 11);
}
}

72
y2015/src/days/d4.rs Normal file
View File

@ -0,0 +1,72 @@
use std::{
sync::{mpsc, Arc, Mutex},
thread,
};
pub fn process_part1(input: &str) -> i64 {
let mut n = 1;
loop {
let hash = md5::compute(format!("{input}{n}"));
let hash = format!("{hash:x}");
if hash.split_at(5).0 == "00000" {
break;
}
n += 1;
}
n
}
pub fn process_part2(input: &str) -> i64 {
let threads = thread::available_parallelism().unwrap().get();
let found = Arc::new(Mutex::new(false));
let (tx, rx) = mpsc::channel();
thread::scope(|s| {
for thread in 0..threads {
let tx_clone = tx.clone();
let found_clone = found.clone();
s.spawn(move || {
let mut n = thread + 1;
loop {
{
if *found_clone.lock().unwrap() {
break;
}
}
let hash = md5::compute(format!("{input}{n}"));
let hash = format!("{hash:x}");
if hash.split_at(6).0 == "000000" {
let _ = tx_clone.send(n);
let mut found_guard = found_clone.lock().unwrap();
*found_guard = true;
break;
}
n += 1;
}
});
}
drop(tx);
let mut res = vec![];
while let Ok(n) = rx.recv() {
res.push(n);
}
*res.iter().min().unwrap() as i64
})
}
#[cfg(test)]
mod tests_4 {
use super::*;
const INPUT1: &str = "abcdef";
const INPUT2: &str = "pqrstuv";
#[test]
fn it_works() {
let result = process_part1(INPUT1);
assert_eq!(result, 609043);
let result = process_part1(INPUT2);
assert_eq!(result, 1048970);
}
}

4
y2015/src/days/mod.rs Normal file
View File

@ -0,0 +1,4 @@
pub mod d1;
pub mod d2;
pub mod d3;
pub mod d4;

View File

@ -0,0 +1 @@
pub mod days;