Adds Day1

This commit is contained in:
Dennis Brentjes 2024-12-01 20:55:15 +01:00
parent a2d898e66b
commit d3bd96f14f
9 changed files with 1205 additions and 4 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
/target
.vscode

20
Cargo.lock generated
View File

@ -1,7 +1,25 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
version = 4
[[package]]
name = "aoc-2024"
version = "0.1.0"
dependencies = [
"itertools",
]
[[package]]
name = "either"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]]
name = "itertools"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
dependencies = [
"either",
]

View File

@ -4,3 +4,4 @@ version = "0.1.0"
edition = "2021"
[dependencies]
itertools = "0.13"

1000
resources/input1.txt Normal file

File diff suppressed because it is too large Load Diff

71
src/days/day1.rs Normal file
View File

@ -0,0 +1,71 @@
use std::{collections::HashMap, iter::zip, path::Path};
use crate::{days::AdventDay, error::AdventError, input::get_lines};
pub struct Day1 {
list1: Vec<i32>,
list2: Vec<i32>,
count1: HashMap<i32, u64>,
count2: HashMap<i32, u64>
}
impl AdventDay for Day1 {
fn new() -> Self {
Day1 {
list1: vec![],
list2: vec![],
count1: HashMap::new(),
count2: HashMap::new()
}
}
fn read_input(&mut self) -> Result<(),AdventError> {
for line in get_lines(Path::new("resources/input1.txt")) {
let line = line?;
let mut s = line.split(" ");
let l = s.next().unwrap().parse::<i32>()?;
self.list1.push(l);
if self.count1.contains_key(&l) {
*self.count1.get_mut(&l).unwrap() += 1;
}
else {
self.count1.insert(l, 1);
}
let r = s.next().unwrap().parse::<i32>()?;
self.list2.push(r);
if self.count2.contains_key(&r) {
*self.count2.get_mut(&r).unwrap() += 1;
}
else {
self.count2.insert(r, 1);
}
}
Ok(())
}
fn puzzle1(&mut self) -> Result<u64, AdventError> {
self.list1.sort();
self.list2.sort();
Ok(zip(self.list1.clone(), self.list2.clone())
.map(|(l, r)| {
(l - r).abs() as u64
})
.sum::<u64>())
}
fn puzzle2(&mut self) -> Result<u64, AdventError> {
Ok(self.count1.keys().into_iter().map(
|k| {
let s = *k as u64;
if self.count2.contains_key(k) {
s * self.count1[k] * self.count2[k]
}
else {
0
}
}).sum())
}
}

11
src/days/mod.rs Normal file
View File

@ -0,0 +1,11 @@
use crate::error::AdventError;
pub trait AdventDay {
fn new() -> Self;
fn read_input(&mut self) -> Result<(),AdventError>;
fn puzzle1(&mut self) -> Result<u64, AdventError>;
fn puzzle2(&mut self) -> Result<u64, AdventError>;
}
pub mod day1;

28
src/error/mod.rs Normal file
View File

@ -0,0 +1,28 @@
use std::{num::{ParseIntError, TryFromIntError}, convert::Infallible, io};
#[derive(Debug)]
pub struct AdventError(pub String);
impl From<ParseIntError> for AdventError {
fn from(e: ParseIntError) -> Self {
AdventError(e.to_string())
}
}
impl From<io::Error> for AdventError {
fn from(e: io::Error) -> Self {
AdventError(e.to_string())
}
}
impl From<Infallible> for AdventError {
fn from(_: Infallible) -> Self {
unreachable!()
}
}
impl From<TryFromIntError> for AdventError {
fn from(e: TryFromIntError) -> Self {
AdventError(e.to_string())
}
}

29
src/input/mod.rs Normal file
View File

@ -0,0 +1,29 @@
use std::{fs::File, io::{BufRead, BufReader, Lines, Read}, path::{Path, PathBuf}, str::FromStr};
use crate::error::AdventError;
pub fn _read_into_vec<T:FromStr>(file_path : &Path) -> Result<Vec<T>, AdventError> where AdventError: From<<T as FromStr>::Err> {
let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
path.push(file_path);
let file = File::open(path).expect("no such file");
let buf = BufReader::new(file);
buf.lines().map(|line| T::from_str(line?.as_str()).map_err(Into::into)).collect::<Result<Vec<T>, AdventError>>()
}
pub fn _read_into<T:FromStr>(file_path: &Path) -> Result<T, AdventError> where AdventError: From<<T as FromStr>::Err> {
let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
path.push(file_path);
let mut file = File::open(path).expect("no such file");
let mut str: String = "".to_string();
file.read_to_string(&mut str)?;
Ok(T::from_str(str.as_str())?)
}
pub fn get_lines(file_path: &Path) -> Lines<BufReader<File>> {
let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
path.push(file_path);
let file = File::open(path).expect("no such file");
let buf = BufReader::new(file);
let lines = buf.lines();
lines
}

View File

@ -1,3 +1,45 @@
fn main() {
println!("Hello, world!");
}
pub mod error;
pub mod days;
mod input;
use std::env;
use day1::Day1;
use crate::error::AdventError;
use crate::days::*;
fn main() -> Result<(), AdventError> {
let mut advent_days = vec!(
Day1::new()
);
if env::args().len() == 1 {
Ok(advent_days.into_iter().map(|mut day| {
day.read_input()?;
let one_result = day.puzzle1()?;
let two_result = day.puzzle2()?;
Ok((one_result, two_result))
}).enumerate().map(|(index, r): (usize, Result<(u64, u64), AdventError>)| {
match r {
Ok((res1, res2)) => println!("{}: ({}, {})", index + 1, res1, res2),
Err(e) => println!("Error: {}", e.0)
};
}).fold((), |acc, _| { acc }))
} else {
let day_index = env::args().nth(1).ok_or(AdventError("Failed to parse day".into()))?.parse::<usize>()? - 1;
let day = &mut advent_days[day_index];
day.read_input()?;
if env::args().len() == 3 {
match env::args().nth(2).unwrap().parse::<usize>()? {
1 => Ok(println!("1: {}", &day.puzzle1()?)),
2 => Ok(println!("2: {}", &day.puzzle2()?)),
_ => return Err(AdventError("part must be either 1 or 2".into()))
}
} else {
Ok(println!("{}: ({}, {})", day_index + 1, day.puzzle1()?, day.puzzle2()?))
}
}
}