From 6f074102075e2d27788882beae374b09611a97ca Mon Sep 17 00:00:00 2001 From: Greg Burri Date: Sun, 1 Dec 2024 22:54:29 +0100 Subject: [PATCH 1/1] Day 01 --- .gitignore | 10 +++++ Cargo.toml | 18 ++++++++ README.md | 27 ++++++++++++ src/day01.rs | 80 ++++++++++++++++++++++++++++++++++ src/days.rs | 13 ++++++ src/main.rs | 120 +++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 268 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 README.md create mode 100644 src/day01.rs create mode 100644 src/days.rs create mode 100644 src/main.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..088ba6b --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..34640d9 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "advent_of_code_2022" +version = "0.1.0" +authors = ["Greg Burri "] +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +itertools = "0.10" +regex = "1" +clap = { version = "4", features = ["derive"] } +rayon = "1.10" + +[profile.release] +opt-level = 3 +lto = true +codegen-units = 1 diff --git a/README.md b/README.md new file mode 100644 index 0000000..5c71c81 --- /dev/null +++ b/README.md @@ -0,0 +1,27 @@ +# AdventOfCode2024 + +https://adventofcode.com/2024 + + +# Running tests + +Example for day 1 tests: + +~~~ +cargo test day01 -- --nocapture +~~~ + +All tests: + +~~~ +cargo test -- --nocapture +~~~ + + +# Running a day code + +~~~ +cargo run -- n +~~~ + +Where 'n' is a number from 1 to 25 diff --git a/src/day01.rs b/src/day01.rs new file mode 100644 index 0000000..67f5cce --- /dev/null +++ b/src/day01.rs @@ -0,0 +1,80 @@ +use std::{cmp::Ordering, io::BufRead, iter::Iterator}; + +pub fn read_location_ids_as_sorted(reader: R) -> (Vec, Vec) +where + R: BufRead, +{ + let mut l1 = Vec::::new(); + let mut l2 = Vec::::new(); + + for l in reader.lines() { + let ids: Vec = l + .unwrap() + .split_whitespace() + .into_iter() + .map(|n| n.parse::().unwrap()) + .collect(); + + l1.push(ids[0]); + l2.push(ids[1]); + } + + l1.sort(); + l2.sort(); + + (l1, l2) +} + +pub fn sum_distances(sorted_ids1: &[i32], sorted_ids2: &[i32]) -> i32 { + sorted_ids1 + .iter() + .zip(sorted_ids2) + .fold(0, |sum, (id1, id2)| sum + (id1 - id2).abs()) +} + +pub fn similarity_score(sorted_ids1: &[i32], sorted_ids2: &[i32]) -> i32 { + let mut score: i32 = 0; + let (mut i, mut j) = (0, 0); + while i < sorted_ids1.len() { + match sorted_ids1[i].cmp(&sorted_ids2[j]) { + Ordering::Greater => { + j += 1; + } + Ordering::Less => { + i += 1; + } + Ordering::Equal => { + score += sorted_ids2[j..] + .iter() + .take_while(|v| **v == sorted_ids1[i]) + .sum::(); + i += 1; + } + } + } + score +} + +#[cfg(test)] +mod tests { + use super::*; + + static IDS: &str = "3 4 +4 3 +2 5 +1 3 +3 9 +3 3"; + + #[test] + fn part1() { + let (ids1, ids2) = read_location_ids_as_sorted(IDS.as_bytes()); + assert_eq!(sum_distances(&ids1, &ids2), 11); + } + + #[test] + fn part2() { + let (ids1, ids2) = read_location_ids_as_sorted(IDS.as_bytes()); + assert_eq!(similarity_score(&ids1, &ids2), 31); + } +} diff --git a/src/days.rs b/src/days.rs new file mode 100644 index 0000000..5c6ed4b --- /dev/null +++ b/src/days.rs @@ -0,0 +1,13 @@ +use std::{fs, io::BufReader}; + +use crate::*; + +pub fn day01() -> String { + let f = fs::File::open("data/day01.input").unwrap(); + let (ids1, ids2) = day01::read_location_ids_as_sorted(BufReader::new(f)); + format!( + "part1: {}, part2: {}", + day01::sum_distances(&ids1, &ids2), + day01::similarity_score(&ids1, &ids2) + ) +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..d268f58 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,120 @@ +use std::time::Instant; + +use clap::Parser; +use rayon::prelude::*; + +mod day01; +// mod day02; +// mod day03; +// mod day04; +// mod day05; +// mod day06; +// mod day07; +// mod day08; +// mod day09; +// mod day10; +// mod day11; +// mod day12; +// mod day13; +// mod day14; +// mod day15; +// mod day16; +// mod day17; +// mod day18; +// mod day19; +// mod day20; +// mod day21; +// mod day22; +// mod day23; +// mod day24; +mod days; + +#[derive(Parser, Debug)] +#[command(author = "Greg Burri", version = "1.0", about = "Advent of Code 2024")] +struct Args { + #[arg(index(1), exclusive(true))] + day: Option, + + #[arg(short, long)] + parallel: bool, +} + +fn main() { + println!("https://adventofcode.com/2024"); + + let days: Vec String> = vec![ + days::day01, + // days::day02, + // days::day03, + // days::day04, + // days::day05, + // days::day06, + // days::day07, + // days::day08, + // days::day09, + // days::day10, + // days::day11, + // days::day12, + // days::day13, + // days::day14, + // days::day15, + // days::day16, + // days::day17, + // days::day18, + // days::day19, + // days::day20, + // days::day21, + // days::day22, + // days::day23, + // days::day24, + ]; + + let args = Args::parse(); + + match args.day { + Some(day) => { + if day >= 1 && day <= days.len() { + do_day(&days, day) + } else { + println!("Unknown day: {}", day) + } + } + // No argument -> execute all day problems. + None => { + let now = Instant::now(); + + if args.parallel { + (1..=days.len()) + .into_par_iter() + .for_each(|d| do_day(&days, d)); + } else { + (1..=days.len()).for_each(|d| do_day(&days, d)); + } + + println!( + "Time to execute all days: {}", + format_micros(now.elapsed().as_micros()) + ); + } + } +} + +fn do_day(days: &[fn() -> String], day: usize) { + let now = Instant::now(); + println!( + "Result of day {:02}: {} (time: {})", + day, + days[day - 1](), + format_micros(now.elapsed().as_micros()) + ); +} + +fn format_micros(t: u128) -> String { + if t < 10_000 { + format!("{} μs", t) + } else if t < 10_000_000u128 { + format!("{:.2} ms", t as f64 / 1e3f64) + } else { + format!("{:.2} s", t as f64 / 1e6f64) + } +} -- 2.45.2