From 0df15292382ced1361aa18e029a558510dfb9bf4 Mon Sep 17 00:00:00 2001 From: 1adept <69433209+1adept@users.noreply.github.com> Date: Thu, 21 Dec 2023 16:40:46 +0100 Subject: [PATCH] Day1 --- src/day1.rs | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 19 +++++++++ 2 files changed, 133 insertions(+) create mode 100644 src/day1.rs create mode 100644 src/main.rs diff --git a/src/day1.rs b/src/day1.rs new file mode 100644 index 0000000..a20ec0b --- /dev/null +++ b/src/day1.rs @@ -0,0 +1,114 @@ +use core::num; + +use crate::util::{Day, Solution}; + +pub struct Day1; + +impl Day for Day1 { + fn solve(input: &str) -> Solution { + let (part1, part2) = input + .lines() + .take_while(|line| !line.is_empty()) + .map(|line| (part1_line(&line), part2_line(line))) + .reduce(|(p1, p2), (part1, part2)| (p1 + part1, p2 + part2)) + .expect("Failed to solve"); + + (part1, part2) + } +} + +fn part1_line(line: &str) -> usize { + let numbers: Vec = line + .chars() + .filter(|char| char.is_ascii_digit()) + .map(|char| char.to_string().parse().expect("Expected a number")) + .collect(); + let first = numbers.first().unwrap_or(&0); + let last = numbers.last().unwrap_or(&0); + first * 10 + last +} + +fn part2_line(line: &str) -> usize { + const WORD_NUMBERS: [&str; 9] = [ + "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", + ]; + + fn of_two_option(a: Option, b: Option, f: F) -> Option + where + F: Fn(usize, usize) -> usize, + { + match (a, b) { + (None, None) => None, + (None, Some(i)) => Some(i), + (Some(i), None) => Some(i), + (Some(l), Some(r)) => Some(f(l, r)), + } + } + + let res = WORD_NUMBERS + .iter() + .enumerate() + .flat_map(|(index, &word)| { + let number = index + 1; + let (number_first, number_last) = { + let number_string = &number.to_string(); + (line.find(number_string), line.rfind(number_string)) + }; + let word_first = line.find(word); + let word_last = line.rfind(word); + + let min = of_two_option(number_first, word_first, usize::min).map(|idx| (idx, number)); + let max = of_two_option(number_last, word_last, usize::max).map(|idx| (idx, number)); + vec![min, max] + }) + .flatten() + .collect::>(); + + let tens = res + .iter() + .min_by_key(|(idx, _num)| idx) + .map(|(_, number)| number) + .expect("Expected to find at least one number"); + let ones = res + .iter() + .max_by_key(|(idx, _num)| idx) + .map(|(_, number)| number) + .expect("Expected to find at least one number"); + + println!("In {line} we have ({tens}, {ones})"); + + // 55336 too HIGH + 10 * tens + ones +} + +#[cfg(test)] +mod tests { + use crate::util::Day; + + use super::Day1; + + const EXAMPLE1: &str = "\ + 1abc2\n\ + pqr3stu8vwx\n\ + a1b2c3d4e5f\n\ + treb7uchet"; + + const EXAMPLE2: &str = "\ + two1nine\n\ + eightwothree\n\ + abcone2threexyz\n\ + xtwone3four\n\ + 4nineeightseven2\n\ + zoneight234\n\ + 7pqrstsixteen"; + + #[test] + fn test_part1() { + assert_eq!(142, Day1::solve(EXAMPLE1).0); + } + + #[test] + fn test_part2() { + assert_eq!(281, Day1::solve(EXAMPLE2).1); + } +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..65587ed --- /dev/null +++ b/src/main.rs @@ -0,0 +1,19 @@ +use day1::Day1; +use util::{read_input, Day}; + +mod day1; +mod util; + +fn main() { + let day1 = solve(1); + println!("Day1 = {day1:?}"); +} + +fn solve(day: u8) -> (usize, usize) { + let input = &read_input(day).unwrap(); + match day { + 1 => Day1::solve(input), + _ if day > 25 => unreachable!("There are only 25 days!"), + _ => todo!("Not done!"), + } +}