diff options
Diffstat (limited to '2023/day7/src')
-rw-r--r-- | 2023/day7/src/lib.rs | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/2023/day7/src/lib.rs b/2023/day7/src/lib.rs new file mode 100644 index 0000000..02cd337 --- /dev/null +++ b/2023/day7/src/lib.rs @@ -0,0 +1,153 @@ +use std::{collections::HashMap, str::FromStr}; + +#[derive(Debug, PartialEq, PartialOrd, Eq, Hash)] +enum HandType { + Five, + Four, + Full, + Three, + Two, + One, + High, +} + +#[derive(Debug)] +struct Play { + hand: Vec<u32>, + bid: u32, + hand_type: HandType, +} + +#[derive(Debug)] +struct PlayError; + +impl FromStr for Play { + type Err = PlayError; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + if !s.contains(' ') { + return Err(PlayError); + } + + let s: Vec<String> = s.split(' ').map(|x| x.to_string()).collect(); + if s.len() != 2 { + return Err(PlayError); + } + + let mut diffcards: HashMap<char, u32> = HashMap::new(); + let hand = s[0].chars().collect::<Vec<char>>(); + + for ch in &hand { + if diffcards.contains_key(&ch) { + *(diffcards.get_mut(ch).unwrap()) += 1; + } else { + diffcards.insert(*ch, 1); + } + } + + let card_points: HashMap<char, u32> = HashMap::from([ + ('A', 13), + ('K', 12), + ('Q', 11), + ('J', 10), + ('T', 9), + ('9', 8), + ('8', 7), + ('7', 6), + ('6', 5), + ('5', 4), + ('4', 3), + ('3', 2), + ('2', 1), + ]); + let hand: Vec<_> = hand.iter().map(|x| *card_points.get(&x).unwrap()).collect(); + + let b: Vec<u32> = diffcards.clone().into_values().collect(); + let max_labels: u32 = *b.iter().max().unwrap(); + + let hand_type: HandType = match diffcards.keys().len() { + 1 => HandType::Five, + 2 if max_labels == 4 => HandType::Four, + 2 if max_labels == 3 => HandType::Full, + 3 if max_labels == 3 => HandType::Three, + 3 => HandType::Two, + 4 => HandType::One, + 5 => HandType::High, + _ => panic!("wtf is this?"), + }; + + Ok(Play { + hand, + bid: s[1].parse::<u32>().unwrap(), + hand_type, + }) + } +} + +pub fn part1(input: &str) -> u32 { + let mut res: u32 = 0; + + let plays: Vec<_> = input + .trim_end() + .split('\n') + .map(|x| x.parse::<Play>().unwrap()) + .collect(); + + let mut hs: HashMap<HandType, Vec<Play>> = HashMap::from([ + (HandType::Five, vec![]), + (HandType::Four, vec![]), + (HandType::Full, vec![]), + (HandType::Three, vec![]), + (HandType::Two, vec![]), + (HandType::One, vec![]), + (HandType::High, vec![]), + ]); + + for play in plays { + if let Some(p) = hs.get_mut(&play.hand_type) { + p.push(play); + } + } + + let mut rank = 1; + + for kind in [ + HandType::High, + HandType::One, + HandType::Two, + HandType::Three, + HandType::Full, + HandType::Four, + HandType::Five, + ] { + hs.get_mut(&kind) + .unwrap() + .sort_by(|a, b| a.hand.partial_cmp(&b.hand).unwrap()); + + for h in hs.get(&kind).unwrap() { + res += rank * h.bid; + rank += 1; + } + } + + res +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn example_part1() { + let input = include_str!("../example.txt"); + let result = part1(input); + assert_eq!(result, 6440); + } + + #[test] + fn input_part1() { + let input = include_str!("../input.txt"); + let result = part1(input); + assert_eq!(result, 248179786); + } +} |