feat: 2023 day seven

This commit is contained in:
Max Hohlfeld 2023-12-22 14:49:27 +01:00 committed by Max Hohlfeld
parent 0f5138df92
commit 27eb39cc0f
4 changed files with 1272 additions and 0 deletions

1000
src/aoc2023/day07/input.txt Normal file

File diff suppressed because it is too large Load Diff

270
src/aoc2023/day07/mod.rs Normal file
View File

@ -0,0 +1,270 @@
pub fn task_one(input: &str) -> String {
let mut hands = parse_input_task_one(&input);
hands.sort_by_key(|hand| hand.hand_type);
loop {
let mut swap_occured = false;
for i in 0..(hands.len() - 1) {
let current_element = hands[i].clone();
let next_element = &hands[i + 1].clone();
if current_element.hand_type != next_element.hand_type {
continue;
}
for j in 0..5 {
match current_element.cards[j].cmp(&next_element.cards[j]) {
std::cmp::Ordering::Greater => {
hands.swap(i, i + 1);
swap_occured = true;
break;
},
std::cmp::Ordering::Equal => continue,
std::cmp::Ordering::Less => break
}
}
}
if !swap_occured {
break;
}
}
hands.iter()
.enumerate()
.fold(0, |sum, (rank, hand)| sum + ((rank + 1) * hand.bid as usize))
.to_string()
}
pub fn task_two(input: &str) -> String {
let mut hands = parse_input_task_two(&input);
hands.sort_by_key(|hand| hand.hand_type);
loop {
let mut swap_occured = false;
for i in 0..(hands.len() - 1) {
let current_element = hands[i].clone();
let next_element = &hands[i + 1].clone();
if current_element.hand_type != next_element.hand_type {
continue;
}
for j in 0..5 {
match current_element.cards[j].cmp(&next_element.cards[j]) {
std::cmp::Ordering::Greater => {
hands.swap(i, i + 1);
swap_occured = true;
break;
},
std::cmp::Ordering::Equal => continue,
std::cmp::Ordering::Less => break
}
}
}
if !swap_occured {
break;
}
}
hands.iter()
.enumerate()
.fold(0, |sum, (rank, hand)| sum + ((rank + 1) * hand.bid as usize))
.to_string()
}
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
enum HandType {
FiveOfAKind = 6,
FourOfAKind = 5,
FullHouse = 4,
ThreeOfAKind = 3,
TwoPair = 2,
OnePair = 1,
HighCard = 0
}
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone)]
enum Card {
Ass = 14,
King = 13,
Queen = 12,
Junior = 11,
Ten = 10,
Nine = 9,
Eight = 8,
Seven = 7,
Six = 6,
Five = 5,
Four = 4,
Three = 3,
Two = 2
}
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone)]
enum JokerCard {
Ass = 14,
King = 13,
Queen = 12,
Ten = 10,
Nine = 9,
Eight = 8,
Seven = 7,
Six = 6,
Five = 5,
Four = 4,
Three = 3,
Two = 2,
Joker = 1
}
impl From<char> for Card {
fn from(value: char) -> Self {
match value {
'A' => Card::Ass,
'K' => Card::King,
'Q' => Card::Queen,
'J' => Card::Junior,
'T' => Card::Ten,
'9' => Card::Nine,
'8' => Card::Eight,
'7' => Card::Seven,
'6' => Card::Six,
'5' => Card::Five,
'4' => Card::Four,
'3' => Card::Three,
'2' => Card::Two,
_ => panic!("Found {}", value)
}
}
}
impl From<char> for JokerCard{
fn from(value: char) -> Self {
match value {
'A' => JokerCard::Ass,
'K' => JokerCard::King,
'Q' => JokerCard::Queen,
'T' => JokerCard::Ten,
'9' => JokerCard::Nine,
'8' => JokerCard::Eight,
'7' => JokerCard::Seven,
'6' => JokerCard::Six,
'5' => JokerCard::Five,
'4' => JokerCard::Four,
'3' => JokerCard::Three,
'2' => JokerCard::Two,
'J' => JokerCard::Joker,
_ => panic!("Found {}", value)
}
}
}
#[derive(Clone)]
struct Hand {
cards: Vec<Card>,
bid: u32,
hand_type: HandType
}
#[derive(Clone)]
struct JokerHand {
cards: Vec<JokerCard>,
bid: u32,
hand_type: HandType
}
fn parse_input_task_one(input: &str) -> Vec<Hand> {
let mut hands = Vec::new();
for line in input.lines() {
let (cards, bid_string) = line.split_once(" ").unwrap();
let mut hand_type = HandType::HighCard;
let pairs = count_cards(cards);
if pairs.iter().find(|pair| pair.1 == 5).is_some() {
hand_type = HandType::FiveOfAKind;
} else if pairs.iter().find(|pair| pair.1 == 4).is_some() {
hand_type = HandType::FourOfAKind;
} else if pairs.iter().find(|pair| pair.1 == 3).is_some() && pairs.iter().find(|pair| pair.1 == 2).is_some() {
hand_type = HandType::FullHouse;
} else if pairs.iter().find(|pair| pair.1 == 3).is_some() {
hand_type = HandType::ThreeOfAKind;
} else if pairs.iter().filter(|pair| pair.1 == 2).count() == 2 {
hand_type = HandType::TwoPair;
} else if pairs.iter().filter(|pair| pair.1 == 2).count() == 1 {
hand_type = HandType::OnePair;
}
hands.push(Hand { cards: cards.chars().into_iter().map(|c| c.into()).collect(), bid: bid_string.parse().unwrap(), hand_type })
}
hands
}
fn parse_input_task_two(input: &str) -> Vec<JokerHand> {
let mut hands = Vec::new();
for line in input.lines() {
let (cards, bid_string) = line.split_once(" ").unwrap();
let mut hand_type = HandType::HighCard;
let mut pairs = count_cards(cards);
let amount_of_joker = pairs.iter().find(|pair| pair.0 == 'J').unwrap_or(&('J', 0)).1;
pairs.retain(|pair| pair.0 != 'J');
pairs.sort_by_key(|pair| pair.1);
pairs.reverse();
if let Some(first_pair) = pairs.first_mut() {
first_pair.1 += amount_of_joker;
}
if amount_of_joker == 5 || pairs.iter().find(|pair| pair.1 == 5).is_some() {
hand_type = HandType::FiveOfAKind;
} else if pairs.iter().find(|pair| pair.1 == 4).is_some() {
hand_type = HandType::FourOfAKind;
} else if pairs.iter().find(|pair| pair.1 == 3).is_some() && pairs.iter().find(|pair| pair.1 == 2).is_some() {
hand_type = HandType::FullHouse;
} else if pairs.iter().find(|pair| pair.1 == 3).is_some() {
hand_type = HandType::ThreeOfAKind;
} else if pairs.iter().filter(|pair| pair.1 == 2).count() == 2 {
hand_type = HandType::TwoPair;
} else if pairs.iter().filter(|pair| pair.1 == 2).count() == 1 {
hand_type = HandType::OnePair;
}
hands.push(JokerHand { cards: cards.chars().into_iter().map(|c| c.into()).collect(), bid: bid_string.parse().unwrap(), hand_type })
}
hands
}
fn count_cards(input: &str) -> Vec<(char, u8)> {
let mut result: Vec<(char, u8)> = Vec::new();
for char in input.chars() {
if let Some(entry) = result.iter_mut().find(|pair| pair.0 == char) {
entry.1 += 1;
} else {
result.push((char, 1));
}
}
result
}
#[test]
fn test_task_two() {
let input = r##"32T3K 765
T55J5 684
KK677 28
KTJJT 220
QQQJA 483"##;
let result = task_two(&input);
assert_eq!(result, "5905");
}

View File

@ -3,3 +3,4 @@ pub mod day02;
pub mod day03;
pub mod day04;
pub mod day06;
pub mod day07;

View File

@ -50,6 +50,7 @@ fn main() {
puzzles.push(Puzzle { day: 3, year: 2023, task_one: aoc2023::day03::task_one, task_two: aoc2023::day03::task_two });
puzzles.push(Puzzle { day: 4, year: 2023, task_one: aoc2023::day04::task_one, task_two: aoc2023::day04::task_two });
puzzles.push(Puzzle { day: 6, year: 2023, task_one: aoc2023::day06::task_one, task_two: aoc2023::day06::task_two });
puzzles.push(Puzzle { day: 7, year: 2023, task_one: aoc2023::day07::task_one, task_two: aoc2023::day07::task_two });
puzzles.iter().for_each(|puzzle| puzzle.solve_and_print());
}