diff --git a/Cargo.lock b/Cargo.lock index b6f8e0e..63a06ff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -49,3 +49,11 @@ version = "0.1.0" [[package]] name = "d06t2" version = "0.1.0" + +[[package]] +name = "d07t1" +version = "0.1.0" + +[[package]] +name = "d07t2" +version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 64700a7..cd69937 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,4 +14,6 @@ members = [ "d05t2", "d06t1", "d06t2", + "d07t1", + "d07t2", ] diff --git a/d07t1/Cargo.toml b/d07t1/Cargo.toml new file mode 100644 index 0000000..09ac912 --- /dev/null +++ b/d07t1/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "d07t1" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/d07t1/demo_input.txt b/d07t1/demo_input.txt new file mode 100644 index 0000000..bf2815e --- /dev/null +++ b/d07t1/demo_input.txt @@ -0,0 +1,5 @@ +32T3K 765 +T55J5 684 +KK677 28 +KTJJT 220 +QQQJA 483 \ No newline at end of file diff --git a/d07t1/src/main.rs b/d07t1/src/main.rs new file mode 100644 index 0000000..f6c666c --- /dev/null +++ b/d07t1/src/main.rs @@ -0,0 +1,85 @@ +use std::{cmp::Ordering, collections::HashMap, fs::read_to_string}; + +fn main() { + let input = read_to_string("input.txt").unwrap(); + println!("d07t1: {}", d07t1(&input)); +} + +pub struct Card(String, usize); + +pub fn d07t1(input: &str) -> usize { + let mut cards = input + .lines() + .map(|line| line.split_once(' ')) + .map(Option::unwrap) + .map(|(cards, bet)| Card(cards.to_owned(), bet.parse::().unwrap())) + .collect::>(); + cards.sort_by(sort_card); + cards + .iter() + .enumerate() + .map(|(idx, card)| (idx + 1) * card.1) + .sum() +} + +pub fn sort_card(a: &Card, b: &Card) -> Ordering { + let set_rating_a = set_rating(&a.0); + let set_rating_b = set_rating(&b.0); + if set_rating_a.cmp(&set_rating_b) != Ordering::Equal { + return set_rating_a.cmp(&set_rating_b); + } + for (a, b) in a.0.chars().zip(b.0.chars()) { + let rank = card_ranking(a).cmp(&card_ranking(b)); + if rank != Ordering::Equal { + return rank; + } + } + Ordering::Equal +} + +fn set_rating(card: &str) -> usize { + let mut map: HashMap = HashMap::new(); + let chars = card.chars().collect::>(); + let mut unique_chars = chars.clone(); + unique_chars.dedup(); + for uc in &unique_chars { + map.insert(*uc, chars.iter().filter(|c| *c == uc).count()); + } + match map.len() { + 5 => 0, + 4 => 1, + 3 => *map.values().max().unwrap(), + 2 => *map.values().max().unwrap() + 1, + 1 => 6, + _ => unimplemented!(), + } +} + +fn card_ranking(c: char) -> usize { + match c { + '2' => 1, + '3' => 2, + '4' => 3, + '5' => 4, + '6' => 5, + '7' => 6, + '8' => 7, + '9' => 8, + 'T' => 9, + 'J' => 10, + 'Q' => 11, + 'K' => 12, + 'A' => 13, + _ => unimplemented!(), + } +} + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn test_d07t1() { + let input = include_str!("../demo_input.txt"); + assert_eq!(d07t1(input), 6440); + } +} diff --git a/d07t2/Cargo.toml b/d07t2/Cargo.toml new file mode 100644 index 0000000..44158e0 --- /dev/null +++ b/d07t2/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "d07t2" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/d07t2/demo_input.txt b/d07t2/demo_input.txt new file mode 100644 index 0000000..bf2815e --- /dev/null +++ b/d07t2/demo_input.txt @@ -0,0 +1,5 @@ +32T3K 765 +T55J5 684 +KK677 28 +KTJJT 220 +QQQJA 483 \ No newline at end of file diff --git a/d07t2/src/main.rs b/d07t2/src/main.rs new file mode 100644 index 0000000..a9b16dc --- /dev/null +++ b/d07t2/src/main.rs @@ -0,0 +1,115 @@ +use std::{cmp::Ordering, collections::HashMap, fs::read_to_string}; + +fn main() { + let input = read_to_string("input.txt").unwrap(); + println!("d07t2: {}", d07t2(&input)); +} + +#[derive(Debug)] +pub struct Cards { + cards: String, + bet: usize, + rating: usize, +} + +pub fn d07t2(input: &str) -> usize { + let mut cards = input + .lines() + .map(|line| line.split_once(' ')) + .map(Option::unwrap) + .map(|(cards, bet)| Cards { + cards: cards.to_owned(), + bet: bet.parse::().unwrap(), + rating: set_rating(cards), + }) + .collect::>(); + cards.sort_by(sort_cards); + cards + .iter() + .enumerate() + .map(|(idx, card)| (idx + 1) * card.bet) + .sum() +} + +pub fn sort_cards(a: &Cards, b: &Cards) -> Ordering { + if a.rating.cmp(&b.rating) != Ordering::Equal { + return a.rating.cmp(&b.rating); + } + for (a, b) in a.cards.chars().zip(b.cards.chars()) { + let rank = card_ranking(a).cmp(&card_ranking(b)); + if rank != Ordering::Equal { + return rank; + } + } + Ordering::Equal +} + +fn set_rating(card: &str) -> usize { + let mut optimal_card = String::from(card); + for i in 0..5 { + let c = optimal_card.chars().nth(i).unwrap(); + let options = match c { + 'J' => optimal_card.chars().collect(), + c => vec![c], + }; + let top_c = options + .into_iter() + .map(|opt| { + let mut check_card = optimal_card.clone(); + check_card.replace_range(i..=i, opt.to_string().as_str()); + (opt, rank_set(&check_card)) + }) + .max_by_key(|(_, rank)| *rank) + .unwrap() + .0; + optimal_card.replace_range(i..=i, top_c.to_string().as_str()); + } + + rank_set(&optimal_card) +} + +fn rank_set(card: &str) -> usize { + let mut chars: HashMap = HashMap::new(); + for c in card.chars() { + chars.insert(c, *chars.get(&c).unwrap_or(&1)); + } + let mut order: Vec = chars.clone().values().copied().collect(); + order.sort_by(|a, b| b.cmp(a)); + match chars.len() { + 1 => 6, + 2 => order[0] + 1, + 3 => order[0], + 4 => 1, + 5 => 0, + a => unimplemented!("{a}"), + } +} + +fn card_ranking(c: char) -> usize { + match c { + 'J' => 1, + '2' => 2, + '3' => 3, + '4' => 4, + '5' => 5, + '6' => 6, + '7' => 7, + '8' => 8, + '9' => 9, + 'T' => 10, + 'Q' => 11, + 'K' => 12, + 'A' => 13, + a => unimplemented!("{a}"), + } +} + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn test_d07t2() { + let input = include_str!("../demo_input.txt"); + assert_eq!(d07t2(input), 5905); + } +}