From a13b049276558c7f5add049554317830599438f0 Mon Sep 17 00:00:00 2001 From: Daniel Flanagan Date: Sun, 1 Dec 2024 16:21:43 -0600 Subject: [PATCH] Day 1 --- 2024/rust/src/day1.rs | 150 +++++++++++++-------------------------- 2024/rust/src/prelude.rs | 4 +- 2 files changed, 54 insertions(+), 100 deletions(-) diff --git a/2024/rust/src/day1.rs b/2024/rust/src/day1.rs index 285059d..45f9357 100644 --- a/2024/rust/src/day1.rs +++ b/2024/rust/src/day1.rs @@ -1,3 +1,5 @@ +use std::{collections::HashMap, iter::zip, num::ParseIntError, str::FromStr}; + use crate::prelude::*; mod prelude; @@ -8,108 +10,57 @@ fn main() { struct Day1 {} impl Day1 { - fn calibration_value(line: &str) -> i128 { - println!("{line}"); - let bytes = line.as_bytes(); - let mut first_digit: Option = None; - let mut last_digit: Option = None; - for i in 0..bytes.len() { - let n = bytes.len() - 1 - i; - println!("{n} {i}"); - if first_digit.is_none() && (0x30..=0x39).contains(&bytes[i]) { - first_digit = Some(bytes[i] - 0x30); - println!("found first {first_digit:?}"); - } - if last_digit.is_none() && (0x30..=0x39).contains(&bytes[n]) { - last_digit = Some(bytes[n] - 0x30); - println!("found last {last_digit:?}"); - } - if first_digit.is_some() && last_digit.is_some() { - break; - } + fn smallests_distances(input: &str) -> i64 { + let mut lefts = Vec::::new(); + let mut rights = Vec::::new(); + for l in input.lines() { + let mut tokens = l.split(" "); + lefts.push(tokens.next().unwrap().parse().unwrap()); + rights.push(tokens.next().unwrap().parse().unwrap()); } - println!("{:?} {:?}", first_digit, last_digit); - Into::::into(first_digit.or(last_digit).unwrap() * 10) - + Into::::into(last_digit.or(first_digit).unwrap()) + lefts.sort(); + rights.sort(); + let mut sum = 0; + for (l, r) in zip(&lefts, &rights) { + sum += (l - r).abs(); + } + sum } - fn num_name(s: &[u8]) -> Option { - for (i, w) in [ - "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", - ] - .map(|s| s.as_bytes()) - .iter() - .enumerate() - { - if s.starts_with(w) { - return Some(i as u8); - } - } - return None; - } - - fn num_name_end(s: &[u8]) -> Option { - for (i, w) in [ - "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", - ] - .map(|s| s.as_bytes()) - .iter() - .enumerate() - { - if s.ends_with(w) { - return Some(i as u8); - } - } - return None; - } - - fn calibration_value_words(line: &str) -> i128 { - println!("{line}"); - let bytes = line.as_bytes(); - let mut first_digit: Option = None; - let mut last_digit: Option = None; - for i in 0..bytes.len() { - let n = bytes.len() - 1 - i; - println!("NI: {n} {i}"); - if first_digit.is_none() { - if (0x30..=0x39).contains(&bytes[i]) { - first_digit = Some(bytes[i] - 0x30); - println!("found first {first_digit:?}"); - } else if let Some(n) = Self::num_name(&bytes[i..]) { - first_digit = Some(n); - println!("found first text {first_digit:?}"); + fn similarity_score(input: &str) -> i64 { + let mut lefts = Vec::::new(); + let mut rights: HashMap = HashMap::new(); + for l in input.lines() { + let mut tokens = l.split(" "); + lefts.push(tokens.next().unwrap().parse().unwrap()); + let right: i64 = tokens.next().unwrap().parse().unwrap(); + match rights.get_mut(&right) { + None => { + rights.insert(right, 1); } - } - if last_digit.is_none() { - println!("{:?}", &bytes[..=n]); - if (0x30..=0x39).contains(&bytes[n]) { - last_digit = Some(bytes[n] - 0x30); - println!("found last {last_digit:?}"); - } else if let Some(n) = Self::num_name_end(&bytes[..=n]) { - last_digit = Some(n); - println!("found last text {last_digit:?}"); + Some(n) => { + *n += 1; } - } - if first_digit.is_some() && last_digit.is_some() { - break; - } + }; } - println!("{:?} {:?}", first_digit, last_digit); - Into::::into(first_digit.or(last_digit).unwrap() * 10) - + Into::::into(last_digit.or(first_digit).unwrap()) + let mut sum = 0; + for l in &lefts { + sum += (rights.get(l).unwrap_or(&0) * l) + } + sum } } impl AoCSolution for Day1 { type Input = String; - type Solution = i128; + type Solution = i64; fn part1(input: Self::Input) -> Self::Solution { - input.lines().map(Self::calibration_value).sum() + Day1::smallests_distances(&input) } fn part2(input: Self::Input) -> Self::Solution { - input.lines().map(Self::calibration_value_words).sum() + Day1::similarity_score(&input) } } @@ -121,26 +72,27 @@ mod tests { fn test() { assert_eq!( Day1::part1( - r#"1abc2 -pqr3stu8vwx -a1b2c3d4e5f -treb7uchet"# + r#"3 4 +4 3 +2 5 +1 3 +3 9 +3 3"# .into() ), - 142 + 11 ); assert_eq!( Day1::part2( - r#"two1nine -eightwothree -abcone2threexyz -xtwone3four -4nineeightseven2 -zoneight234 -7pqrstsixteen"# + r#"3 4 +4 3 +2 5 +1 3 +3 9 +3 3"# .into() ), - 281 + 31 ); } } diff --git a/2024/rust/src/prelude.rs b/2024/rust/src/prelude.rs index b50b57e..8086f69 100644 --- a/2024/rust/src/prelude.rs +++ b/2024/rust/src/prelude.rs @@ -6,8 +6,10 @@ use std::{env, io}; #[derive(Debug)] enum InputFileError { - #![allow(dead_code)] + #[allow(dead_code)] EnvVar(env::VarError), + + #[allow(dead_code)] Io(io::Error), }