summaryrefslogtreecommitdiff
path: root/2023/day7/src
diff options
context:
space:
mode:
Diffstat (limited to '2023/day7/src')
-rw-r--r--2023/day7/src/lib.rs153
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);
+ }
+}