day07: rust
This commit is contained in:
parent
c95182d32c
commit
ead01162cb
12
07/README.md
Normal file
12
07/README.md
Normal file
@ -0,0 +1,12 @@
|
||||
# [Day 7](https://adventofcode.com/2023/day/7)
|
||||
:gift::gift::gift::gift::gift::gift::gift:
|
||||
|
||||
Today's language: **Rust**
|
||||
|
||||
Not pretty, but pretty fast.
|
||||
|
||||
```shell
|
||||
rustc day07.rs
|
||||
./day07
|
||||
```
|
||||
<!-- -->
|
227
07/day07.rs
Normal file
227
07/day07.rs
Normal file
@ -0,0 +1,227 @@
|
||||
use std::fmt;
|
||||
use std::io::{self, BufRead};
|
||||
use std::cmp::{Ord, Ordering};
|
||||
|
||||
const HIGH_CARD: u32 = 0;
|
||||
const ONE_PAIR: u32 = 1;
|
||||
const TWO_PAIR: u32 = 2;
|
||||
const THREE_OF_KIND: u32 = 3;
|
||||
const FULL_HOUSE: u32 = 4;
|
||||
const FOUR_OF_KIND: u32 = 5;
|
||||
const FIVE_OF_KIND: u32 = 6;
|
||||
|
||||
|
||||
#[derive(Eq)]
|
||||
struct Hand {
|
||||
cards: Vec<usize>,
|
||||
hand_type: u32,
|
||||
bid: u32,
|
||||
}
|
||||
impl Hand {
|
||||
fn new1(cards: &str, bid: u32, card_counts: &mut [usize; 13]) -> Hand {
|
||||
let mut hand = Hand{ cards: cards.chars().map(|c| Hand::char_to_num1(c)).collect(), hand_type: HIGH_CARD, bid: bid };
|
||||
assert!(hand.cards.len() == 5, "Found {} cards instead of five", hand.cards.len());
|
||||
hand.determine_type1(card_counts);
|
||||
return hand;
|
||||
}
|
||||
fn new2(cards: &str, bid: u32, card_counts: &mut [usize; 13]) -> Hand {
|
||||
let mut hand = Hand{ cards: cards.chars().map(|c| Hand::char_to_num2(c)).collect(), hand_type: HIGH_CARD, bid: bid };
|
||||
assert!(hand.cards.len() == 5, "Found {} cards instead of five", hand.cards.len());
|
||||
hand.determine_type2(card_counts);
|
||||
return hand;
|
||||
}
|
||||
fn char_to_num1(c: char) -> usize {
|
||||
match c {
|
||||
'2' => return 0,
|
||||
'3' => return 1,
|
||||
'4' => return 2,
|
||||
'5' => return 3,
|
||||
'6' => return 4,
|
||||
'7' => return 5,
|
||||
'8' => return 6,
|
||||
'9' => return 7,
|
||||
'T' => return 8,
|
||||
'J' => return 9,
|
||||
'Q' => return 10,
|
||||
'K' => return 11,
|
||||
'A' => return 12,
|
||||
_ => panic!("Invalid char found: {}", c),
|
||||
}
|
||||
}
|
||||
fn char_to_num2(c: char) -> usize {
|
||||
match c {
|
||||
'J' => return 0,
|
||||
'2' => return 1,
|
||||
'3' => return 2,
|
||||
'4' => return 3,
|
||||
'5' => return 4,
|
||||
'6' => return 5,
|
||||
'7' => return 6,
|
||||
'8' => return 7,
|
||||
'9' => return 8,
|
||||
'T' => return 9,
|
||||
'Q' => return 10,
|
||||
'K' => return 11,
|
||||
'A' => return 12,
|
||||
_ => panic!("Invalid char found: {}", c),
|
||||
}
|
||||
}
|
||||
fn determine_type1(&mut self, card_counts: &mut [usize; 13]) {
|
||||
// use given array to reduce memory allocations
|
||||
for count in card_counts.iter_mut() { *count = 0 };
|
||||
for card in &self.cards {
|
||||
card_counts[*card] += 1;
|
||||
}
|
||||
let mut found_three = false;
|
||||
let mut found_two = false;
|
||||
for count in card_counts {
|
||||
match count {
|
||||
5 => { self.hand_type = FIVE_OF_KIND; return; },
|
||||
4 => { self.hand_type = FOUR_OF_KIND; return; },
|
||||
3 => { self.hand_type = THREE_OF_KIND; found_three = true; },
|
||||
2 => {
|
||||
if found_two {
|
||||
self.hand_type = TWO_PAIR;
|
||||
return;
|
||||
}
|
||||
else {
|
||||
self.hand_type = ONE_PAIR;
|
||||
found_two = true;
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
if found_two && found_three {
|
||||
self.hand_type = FULL_HOUSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
fn determine_type2(&mut self, card_counts: &mut [usize; 13]) {
|
||||
// better solution would be to just add the number of jokers to the card with the highest
|
||||
// number
|
||||
// use given array to reduce memory allocations
|
||||
for count in card_counts.iter_mut() { *count = 0 };
|
||||
for card in &self.cards {
|
||||
card_counts[*card] += 1;
|
||||
}
|
||||
let mut found_three = false;
|
||||
let mut found_two = false;
|
||||
// determine without jokers
|
||||
for count in card_counts.iter().skip(1) {
|
||||
match count {
|
||||
5 => { self.hand_type = FIVE_OF_KIND; return; },
|
||||
4 => { self.hand_type = FOUR_OF_KIND; break; },
|
||||
3 => { self.hand_type = THREE_OF_KIND; found_three = true; },
|
||||
2 => {
|
||||
if found_two {
|
||||
self.hand_type = TWO_PAIR;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
self.hand_type = ONE_PAIR;
|
||||
found_two = true;
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
if found_two && found_three {
|
||||
self.hand_type = FULL_HOUSE;
|
||||
return
|
||||
}
|
||||
}
|
||||
match card_counts[0] {
|
||||
0 => return, // no jokers
|
||||
1 => match self.hand_type {
|
||||
FOUR_OF_KIND => self.hand_type = FIVE_OF_KIND,
|
||||
THREE_OF_KIND => self.hand_type = FOUR_OF_KIND,
|
||||
TWO_PAIR => self.hand_type = FULL_HOUSE,
|
||||
ONE_PAIR => self.hand_type = THREE_OF_KIND,
|
||||
HIGH_CARD => self.hand_type = ONE_PAIR,
|
||||
_ => panic!("Unhandled joker(1) case: hand_type={}", self.hand_type),
|
||||
},
|
||||
2 => match self.hand_type {
|
||||
THREE_OF_KIND => self.hand_type = FIVE_OF_KIND,
|
||||
ONE_PAIR => self.hand_type = FOUR_OF_KIND,
|
||||
HIGH_CARD => self.hand_type = THREE_OF_KIND,
|
||||
_ => panic!("Unhandled joker(2) case: hand_type={}", self.hand_type)
|
||||
},
|
||||
3 => match self.hand_type {
|
||||
ONE_PAIR => self.hand_type = FIVE_OF_KIND,
|
||||
HIGH_CARD => self.hand_type = FOUR_OF_KIND,
|
||||
_ => panic!("Unhandled joker(3) case: hand_type={}", self.hand_type)
|
||||
},
|
||||
_ => self.hand_type = FIVE_OF_KIND
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl Ord for Hand {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
let mut order = self.hand_type.cmp(&other.hand_type);
|
||||
if order != Ordering::Equal { return order };
|
||||
for i in 0..self.cards.len() {
|
||||
order = self.cards[i].cmp(&other.cards[i]);
|
||||
if order != Ordering::Equal { return order };
|
||||
}
|
||||
panic!("Equal elements: {} and {}", self, other);
|
||||
}
|
||||
}
|
||||
impl PartialOrd for Hand {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
return Some(self.cmp(other));
|
||||
}
|
||||
}
|
||||
impl PartialEq for Hand {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
return self.cmp(other) == Ordering::Equal;
|
||||
}
|
||||
}
|
||||
impl fmt::Display for Hand {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let _ =write!(f, "Hand=");
|
||||
for c in &self.cards {
|
||||
let _ = write!(f, "{}", c);
|
||||
}
|
||||
write!(f, ", type={}, bid={}", self.hand_type, self.bid)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn main() {
|
||||
let input = "input.txt";
|
||||
let lines = read_lines(&input);
|
||||
let mut hands1: Vec<Hand> = Vec::new();
|
||||
hands1.reserve(1000);
|
||||
let mut hands2: Vec<Hand> = Vec::new();
|
||||
hands2.reserve(1000);
|
||||
// use given array to reduce memory allocations
|
||||
let mut card_counts: [usize; 13] = [0; 13];
|
||||
for (_, line) in lines.enumerate() {
|
||||
let Ok(line) = line else { panic!("Line not ok"); };
|
||||
hands1.push(Hand::new1(&line[..5], line[6..].parse::<u32>().unwrap(), &mut card_counts));
|
||||
hands2.push(Hand::new2(&line[..5], line[6..].parse::<u32>().unwrap(), &mut card_counts));
|
||||
// println!("Hand: {}", hands.last().expect("No hand"));
|
||||
}
|
||||
hands1.sort_unstable();
|
||||
hands2.sort_unstable();
|
||||
let mut total_winnings1: u32 = 0;
|
||||
let mut total_winnings2: u32 = 0;
|
||||
for (i, hand) in hands1.iter().enumerate() {
|
||||
total_winnings1 += (i as u32 + 1) * hand.bid;
|
||||
}
|
||||
for (i, hand) in hands2.iter().enumerate() {
|
||||
total_winnings2 += (i as u32 + 1) * hand.bid;
|
||||
}
|
||||
println!("Total winnings (1): {}", total_winnings1);
|
||||
println!("Total winnings (2): {}", total_winnings2);
|
||||
}
|
||||
|
||||
|
||||
fn read_lines<P>(filename: P) -> io::Lines<io::BufReader<std::fs::File>>
|
||||
where P: AsRef<std::path::Path>, {
|
||||
return match std::fs::File::open(filename) {
|
||||
Err(why) => panic!("Could not open file. {}", why),
|
||||
Ok(file) => std::io::BufReader::new(file).lines()
|
||||
};
|
||||
}
|
@ -1,9 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
maxday=$(ls -d */ | sed -r 's|0*(.*)/|\1|g' | tail -1)
|
||||
echo $maxday
|
||||
nextday=$((maxday + 1))
|
||||
nextday_dir=$(printf "%02d" $nextday)
|
||||
echo $nextday
|
||||
mkdir $nextday_dir
|
||||
sed "s/X/$nextday/g" README.md.temp > $nextday_dir/README.md
|
||||
|
Loading…
Reference in New Issue
Block a user