Day 7 aoc was a breeze
This commit is contained in:
7
advent_of_code/2023/7/Cargo.toml
Normal file
7
advent_of_code/2023/7/Cargo.toml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
[package]
|
||||||
|
name = "main"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
nom = "7.1.3"
|
||||||
1000
advent_of_code/2023/7/input.txt
Normal file
1000
advent_of_code/2023/7/input.txt
Normal file
File diff suppressed because it is too large
Load Diff
263
advent_of_code/2023/7/src/main.rs
Normal file
263
advent_of_code/2023/7/src/main.rs
Normal file
@@ -0,0 +1,263 @@
|
|||||||
|
use std::{cmp::Ordering, collections::HashMap, iter::zip};
|
||||||
|
|
||||||
|
use nom::{
|
||||||
|
character::complete::{alphanumeric1, multispace1, u64},
|
||||||
|
multi::separated_list1,
|
||||||
|
sequence::separated_pair,
|
||||||
|
IResult, Parser,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
enum HandType {
|
||||||
|
HighCard,
|
||||||
|
OnePair,
|
||||||
|
TwoPair,
|
||||||
|
ThreeKind,
|
||||||
|
FullHouse,
|
||||||
|
FourKind,
|
||||||
|
FiveKind,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
enum CardType {
|
||||||
|
Two,
|
||||||
|
Three,
|
||||||
|
Four,
|
||||||
|
Five,
|
||||||
|
Six,
|
||||||
|
Seven,
|
||||||
|
Eight,
|
||||||
|
Nine,
|
||||||
|
T,
|
||||||
|
Jack,
|
||||||
|
Queen,
|
||||||
|
King,
|
||||||
|
Ace,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
enum CardType2 {
|
||||||
|
Jack,
|
||||||
|
Two,
|
||||||
|
Three,
|
||||||
|
Four,
|
||||||
|
Five,
|
||||||
|
Six,
|
||||||
|
Seven,
|
||||||
|
Eight,
|
||||||
|
Nine,
|
||||||
|
T,
|
||||||
|
Queen,
|
||||||
|
King,
|
||||||
|
Ace,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_input(input: &str) -> IResult<&str, Vec<(String, u64)>> {
|
||||||
|
let (input, result) = separated_list1(
|
||||||
|
multispace1,
|
||||||
|
separated_pair(alphanumeric1::<&str, _>, multispace1, u64)
|
||||||
|
.map(|(hand, bid)| (hand.to_string(), bid)),
|
||||||
|
)(input)?;
|
||||||
|
|
||||||
|
Ok((input, result))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn classify_hand(hand: &String) -> HandType {
|
||||||
|
use HandType::*;
|
||||||
|
|
||||||
|
let mut card_numbers: HashMap<char, i32> = HashMap::new();
|
||||||
|
for c in hand.to_owned().chars() {
|
||||||
|
card_numbers.insert(
|
||||||
|
c,
|
||||||
|
match card_numbers.get(&c) {
|
||||||
|
Some(n) => n + 1,
|
||||||
|
None => 1,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut card_numbers = card_numbers.values().collect::<Vec<_>>();
|
||||||
|
card_numbers.sort_unstable();
|
||||||
|
match card_numbers[..] {
|
||||||
|
[1, 1, 1, 1, 1] => HighCard,
|
||||||
|
[1, 1, 1, 2] => OnePair,
|
||||||
|
[1, 2, 2] => TwoPair,
|
||||||
|
[1, 1, 3] => ThreeKind,
|
||||||
|
[2, 3] => FullHouse,
|
||||||
|
[1, 4] => FourKind,
|
||||||
|
[5] => FiveKind,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn classify_hand2(hand: &String) -> HandType {
|
||||||
|
use HandType::*;
|
||||||
|
|
||||||
|
let mut card_numbers: HashMap<char, i32> = HashMap::new();
|
||||||
|
for c in hand.to_owned().chars() {
|
||||||
|
card_numbers.insert(
|
||||||
|
c,
|
||||||
|
match card_numbers.get(&c) {
|
||||||
|
Some(n) => n + 1,
|
||||||
|
None => 1,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(jokers) = card_numbers.remove(&'J') {
|
||||||
|
let mut card_numbers = card_numbers.values().collect::<Vec<_>>();
|
||||||
|
card_numbers.sort_unstable();
|
||||||
|
let highest = card_numbers.pop().unwrap_or(&0) + jokers;
|
||||||
|
card_numbers.push(&highest);
|
||||||
|
|
||||||
|
match card_numbers[..] {
|
||||||
|
[1, 1, 1, 2] => OnePair,
|
||||||
|
[1, 1, 3] => ThreeKind,
|
||||||
|
[2, 3] => FullHouse,
|
||||||
|
[1, 4] => FourKind,
|
||||||
|
[5] => FiveKind,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let mut card_numbers = card_numbers.values().collect::<Vec<_>>();
|
||||||
|
card_numbers.sort_unstable();
|
||||||
|
match card_numbers[..] {
|
||||||
|
[1, 1, 1, 1, 1] => HighCard,
|
||||||
|
[1, 1, 1, 2] => OnePair,
|
||||||
|
[1, 2, 2] => TwoPair,
|
||||||
|
[1, 1, 3] => ThreeKind,
|
||||||
|
[2, 3] => FullHouse,
|
||||||
|
[1, 4] => FourKind,
|
||||||
|
[5] => FiveKind,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn classify_card(card: char) -> CardType {
|
||||||
|
use CardType::*;
|
||||||
|
|
||||||
|
match card {
|
||||||
|
'A' => Ace,
|
||||||
|
'K' => King,
|
||||||
|
'Q' => Queen,
|
||||||
|
'J' => Jack,
|
||||||
|
'T' => T,
|
||||||
|
'9' => Nine,
|
||||||
|
'8' => Eight,
|
||||||
|
'7' => Seven,
|
||||||
|
'6' => Six,
|
||||||
|
'5' => Five,
|
||||||
|
'4' => Four,
|
||||||
|
'3' => Three,
|
||||||
|
'2' => Two,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn classify_card2(card: char) -> CardType2 {
|
||||||
|
use CardType2::*;
|
||||||
|
|
||||||
|
match card {
|
||||||
|
'A' => Ace,
|
||||||
|
'K' => King,
|
||||||
|
'Q' => Queen,
|
||||||
|
'T' => T,
|
||||||
|
'9' => Nine,
|
||||||
|
'8' => Eight,
|
||||||
|
'7' => Seven,
|
||||||
|
'6' => Six,
|
||||||
|
'5' => Five,
|
||||||
|
'4' => Four,
|
||||||
|
'3' => Three,
|
||||||
|
'2' => Two,
|
||||||
|
'J' => Jack,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compare_hands(hand_1: &String, hand_2: &String) -> Ordering {
|
||||||
|
let (hand_type_1, hand_type_2) = (classify_hand(hand_1), classify_hand(hand_2));
|
||||||
|
if hand_type_1 == hand_type_2 {
|
||||||
|
for (card_1, card_2) in zip(hand_1.to_owned().chars(), hand_2.to_owned().chars()) {
|
||||||
|
if card_1 != card_2 {
|
||||||
|
return classify_card(card_1).cmp(&classify_card(card_2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ordering::Equal
|
||||||
|
} else {
|
||||||
|
hand_type_1.cmp(&hand_type_2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compare_hands2(hand_1: &String, hand_2: &String) -> Ordering {
|
||||||
|
let (hand_type_1, hand_type_2) = (classify_hand2(hand_1), classify_hand2(hand_2));
|
||||||
|
if hand_type_1 == hand_type_2 {
|
||||||
|
for (card_1, card_2) in zip(hand_1.to_owned().chars(), hand_2.to_owned().chars()) {
|
||||||
|
if card_1 != card_2 {
|
||||||
|
return classify_card2(card_1).cmp(&classify_card2(card_2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ordering::Equal
|
||||||
|
} else {
|
||||||
|
hand_type_1.cmp(&hand_type_2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn solve_1(plays: &Vec<(String, u64)>) -> u64 {
|
||||||
|
let mut plays = plays.clone();
|
||||||
|
|
||||||
|
plays.sort_unstable_by(|(hand_1, _bid1), (hand_2, _bid2)| compare_hands(hand_1, hand_2));
|
||||||
|
|
||||||
|
plays
|
||||||
|
.into_iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(rank, (_hand, bid))| (rank as u64 + 1) * bid)
|
||||||
|
.sum()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn solve_2(plays: &Vec<(String, u64)>) -> u64 {
|
||||||
|
let mut plays = plays.clone();
|
||||||
|
|
||||||
|
plays.sort_unstable_by(|(hand_1, _bid1), (hand_2, _bid2)| compare_hands2(hand_1, hand_2));
|
||||||
|
|
||||||
|
plays
|
||||||
|
.into_iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(rank, (_hand, bid))| (rank as u64 + 1) * bid)
|
||||||
|
.sum()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
println!("Hello, this is Patrick!");
|
||||||
|
|
||||||
|
let input_text = include_str!("../input.txt");
|
||||||
|
|
||||||
|
let (_, plays) = parse_input(input_text).unwrap();
|
||||||
|
|
||||||
|
println!("The total winnings are {}", solve_1(&plays));
|
||||||
|
println!("The new total winnings are {}", solve_2(&plays));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_1() {
|
||||||
|
let input_text = include_str!("../test_input.txt");
|
||||||
|
|
||||||
|
let (_, plays) = parse_input(input_text).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(solve_1(&plays), 6440);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_2() {
|
||||||
|
let input_text = include_str!("../test_input.txt");
|
||||||
|
|
||||||
|
let (_, plays) = parse_input(input_text).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(solve_2(&plays), 5905);
|
||||||
|
}
|
||||||
|
}
|
||||||
5
advent_of_code/2023/7/test_input.txt
Normal file
5
advent_of_code/2023/7/test_input.txt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
32T3K 765
|
||||||
|
T55J5 684
|
||||||
|
KK677 28
|
||||||
|
KTJJT 220
|
||||||
|
QQQJA 483
|
||||||
Reference in New Issue
Block a user