Advent of Code 2023 - DAY 7

fushji

Antonio Perrone

Posted on December 14, 2023

Advent of Code 2023 - DAY 7

Problem Day 7: Camel Cards

Here the day 7 problem statement: https://adventofcode.com/2023/day/7

Solution Part 1

enum HandType {
    FiveOfAKind,
    FourOfAKind,
    FullHouse,
    ThreeOfAKind,
    TwoPairs,
    OnePair,
    HighCard,
}

fn card_to_rank(card: char) -> usize {
    match card {
        '2' => 0,
        '3' => 1,
        '4' => 2,
        '5' => 3,
        '6' => 4,
        '7' => 5,
        '8' => 6,
        '9' => 7,
        'T' => 8,
        'J' => 9,
        'Q' => 10,
        'K' => 11,
        'A' => 12,
        _ => panic!("bad"),
    }
}

fn get_hand_type(hand: Hand) -> HandType {
    let mut sorted_hand = hand.ranks;
    sorted_hand.sort_by(|a, b| b.cmp(a));
    match sorted_hand[0] {
        5 => HandType::FiveOfAKind,
        4 => HandType::FourOfAKind,
        3 => {
            if sorted_hand[1] == 2 {
                HandType::FullHouse
            } else {
                HandType::ThreeOfAKind
            }
        }

        2 => {
            if sorted_hand[1] == 2 {
                HandType::TwoPairs
            } else {
                HandType::OnePair
            }
        }
        1 | 0 => HandType::HighCard,

        _ => panic!("Invalid Hand"),
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct Hand {
    cards: [usize; 5],
    score: u32,
    ranks: [u8; 13],
}

impl Hand {
    fn new(hand: &str, score: u32) -> Self {
        let mut ranks = [0; 13];
        let mut cards = [0; 5];

        for (i, card) in hand.chars().enumerate() {
            ranks[card_to_rank(card)] += 1;
            cards[i] = card_to_rank(card);
        }

        Self {
            cards,
            score,
            ranks,
        }
    }
}

impl PartialOrd for Hand {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        match get_hand_type(*self).cmp(&get_hand_type(*other)) {
            Ordering::Equal => Some(self.cards.cmp(&other.cards).reverse()),
            ord => Some(ord),
        }
    }
}
impl Ord for Hand {
    fn cmp(&self, other: &Self) -> Ordering {
        self.partial_cmp(other).unwrap()
    }
}

pub fn part_one(input: &str) -> Option<u32> {
    let mut hands: Vec<Hand> = input
        .lines()
        .map(|line| {
            let (hand, score) = line.split(' ').collect_tuple().unwrap();
            Hand::new(hand, score.parse().unwrap())
        })
        .collect();

    hands.sort_by(|h1, h2| h2.cmp(h1));
    let score: u32 = hands
        .iter()
        .enumerate()
        .map(|(idx, hand)| (idx as u32 + 1) * hand.score)
        .sum();

    Some(score)
}

Enter fullscreen mode Exit fullscreen mode

Solution Part 2

enum HandType {
    FiveOfAKind,
    FourOfAKind,
    FullHouse,
    ThreeOfAKind,
    TwoPairs,
    OnePair,
    HighCard,
}

fn card_to_rank_2(card: char) -> usize {
    match card {
        'J' => 0,
        '2' => 1,
        '3' => 2,
        '4' => 3,
        '5' => 4,
        '6' => 5,
        '7' => 6,
        '8' => 7,
        '9' => 8,
        'T' => 9,
        'Q' => 10,
        'K' => 11,
        'A' => 12,
        _ => panic!("bad"),
    }
}

fn get_hand_type_2(hand: Hand2) -> HandType {
    let mut sorted_hand = hand.ranks;
    sorted_hand.sort_by(|a, b| b.cmp(a));
    match sorted_hand[0] {
        5 => HandType::FiveOfAKind,
        4 => HandType::FourOfAKind,
        3 => {
            if sorted_hand[1] == 2 {
                HandType::FullHouse
            } else {
                HandType::ThreeOfAKind
            }
        }

        2 => {
            if sorted_hand[1] == 2 {
                HandType::TwoPairs
            } else {
                HandType::OnePair
            }
        }
        1 | 0 => HandType::HighCard,

        _ => panic!("Invalid Hand"),
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct Hand2 {
    cards: [usize; 5],
    score: u32,
    ranks: [u8; 13],
}

impl Hand2 {
    fn new(hand: &str, score: u32) -> Self {
        let mut ranks = [0; 13];
        let mut cards = [0; 5];

        for (i, card) in hand.chars().enumerate() {
            ranks[card_to_rank_2(card)] += 1;
            cards[i] = card_to_rank_2(card);
        }

        Self {
            cards,
            score,
            ranks,
        }
    }
}

impl PartialOrd for Hand2 {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        match get_hand_type_2(*self).cmp(&get_hand_type_2(*other)) {
            Ordering::Equal => Some(self.cards.cmp(&other.cards).reverse()),
            ord => Some(ord),
        }
    }
}
impl Ord for Hand2 {
    fn cmp(&self, other: &Self) -> Ordering {
        self.partial_cmp(other).unwrap()
    }
}

fn apply_j(hand: &mut Hand2) {
    let j = hand.ranks[0];

    match get_hand_type_2(*hand) {
        HandType::FiveOfAKind => {
            hand.ranks[0] = 0;
            hand.ranks[12] = 5;
        }
        HandType::FourOfAKind => {
            let mut max_rank_index = 1;
            for i in 1..13 {
                if hand.ranks[i] >= hand.ranks[max_rank_index] {
                    max_rank_index = i
                }
            }
            hand.ranks[0] = 0;
            hand.ranks[max_rank_index] = 5;
        }
        HandType::FullHouse => {
            let mut max_rank_index = 1;
            for i in 1..13 {
                if hand.ranks[i] >= hand.ranks[max_rank_index] {
                    max_rank_index = i
                }
            }
            hand.ranks[0] = 0;
            hand.ranks[max_rank_index] += j;
        }
        HandType::ThreeOfAKind => {
            let mut max_rank_index = 1;
            for i in 1..13 {
                if hand.ranks[i] >= hand.ranks[max_rank_index] {
                    max_rank_index = i
                }
            }
            hand.ranks[0] = 0;
            hand.ranks[max_rank_index] += j;
        }
        HandType::TwoPairs => {
            let mut max_rank_index = 1;
            for i in 1..13 {
                if hand.ranks[i] >= hand.ranks[max_rank_index] {
                    max_rank_index = i
                }
            }
            hand.ranks[0] = 0;
            hand.ranks[max_rank_index] += j;
        }
        HandType::OnePair => {
            let mut max_rank_index = 1;
            for i in 1..13 {
                if hand.ranks[i] >= hand.ranks[max_rank_index] {
                    max_rank_index = i
                }
            }

            hand.ranks[0] = 0;
            hand.ranks[max_rank_index] += j;
        }
        HandType::HighCard => {
            let mut max_rank_index = 1;
            for i in 1..13 {
                if hand.ranks[i] >= hand.ranks[max_rank_index] {
                    max_rank_index = i
                }
            }
            hand.ranks[0] = 0;
            hand.ranks[max_rank_index] += j;
        }
    }
}

pub fn part_two(input: &str) -> Option<u32> {
    let mut hands: Vec<Hand2> = input
        .lines()
        .map(|line| {
            let (hand, score) = line.split(' ').collect_tuple().unwrap();
            Hand2::new(hand, score.parse().unwrap())
        })
        .collect();

    hands.iter_mut().for_each(|h| {
        if h.ranks[0] > 0 {
            apply_j(h)
        }
    });

    hands.sort_by(|h1, h2| h2.cmp(h1));
    let score: u32 = hands
        .iter()
        .enumerate()
        .map(|(idx, hand)| (idx as u32 + 1) * hand.score)
        .sum();

    Some(score)
}
Enter fullscreen mode Exit fullscreen mode

Here the repository with all puzzle solutions.

💖 💪 🙅 🚩
fushji
Antonio Perrone

Posted on December 14, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Advent of Code 2023 - DAY 11
rust Advent of Code 2023 - DAY 11

January 3, 2024

Advent of Code 2023 - DAY 9
rust Advent of Code 2023 - DAY 9

December 18, 2023

Advent of Code 2023 - DAY 8
rust Advent of Code 2023 - DAY 8

December 15, 2023

Advent of Code 2023 - DAY 7
rust Advent of Code 2023 - DAY 7

December 14, 2023

Advent of Code 2023 - DAY 6
rust Advent of Code 2023 - DAY 6

December 12, 2023