From 3be88c4f96b8bbcba951a017561cb4b84bdfe7c5 Mon Sep 17 00:00:00 2001 From: Dreaded_X Date: Sun, 4 Dec 2022 19:44:00 +0100 Subject: [PATCH] Improved solutions --- 2022/src/bin/day2.rs | 14 ++----------- 2022/src/bin/day3.rs | 48 ++++++++++++++++++++------------------------ 2022/src/bin/day4.rs | 5 +++-- 3 files changed, 27 insertions(+), 40 deletions(-) diff --git a/2022/src/bin/day2.rs b/2022/src/bin/day2.rs index 906206b..7f6d8a5 100644 --- a/2022/src/bin/day2.rs +++ b/2022/src/bin/day2.rs @@ -95,14 +95,6 @@ impl From<&Hand> for u32 { } // -- Helper functions -- -// Convert the round to a tuple containing the actions of both players -fn convert(round: &str) -> (&str, &str) { - match round.split_once(" ") { - Some((a, b)) => (a, b), - None => panic!("Invalid input: {round}"), - } -} - fn calc_score(sum: u32, (a, b): (Hand, Hand)) -> u32 { sum + b.play(&a) + u32::from(&b) } @@ -116,16 +108,14 @@ impl aoc::Solver for Day { fn part1(input: &str) -> u32 { input.lines() - .filter(|round| round.len() > 0) - .map(convert) + .filter_map(|round| round.split_once(" ")) .map(|(a, b)| (Hand::from(a), Hand::from(b))) .fold(0, calc_score) } fn part2(input: &str) -> u32 { input.lines() - .filter(|round| round.len() > 0) - .map(convert) + .filter_map(|round| round.split_once(" ")) .map(|(a, b)| { let opponent = Hand::from(a); (opponent, opponent.strategy(b)) diff --git a/2022/src/bin/day3.rs b/2022/src/bin/day3.rs index 1ad6d29..480f978 100644 --- a/2022/src/bin/day3.rs +++ b/2022/src/bin/day3.rs @@ -29,13 +29,28 @@ mod tests { } // -- Helpers -- -fn convert(c: &u8) -> u32 { +fn convert(c: char) -> u32 { let result = match c { - b'a'..=b'z' => c - b'a' + 1, - b'A'..=b'Z' => c - b'A' + 27, + 'a'..='z' => c as u32 - 'a' as u32 + 1, + 'A'..='Z' => c as u32 - 'A' as u32 + 27, _ => panic!("Invalid input"), }; - result as u32 + result +} + +// Very nice alternative way to find the overlap +// Based on something I say online +// Part 1 could also be adapted to use this, but for historical sake I will leave that as is +// Part 2 was originally done the same as part 1, just with an extra condition in the if +fn find_common(group: &[&str]) -> char { + let mut common = group[0].chars().collect::>(); + + // Only keep characters that appear in all other strings + common.retain(|&c| { + group[1..].iter().all(|g| g.contains(c)) + }); + + *common.first().expect("Should be one overlap") } // -- Solution -- @@ -49,11 +64,9 @@ impl aoc::Solver for Day { input.lines() .map(|line| line.split_at(line.len()/2)) .map(|(a, b)| { - // @NOTE This is not really ok if the string contains multi byte characters, this - // is however not the case here - for c in a.as_bytes() { + for c in a.chars() { // There is always one character in common between the two sides - if b.contains(*c as char) { + if b.contains(c) { return c; } } @@ -67,24 +80,7 @@ impl aoc::Solver for Day { input.lines() .collect::>() .chunks(3) - .map(|group| { - if let [a, b, c] = group { - (a, b, c) - } else { - panic!("The total amount of lines should be a multiple of 3") - } - }) - .map(|(a, b, c)| { - // @NOTE This is not really ok if the string contains multi byte characters, this - // is however not the case here - for l in a.as_bytes() { - // There is always one character in common between the three rucksacks - if b.contains(*l as char) && c.contains(*l as char) { - return l; - } - } - unreachable!("No characters in common, this should never happen") - }) + .map(find_common) .map(convert) .sum() } diff --git a/2022/src/bin/day4.rs b/2022/src/bin/day4.rs index 8c87a1d..8db642f 100644 --- a/2022/src/bin/day4.rs +++ b/2022/src/bin/day4.rs @@ -54,8 +54,9 @@ fn overlaps((a, b): &(Elf, Elf)) -> bool { // Transform from line to pair of Elfs fn transform(s: &str) -> (Elf, Elf) { - let transformed = s.split(',') - .flat_map(|pair| pair.split('-')) + let transformed = s + .replace("-", ",") + .split(',') .flat_map(|value| value.parse::()) .collect::>();