summaryrefslogtreecommitdiff
path: root/2023/day7_2/src
diff options
context:
space:
mode:
authorSanto Cariotti <santo@dcariotti.me>2023-12-07 21:16:29 +0100
committerSanto Cariotti <santo@dcariotti.me>2023-12-07 21:16:29 +0100
commitc34b3109bb6d7bc40208428d6afa031227186911 (patch)
treec05f439ffc36f76b10548661e48431083f99411a /2023/day7_2/src
parent20ec09ee044f1936688cf561285b0512b44beaae (diff)
add day7 (+ day7 pt.2)
Two crates because i did not want to fix the `from_str`
Diffstat (limited to '2023/day7_2/src')
-rw-r--r--2023/day7_2/src/lib.rs189
1 files changed, 189 insertions, 0 deletions
diff --git a/2023/day7_2/src/lib.rs b/2023/day7_2/src/lib.rs
new file mode 100644
index 0000000..2651e98
--- /dev/null
+++ b/2023/day7_2/src/lib.rs
@@ -0,0 +1,189 @@
+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),
+ ('T', 9),
+ ('9', 8),
+ ('8', 7),
+ ('7', 6),
+ ('6', 5),
+ ('5', 4),
+ ('4', 3),
+ ('3', 2),
+ ('2', 1),
+ ('J', 0),
+ ]);
+ let hand: Vec<_> = hand.iter().map(|x| *card_points.get(&x).unwrap()).collect();
+ let jokers = hand.iter().filter(|&n| *n == 0).count();
+ let b: Vec<u32> = diffcards.clone().into_values().collect();
+ let max_labels: u32 = *b.iter().max().unwrap();
+
+ let mut 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?"),
+ };
+
+ match jokers {
+ 1 => {
+ hand_type = match hand_type {
+ HandType::High => HandType::One,
+ HandType::One => HandType::Three,
+ HandType::Two => HandType::Full,
+ HandType::Three => HandType::Four,
+ HandType::Four => HandType::Five,
+ _ => panic!("wtf is this?"),
+ }
+ }
+ 2 => {
+ hand_type = match hand_type {
+ HandType::One => HandType::Three,
+ HandType::Two => HandType::Four,
+ HandType::Full => HandType::Five,
+ _ => panic!("wtf is this?"),
+ }
+ }
+ 3 => {
+ hand_type = match hand_type {
+ HandType::High => HandType::Three,
+ HandType::One => HandType::Four,
+ HandType::Two => HandType::Five,
+ HandType::Three => HandType::Four,
+ HandType::Full => HandType::Five,
+ _ => panic!("wtf is this?"),
+ }
+ }
+ 4 => {
+ hand_type = HandType::Five;
+ }
+ 0 | 5 => {}
+ _ => panic!("wtf is this?"),
+ };
+
+ Ok(Play {
+ hand,
+ bid: s[1].parse::<u32>().unwrap(),
+ hand_type,
+ })
+ }
+}
+
+pub fn part2(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_part2() {
+ let input = include_str!("../example.txt");
+ let result = part2(input);
+ assert_eq!(result, 5905);
+ }
+
+ #[test]
+ fn input_part2() {
+ let input = include_str!("../input.txt");
+ let result = part2(input);
+ assert_eq!(result, 247885995);
+ }
+}