2024 day-1 done
This commit is contained in:
33
2024/Cargo.toml
Normal file
33
2024/Cargo.toml
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
[workspace]
|
||||||
|
resolver = "2"
|
||||||
|
members = [ "day-*" ]
|
||||||
|
|
||||||
|
[workspace.package]
|
||||||
|
version = "2024.0.0"
|
||||||
|
edition = "2021"
|
||||||
|
authors = [ "Dylan Thies" ]
|
||||||
|
repository = "https://github.com/smellyfis/AOC.git"
|
||||||
|
|
||||||
|
[workspace.dependencies]
|
||||||
|
derive-getters = "0.5.0"
|
||||||
|
error-stack = "0.5.0"
|
||||||
|
itertools = "0.13.0"
|
||||||
|
log = "0.4.22"
|
||||||
|
nom = "7.1.3"
|
||||||
|
nom_locate= "4.2.0"
|
||||||
|
rstest = "0.23.0"
|
||||||
|
rstest_reuse = "0.7.0"
|
||||||
|
dhat = "0.3.3"
|
||||||
|
glam = "0.29.2"
|
||||||
|
petgraph = "0.6.5"
|
||||||
|
num = "0.4.3"
|
||||||
|
num-traits = "0.2.19"
|
||||||
|
rustworkx-core = "0.15.1"
|
||||||
|
pathfinding = "4.11.0"
|
||||||
|
test-log = {version="0.2.16", features=["default", "unstable"]}
|
||||||
|
thiserror = "2.0.3"
|
||||||
|
|
||||||
|
|
||||||
|
[profile.dhat]
|
||||||
|
inherits = "release"
|
||||||
|
debug = true
|
||||||
23
2024/day-1/Cargo.toml
Normal file
23
2024/day-1/Cargo.toml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
[package]
|
||||||
|
name = "day-1"
|
||||||
|
version.workspace = true
|
||||||
|
edition.workspace = true
|
||||||
|
authors.workspace = true
|
||||||
|
repository.workspace = true
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
nom.workspace = true
|
||||||
|
itertools.workspace = true
|
||||||
|
log.workspace = true
|
||||||
|
error-stack.workspace = true
|
||||||
|
thiserror.workspace = true
|
||||||
|
dhat.workspace = true
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
test-log.workspace = true
|
||||||
|
|
||||||
|
[features]
|
||||||
|
dhat-heap = []
|
||||||
4
2024/day-1/src/lib.rs
Normal file
4
2024/day-1/src/lib.rs
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
pub(crate) mod part1;
|
||||||
|
pub use crate::part1::*;
|
||||||
|
pub(crate) mod part2;
|
||||||
|
pub use crate::part2::*;
|
||||||
31
2024/day-1/src/main.rs
Normal file
31
2024/day-1/src/main.rs
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
#![warn(clippy::all, clippy::pedantic)]
|
||||||
|
|
||||||
|
use day_1::part1;
|
||||||
|
use day_1::part2;
|
||||||
|
|
||||||
|
use error_stack::{Result, ResultExt};
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[cfg(feature = "dhat-heap")]
|
||||||
|
#[global_allocator]
|
||||||
|
static ALLOC: dhat::Alloc = dhat::Alloc;
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
enum Day1Error {
|
||||||
|
#[error("Part 1 failed")]
|
||||||
|
Part1Error,
|
||||||
|
#[error("Part 2 failed")]
|
||||||
|
Part2Error,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> Result<(), Day1Error> {
|
||||||
|
#[cfg(feature = "dhat-heap")]
|
||||||
|
let _profiler = dhat::Profiler::new_heap();
|
||||||
|
|
||||||
|
let input = include_str!("./input.txt");
|
||||||
|
let part1_result = part1(input).change_context(Day1Error::Part1Error)?;
|
||||||
|
println!("part 1: {part1_result}");
|
||||||
|
let part2_result = part2(input).change_context(Day1Error::Part2Error)?;
|
||||||
|
println!("part 2: {part2_result}");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
54
2024/day-1/src/part1.rs
Normal file
54
2024/day-1/src/part1.rs
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
#![warn(clippy::all, clippy::pedantic)]
|
||||||
|
|
||||||
|
use error_stack::Result;
|
||||||
|
use nom::{character::complete, multi::separated_list1, sequence::separated_pair, IResult};
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
// day-1
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum Day1Part1Error {
|
||||||
|
#[error("Problem parsing Day 1")]
|
||||||
|
ParseError,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn part1(input: &str) -> Result<u64, Day1Part1Error> {
|
||||||
|
let (_, (mut col1, mut col2)) =
|
||||||
|
parse_input(input).expect("there should always be valid input from aoc");
|
||||||
|
col1.sort();
|
||||||
|
col2.sort();
|
||||||
|
|
||||||
|
Ok(col1
|
||||||
|
.into_iter()
|
||||||
|
.zip(col2.iter())
|
||||||
|
.map(|(a, b)| u64::max(a, *b) - u64::min(a, *b))
|
||||||
|
.sum())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_input(input: &str) -> IResult<&str, (Vec<u64>, Vec<u64>)> {
|
||||||
|
let (input, combo) = separated_list1(
|
||||||
|
complete::line_ending,
|
||||||
|
separated_pair(complete::u64, complete::space1, complete::u64),
|
||||||
|
)(input)?;
|
||||||
|
Ok((input, combo.into_iter().unzip()))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const INPUT: &str = "3 4
|
||||||
|
4 3
|
||||||
|
2 5
|
||||||
|
1 3
|
||||||
|
3 9
|
||||||
|
3 3 ";
|
||||||
|
|
||||||
|
#[test_log::test]
|
||||||
|
#[test_log(default_log_filter = "trace")]
|
||||||
|
fn part1_works() {
|
||||||
|
let result = part1(INPUT).unwrap();
|
||||||
|
assert_eq!(result, 11);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
54
2024/day-1/src/part2.rs
Normal file
54
2024/day-1/src/part2.rs
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
#![warn(clippy::all, clippy::pedantic)]
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use error_stack::{Report, Result, ResultExt};
|
||||||
|
use nom::{character::complete, multi::separated_list1, sequence::separated_pair, IResult};
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
// day-1
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum Day1Part2Error {
|
||||||
|
#[error("Problem parsing Day 1")]
|
||||||
|
ParseError,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn part2(input: &str) -> Result<u64, Day1Part2Error> {
|
||||||
|
let (_, (col1, col2)) = parse_input(input)
|
||||||
|
.map_err(|x| Report::from(x.to_owned()))
|
||||||
|
.change_context(Day1Part2Error::ParseError)?;
|
||||||
|
let col2_bucket: HashMap<u64, u64> = col2.into_iter().fold(HashMap::new(), |mut acc, x| {
|
||||||
|
let val = acc.entry(x).or_insert(0);
|
||||||
|
*val += 1;
|
||||||
|
acc
|
||||||
|
});
|
||||||
|
Ok(col1.iter().map(|x| *x * col2_bucket.get(x).or(Some(&0)).unwrap()).sum())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_input(input: &str) -> IResult<&str, (Vec<u64>, Vec<u64>)> {
|
||||||
|
let (input, combo) = separated_list1(
|
||||||
|
complete::line_ending,
|
||||||
|
separated_pair(complete::u64, complete::space1, complete::u64),
|
||||||
|
)(input)?;
|
||||||
|
Ok((input, combo.into_iter().unzip()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const INPUT: &str = "3 4
|
||||||
|
4 3
|
||||||
|
2 5
|
||||||
|
1 3
|
||||||
|
3 9
|
||||||
|
3 3 ";
|
||||||
|
|
||||||
|
#[test_log::test]
|
||||||
|
#[test_log(default_log_filter = "trace")]
|
||||||
|
fn part2_works() {
|
||||||
|
let result = part2(INPUT).unwrap();
|
||||||
|
assert_eq!(result, 31);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user