day7: problem 1 & 2 solutions
forgot to commit problem 1 only solution
This commit is contained in:
parent
9718b8ab04
commit
9ab450d258
7
7/Cargo.lock
generated
Normal file
7
7/Cargo.lock
generated
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "day7"
|
||||||
|
version = "0.1.0"
|
8
7/Cargo.toml
Normal file
8
7/Cargo.toml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
[package]
|
||||||
|
name = "day7"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
267
7/src/main.rs
Normal file
267
7/src/main.rs
Normal file
@ -0,0 +1,267 @@
|
|||||||
|
use std::fs::File;
|
||||||
|
use std::io::{BufRead, BufReader, Lines};
|
||||||
|
|
||||||
|
// BOILERPLATE
|
||||||
|
type InputIter = Lines<BufReader<File>>;
|
||||||
|
|
||||||
|
fn get_input() -> InputIter {
|
||||||
|
let f = File::open("input").unwrap();
|
||||||
|
let br = BufReader::new(f);
|
||||||
|
br.lines()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
println!("Problem 1 solution: {}", problem1(get_input()));
|
||||||
|
println!("Problem 2 solution: {}", problem2(get_input()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// PARSING
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Ord, Eq)]
|
||||||
|
enum Card {
|
||||||
|
TWO,
|
||||||
|
THREE,
|
||||||
|
FOUR,
|
||||||
|
FIVE,
|
||||||
|
SIX,
|
||||||
|
SEVEN,
|
||||||
|
EIGHT,
|
||||||
|
NINE,
|
||||||
|
T,
|
||||||
|
J,
|
||||||
|
Q,
|
||||||
|
K,
|
||||||
|
A,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Card {
|
||||||
|
const fn count() -> usize {
|
||||||
|
Card::A as usize + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, PartialOrd, Ord, Eq)]
|
||||||
|
enum HandType {
|
||||||
|
HighCard,
|
||||||
|
OnePair,
|
||||||
|
TwoPair,
|
||||||
|
ThreeOfAKind,
|
||||||
|
FullHouse,
|
||||||
|
FourOfAKind,
|
||||||
|
FiveOfAKind,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<char> for Card {
|
||||||
|
fn from(c: char) -> Self {
|
||||||
|
match c {
|
||||||
|
'A' => Self::A,
|
||||||
|
'K' => Self::K,
|
||||||
|
'Q' => Self::Q,
|
||||||
|
'J' => Self::J,
|
||||||
|
'T' => Self::T,
|
||||||
|
'9' => Self::NINE,
|
||||||
|
'8' => Self::EIGHT,
|
||||||
|
'7' => Self::SEVEN,
|
||||||
|
'6' => Self::SIX,
|
||||||
|
'5' => Self::FIVE,
|
||||||
|
'4' => Self::FOUR,
|
||||||
|
'3' => Self::THREE,
|
||||||
|
'2' => Self::TWO,
|
||||||
|
_ => panic!("Invalid card {}", c),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
struct Hand<const WILD: bool> {
|
||||||
|
cards: Vec<Card>,
|
||||||
|
bid: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const WILD: bool> Hand<WILD> {
|
||||||
|
fn card_counts(&self) -> [u64; Card::count()] {
|
||||||
|
let mut counts = [0u64; Card::count()];
|
||||||
|
for card in &self.cards {
|
||||||
|
counts[*card as usize] += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
counts
|
||||||
|
}
|
||||||
|
fn hand_type(&self) -> HandType {
|
||||||
|
if !WILD {
|
||||||
|
let card_counts = self.card_counts();
|
||||||
|
if card_counts.contains(&5) {
|
||||||
|
HandType::FiveOfAKind
|
||||||
|
} else if card_counts.contains(&4) {
|
||||||
|
HandType::FourOfAKind
|
||||||
|
} else if card_counts.contains(&3) && card_counts.contains(&2) {
|
||||||
|
HandType::FullHouse
|
||||||
|
} else if card_counts.contains(&3) {
|
||||||
|
HandType::ThreeOfAKind
|
||||||
|
} else if card_counts.iter().filter(|count| **count == 2).count() == 2 {
|
||||||
|
HandType::TwoPair
|
||||||
|
} else if card_counts.contains(&2) {
|
||||||
|
HandType::OnePair
|
||||||
|
} else {
|
||||||
|
HandType::HighCard
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let mut card_counts = self.card_counts();
|
||||||
|
let wild_count = card_counts[Card::J as usize];
|
||||||
|
card_counts[Card::J as usize] = 0;
|
||||||
|
|
||||||
|
let same_count = card_counts.iter().max().unwrap() + wild_count;
|
||||||
|
|
||||||
|
if same_count == 5 {
|
||||||
|
HandType::FiveOfAKind
|
||||||
|
} else if same_count == 4 {
|
||||||
|
HandType::FourOfAKind
|
||||||
|
} else if card_counts.contains(&3) && card_counts.contains(&2) {
|
||||||
|
HandType::FullHouse
|
||||||
|
} else
|
||||||
|
// Full House with WILDs
|
||||||
|
if wild_count == 1
|
||||||
|
&& (card_counts.contains(&3)
|
||||||
|
|| (card_counts.iter().filter(|count| **count == 2).count() == 2))
|
||||||
|
{
|
||||||
|
HandType::FullHouse
|
||||||
|
} else if wild_count == 2 && card_counts.contains(&2) {
|
||||||
|
HandType::FullHouse
|
||||||
|
} else if wild_count == 3 {
|
||||||
|
HandType::FullHouse
|
||||||
|
} else if same_count == 3 {
|
||||||
|
HandType::ThreeOfAKind
|
||||||
|
} else if card_counts.iter().filter(|count| **count == 2).count() == 2
|
||||||
|
|| (card_counts.contains(&2) && wild_count > 0)
|
||||||
|
{
|
||||||
|
HandType::TwoPair
|
||||||
|
} else if same_count == 2 {
|
||||||
|
HandType::OnePair
|
||||||
|
} else {
|
||||||
|
HandType::HighCard
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const WILD: bool> From<&str> for Hand<WILD> {
|
||||||
|
fn from(s: &str) -> Self {
|
||||||
|
let (cards_s, bid_s) = s.split_once(' ').unwrap();
|
||||||
|
let bid = bid_s.parse().unwrap();
|
||||||
|
let cards = cards_s.chars().map(|c| Card::from(c)).collect();
|
||||||
|
|
||||||
|
Hand { cards, bid }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const WILD: bool> PartialOrd for Hand<WILD> {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||||
|
Some(self.cmp(other))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const WILD: bool> Ord for Hand<WILD> {
|
||||||
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||||
|
let our_type = self.hand_type();
|
||||||
|
let other_type = other.hand_type();
|
||||||
|
if our_type != other_type {
|
||||||
|
our_type.cmp(&other_type)
|
||||||
|
} else {
|
||||||
|
let (ours, theirs) = self
|
||||||
|
.cards
|
||||||
|
.iter()
|
||||||
|
.zip(other.cards.iter())
|
||||||
|
.find(|(ours, theirs)| *ours != *theirs)
|
||||||
|
.unwrap();
|
||||||
|
if !WILD {
|
||||||
|
ours.cmp(theirs)
|
||||||
|
} else {
|
||||||
|
if *ours == Card::J {
|
||||||
|
std::cmp::Ordering::Less
|
||||||
|
} else if *theirs == Card::J {
|
||||||
|
std::cmp::Ordering::Greater
|
||||||
|
} else {
|
||||||
|
ours.cmp(theirs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PROBLEM 1 solution
|
||||||
|
|
||||||
|
fn problem1<T: BufRead>(input: Lines<T>) -> u64 {
|
||||||
|
let mut hands: Vec<_> = input
|
||||||
|
.map(|line| Hand::<false>::from(line.unwrap().as_str()))
|
||||||
|
.collect();
|
||||||
|
hands.sort();
|
||||||
|
hands
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(idx, hand)| (idx + 1) as u64 * hand.bid)
|
||||||
|
.sum()
|
||||||
|
}
|
||||||
|
|
||||||
|
// PROBLEM 2 solution
|
||||||
|
fn problem2<T: BufRead>(input: Lines<T>) -> u64 {
|
||||||
|
let mut hands: Vec<_> = input
|
||||||
|
.map(|line| Hand::<true>::from(line.unwrap().as_str()))
|
||||||
|
.collect();
|
||||||
|
hands.sort();
|
||||||
|
hands
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(idx, hand)| (idx + 1) as u64 * hand.bid)
|
||||||
|
.sum()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::io::Cursor;
|
||||||
|
|
||||||
|
use crate::*;
|
||||||
|
|
||||||
|
const EXAMPLE: &str = &"32T3K 765
|
||||||
|
T55J5 684
|
||||||
|
KK677 28
|
||||||
|
KTJJT 220
|
||||||
|
QQQJA 483";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hand_parser() {
|
||||||
|
let hand = Hand::<false>::from(EXAMPLE.lines().next().unwrap());
|
||||||
|
assert_eq!(
|
||||||
|
hand,
|
||||||
|
Hand {
|
||||||
|
bid: 765,
|
||||||
|
cards: vec![Card::THREE, Card::TWO, Card::T, Card::THREE, Card::K]
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn problem1_test_hand_compare() {
|
||||||
|
let hand1 = Hand::<false>::from("T55J5 123");
|
||||||
|
let hand2 = Hand::<false>::from("QQQJA 123");
|
||||||
|
let hand3 = Hand::<false>::from("KK677 123");
|
||||||
|
|
||||||
|
assert!(hand2 > hand1);
|
||||||
|
assert!(hand3 < hand1);
|
||||||
|
assert!(hand3 < hand2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn problem2_test_hand_compare() {}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn problem1_example() {
|
||||||
|
let c = Cursor::new(EXAMPLE);
|
||||||
|
assert_eq!(problem1(c.lines()), 6440);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn problem2_example() {
|
||||||
|
let c = Cursor::new(EXAMPLE);
|
||||||
|
assert_eq!(problem2(c.lines()), 5905);
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user