diff --git a/Cargo.lock b/Cargo.lock index ef9f682..ee5de96 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -68,6 +68,7 @@ name = "day07" version = "0.1.0" dependencies = [ "aoc_libs", + "itertools", "once_cell", "regex", ] @@ -82,6 +83,21 @@ dependencies = [ "regex", ] +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + +[[package]] +name = "itertools" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0" +dependencies = [ + "either", +] + [[package]] name = "memchr" version = "2.6.4" diff --git a/Cargo.toml b/Cargo.toml index 225f04a..922814b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,3 +20,4 @@ once_cell = "1.16" thiserror = "1.0" nom = "7.1" collection_literals = "1.0.1" +itertools = "0.12.0" diff --git a/days/day07/Cargo.toml b/days/day07/Cargo.toml index 2b9d639..e535201 100644 --- a/days/day07/Cargo.toml +++ b/days/day07/Cargo.toml @@ -9,3 +9,4 @@ edition.workspace = true aoc_libs.workspace = true regex.workspace = true once_cell.workspace = true +itertools.workspace = true diff --git a/days/day07/src/main.rs b/days/day07/src/main.rs index dc858b8..2be664b 100644 --- a/days/day07/src/main.rs +++ b/days/day07/src/main.rs @@ -10,5 +10,5 @@ fn main() { println!("Result: {}", part1::part1(&mut structured_input)); println!("Part Two"); - println!("Result: {}", part2::part2(&structured_input)); + println!("Result: {}", part2::part2(&mut structured_input)); } diff --git a/days/day07/src/parse.rs b/days/day07/src/parse.rs index b471ff6..c0ac092 100644 --- a/days/day07/src/parse.rs +++ b/days/day07/src/parse.rs @@ -1,7 +1,8 @@ +use itertools::Itertools; use once_cell::sync::Lazy; use regex::Regex; -#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)] pub enum Card { Ace = 14, King = 13, @@ -19,7 +20,7 @@ pub enum Card { Joker = 1, } -#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] pub enum Formation { FiveOfKind = 7, FourOfKind = 6, @@ -30,29 +31,24 @@ pub enum Formation { HighCard = 1, } -#[derive(Debug, PartialEq, Eq, Default)] -struct UnorderedHand { - ace: u8, - king: u8, - queen: u8, - jack: u8, - tim: u8, - nine: u8, - eight: u8, - seven: u8, - six: u8, - five: u8, - four: u8, - three: u8, - two: u8, - joker: u8, +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct Hand { + formation: Formation, + cards: [Card; 5], } -impl UnorderedHand { - fn determine_formation(&self) -> Formation { - let amounts = self.get_vec_of_amounts(); - let types = amounts.len(); - let max_of_type = *amounts.iter().max().unwrap_or(&0) + self.joker; +impl Hand { + pub fn new(cards: [Card; 5]) -> Hand { + Hand { + formation: Self::determine_formation(&cards), + cards, + } + } + fn determine_formation(cards: &[Card; 5]) -> Formation { + let mut counts = cards.iter().counts(); + let jokers = counts.remove(&Card::Joker).unwrap_or(0); + let types = counts.len(); + let max_of_type = counts.into_values().max().unwrap_or(0) + jokers; match types { // if 0 types, they are all joker. 0 => Formation::FiveOfKind, @@ -63,7 +59,7 @@ impl UnorderedHand { match max_of_type { 4 => Formation::FourOfKind, 3 => Formation::FullHouse, - _ => panic!("idk what type of hand this is: {:?}", self), + _ => panic!("idk what type of hand this is: {:?}", cards), } } 3 => { @@ -71,7 +67,7 @@ impl UnorderedHand { match max_of_type { 3 => Formation::ThreeOfKind, 2 => Formation::TwoPair, - _ => panic!("idk what type of hand this is: {:?}", self), + _ => panic!("idk what type of hand this is: {:?}", cards), } } 4 => Formation::OnePair, @@ -79,114 +75,10 @@ impl UnorderedHand { _ => panic!("how are there more than 5 types!"), } } - // just to make iteration easier - fn get_vec_of_amounts(&self) -> Vec { - let mut ret = Vec::new(); - if self.ace > 0 { - ret.push(self.ace); - } - if self.king > 0 { - ret.push(self.king); - } - if self.queen > 0 { - ret.push(self.queen); - } - if self.jack > 0 { - ret.push(self.jack); - } - if self.tim > 0 { - ret.push(self.tim); - } - if self.nine > 0 { - ret.push(self.nine); - } - if self.eight > 0 { - ret.push(self.eight); - } - if self.seven > 0 { - ret.push(self.seven); - } - if self.six > 0 { - ret.push(self.six); - } - if self.five > 0 { - ret.push(self.five); - } - if self.four > 0 { - ret.push(self.four); - } - if self.three > 0 { - ret.push(self.three); - } - if self.two > 0 { - ret.push(self.two); - } - ret - } -} - -#[derive(Debug, PartialEq, Eq)] -pub struct Hand { - pub cards: [Card; 5], - unordered_hand: UnorderedHand, -} - -impl Hand { - pub fn new(cards: [Card; 5]) -> Hand { - Hand { - unordered_hand: Self::get_unordered_hand(&cards), - cards, - } - } - pub fn determine_formation(&self) -> Formation { - self.unordered_hand.determine_formation() - } - fn get_unordered_hand(cards: &[Card]) -> UnorderedHand { - cards - .iter() - .fold(UnorderedHand::default(), |mut acc, card| { - match card { - Card::Ace => acc.ace += 1, - Card::King => acc.king += 1, - Card::Queen => acc.queen += 1, - Card::Jack => acc.jack += 1, - Card::Tim => acc.tim += 1, - Card::Nine => acc.nine += 1, - Card::Eight => acc.eight += 1, - Card::Seven => acc.seven += 1, - Card::Six => acc.six += 1, - Card::Five => acc.five += 1, - Card::Four => acc.four += 1, - Card::Three => acc.three += 1, - Card::Two => acc.two += 1, - Card::Joker => acc.joker += 1, - }; - acc - }) - } - pub fn turn_jacks_to_jokers(&self) -> Hand { - Hand::new( - self.cards - .map(|c| if c == Card::Jack { Card::Joker } else { c }), - ) - } -} - -impl Ord for Hand { - fn cmp(&self, other: &Self) -> std::cmp::Ordering { - let self_formation = self.determine_formation(); - let other_formation = other.determine_formation(); - if self_formation != other_formation { - self_formation.cmp(&other_formation) - } else { - self.cards.cmp(&other.cards) - } - } -} - -impl PartialOrd for Hand { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) + pub fn turn_jacks_to_jokers(&mut self) { + self.cards = self + .cards + .map(|c| if c == Card::Jack { Card::Joker } else { c }); } } @@ -339,10 +231,7 @@ mod tests { 41, ), ]; - input = input - .into_iter() - .map(|c| (c.0.turn_jacks_to_jokers(), c.1)) - .collect(); + input.iter_mut().for_each(|i| i.0.turn_jacks_to_jokers()); input.sort_by(|a, b| a.0.cmp(&b.0)); println!("{:#?}", input); //check that the bids are sorted (the input is curated to ensure that the bids are sorted @@ -460,12 +349,9 @@ mod tests { Formation::FiveOfKind, ), ]; - tests = tests - .into_iter() - .map(|c| (c.0.turn_jacks_to_jokers(), c.1)) - .collect(); + tests.iter_mut().for_each(|i| i.0.turn_jacks_to_jokers()); for test in tests { - assert_eq!(test.0.determine_formation(), test.1) + assert_eq!(test.0.formation, test.1) } } @@ -650,7 +536,7 @@ mod tests { ), ]; for test in tests { - assert_eq!(test.0.determine_formation(), test.1) + assert_eq!(test.0.formation, test.1) } } diff --git a/days/day07/src/part2.rs b/days/day07/src/part2.rs index c6c1ccd..aebc04a 100644 --- a/days/day07/src/part2.rs +++ b/days/day07/src/part2.rs @@ -1,10 +1,7 @@ use crate::parse::*; -pub fn part2(input: &[(Hand, u32)]) -> usize { - let mut input: Vec<(Hand, u32)> = input - .iter() - .map(|c| (c.0.turn_jacks_to_jokers(), c.1)) - .collect(); +pub fn part2(input: &mut [(Hand, u32)]) -> usize { + input.iter_mut().for_each(|i| i.0.turn_jacks_to_jokers()); input.sort_by(|a, b| a.0.cmp(&b.0) ); input .iter() @@ -19,7 +16,7 @@ mod tests { #[test] fn test_part2() { - let input = vec![ + let mut input = vec![ ( Hand::new([Card::Two, Card::Three, Card::Four, Card::Five, Card::Ace]), 1, @@ -127,6 +124,6 @@ mod tests { 41, ), ]; - assert_eq!(part2(&input), 6839); + assert_eq!(part2(&mut input), 6839); } }