generated from janezicmatej/aoc-template
	solution: day 7 clean
This commit is contained in:
		
							
								
								
									
										5
									
								
								data/examples/07.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								data/examples/07.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
32T3K 765
 | 
			
		||||
T55J5 684
 | 
			
		||||
KK677 28
 | 
			
		||||
KTJJT 220
 | 
			
		||||
QQQJA 483
 | 
			
		||||
							
								
								
									
										191
									
								
								src/bin/07.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										191
									
								
								src/bin/07.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,191 @@
 | 
			
		||||
use std::{cmp::Ordering, collections::HashMap, str::FromStr};
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
 | 
			
		||||
enum Label {
 | 
			
		||||
    Ace = 14,
 | 
			
		||||
    King = 13,
 | 
			
		||||
    Queen = 12,
 | 
			
		||||
    Jack = 11,
 | 
			
		||||
    Ten = 10,
 | 
			
		||||
    Nine = 9,
 | 
			
		||||
    Eight = 8,
 | 
			
		||||
    Seven = 7,
 | 
			
		||||
    Six = 6,
 | 
			
		||||
    Five = 5,
 | 
			
		||||
    Four = 4,
 | 
			
		||||
    Three = 3,
 | 
			
		||||
    Two = 2,
 | 
			
		||||
    Joker = 1,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<char> for Label {
 | 
			
		||||
    fn from(value: char) -> Self {
 | 
			
		||||
        use Label::*;
 | 
			
		||||
        match value {
 | 
			
		||||
            'A' => Ace,
 | 
			
		||||
            'K' => King,
 | 
			
		||||
            'Q' => Queen,
 | 
			
		||||
            'J' => Jack,
 | 
			
		||||
            'T' => Ten,
 | 
			
		||||
            '9' => Nine,
 | 
			
		||||
            '8' => Eight,
 | 
			
		||||
            '7' => Seven,
 | 
			
		||||
            '6' => Six,
 | 
			
		||||
            '5' => Five,
 | 
			
		||||
            '4' => Four,
 | 
			
		||||
            '3' => Three,
 | 
			
		||||
            '2' => Two,
 | 
			
		||||
            'X' => Joker,
 | 
			
		||||
            _ => unreachable!(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
struct ParseHandError;
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
 | 
			
		||||
struct Hand {
 | 
			
		||||
    labels: [Label; 5],
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl FromStr for Hand {
 | 
			
		||||
    type Err = ParseHandError;
 | 
			
		||||
    fn from_str(s: &str) -> Result<Self, Self::Err> {
 | 
			
		||||
        let labels = s
 | 
			
		||||
            .chars()
 | 
			
		||||
            .map(Label::from)
 | 
			
		||||
            .collect::<Vec<_>>()
 | 
			
		||||
            .try_into()
 | 
			
		||||
            .map_err(|_| ParseHandError)?;
 | 
			
		||||
        Ok(Hand { labels })
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl PartialOrd for Hand {
 | 
			
		||||
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
 | 
			
		||||
        Some(self.cmp(other))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Ord for Hand {
 | 
			
		||||
    fn cmp(&self, other: &Self) -> Ordering {
 | 
			
		||||
        let sf = HandType::from(*self);
 | 
			
		||||
        let so = HandType::from(*other);
 | 
			
		||||
 | 
			
		||||
        sf.cmp(&so).then({
 | 
			
		||||
            let mut c = Ordering::Equal;
 | 
			
		||||
            for i in 0..5 {
 | 
			
		||||
                c = self.labels[i].cmp(&other.labels[i]);
 | 
			
		||||
                if c != Ordering::Equal {
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            c
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
 | 
			
		||||
enum HandType {
 | 
			
		||||
    Five = 6,
 | 
			
		||||
    Four = 5,
 | 
			
		||||
    FullHouse = 4,
 | 
			
		||||
    Three = 3,
 | 
			
		||||
    TwoPair = 2,
 | 
			
		||||
    Pair = 1,
 | 
			
		||||
    HighCard = 0,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<Hand> for HandType {
 | 
			
		||||
    fn from(value: Hand) -> Self {
 | 
			
		||||
        let mut map = HashMap::new();
 | 
			
		||||
 | 
			
		||||
        for c in value.labels {
 | 
			
		||||
            *map.entry(c).or_insert(0) += 1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let joker = map.remove(&Label::Joker).unwrap_or(0);
 | 
			
		||||
 | 
			
		||||
        let is_n_k = |n| joker == n || map.values().filter(|&x| *x == n - joker).count() > 0;
 | 
			
		||||
 | 
			
		||||
        if is_n_k(5) {
 | 
			
		||||
            return Self::Five;
 | 
			
		||||
        }
 | 
			
		||||
        if is_n_k(4) {
 | 
			
		||||
            return Self::Four;
 | 
			
		||||
        }
 | 
			
		||||
        // full house
 | 
			
		||||
        if map.values().count() <= 2 {
 | 
			
		||||
            return Self::FullHouse;
 | 
			
		||||
        }
 | 
			
		||||
        if is_n_k(3) {
 | 
			
		||||
            return Self::Three;
 | 
			
		||||
        }
 | 
			
		||||
        // two pair
 | 
			
		||||
        if map.values().count() <= 3 {
 | 
			
		||||
            return Self::TwoPair;
 | 
			
		||||
        }
 | 
			
		||||
        if is_n_k(2) {
 | 
			
		||||
            return Self::Pair;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Self::HighCard
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn part_one(input: &str) -> Option<u32> {
 | 
			
		||||
    let mut v = input
 | 
			
		||||
        .lines()
 | 
			
		||||
        .filter_map(|l| l.split_once(' '))
 | 
			
		||||
        .map(|(f, s)| (f.parse::<Hand>().unwrap(), s.parse::<u32>().unwrap()))
 | 
			
		||||
        .collect::<Vec<_>>();
 | 
			
		||||
 | 
			
		||||
    v.sort_by(|f, o| f.0.cmp(&o.0));
 | 
			
		||||
 | 
			
		||||
    Some(
 | 
			
		||||
        v.into_iter()
 | 
			
		||||
            .enumerate()
 | 
			
		||||
            .map(|(i, x)| (i as u32 + 1) * x.1)
 | 
			
		||||
            .sum::<u32>(),
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn part_two(input: &str) -> Option<u32> {
 | 
			
		||||
    let mut v = input
 | 
			
		||||
        .replace('J', "X")
 | 
			
		||||
        .lines()
 | 
			
		||||
        .filter_map(|l| l.split_once(' '))
 | 
			
		||||
        .map(|(f, s)| (f.parse::<Hand>().unwrap(), s.parse::<u32>().unwrap()))
 | 
			
		||||
        .collect::<Vec<_>>();
 | 
			
		||||
 | 
			
		||||
    v.sort_by(|f, o| f.0.cmp(&o.0));
 | 
			
		||||
 | 
			
		||||
    Some(
 | 
			
		||||
        v.into_iter()
 | 
			
		||||
            .enumerate()
 | 
			
		||||
            .map(|(i, x)| (i as u32 + 1) * x.1)
 | 
			
		||||
            .sum::<u32>(),
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
aoc::solution!(7);
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod tests {
 | 
			
		||||
    use super::*;
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_part_one() {
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            part_one(&aoc::template::read_file("examples", 7)),
 | 
			
		||||
            Some(6440)
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_part_two() {
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            part_two(&aoc::template::read_file("examples", 7)),
 | 
			
		||||
            Some(5905)
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user