Compare commits
No commits in common. "90396f7fd1bfe1556e9cd08eb48d98ef2188f96d" and "c3c5667c8518cc48c6ca7823b5218c7aa34f3c6e" have entirely different histories.
90396f7fd1
...
c3c5667c85
|
@ -1,2 +0,0 @@
|
||||||
Time: 44 82 69 81
|
|
||||||
Distance: 202 1076 1138 1458
|
|
1000
2023/data/day7.txt
1000
2023/data/day7.txt
File diff suppressed because it is too large
Load Diff
|
@ -1,44 +0,0 @@
|
||||||
const RACES: [(u64, u64); 4] = [(44, 202), (82, 1076), (69, 1138), (81, 1458)];
|
|
||||||
|
|
||||||
pub fn day6a() -> String {
|
|
||||||
let score = RACES
|
|
||||||
.iter()
|
|
||||||
.map(|(time, winning_distance)| optimal_winners(*time, *winning_distance).len())
|
|
||||||
.fold(1, |acc, val| acc * val);
|
|
||||||
format!("{}", score)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn day6b() -> String {
|
|
||||||
format!("{}", optimal_winners(44826981, 202107611381458).len())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn optimal_winners(total_time: u64, winning_distance: u64) -> Vec<u64> {
|
|
||||||
race_distances(total_time)
|
|
||||||
.filter(|(_, distance)| *distance > winning_distance)
|
|
||||||
.map(|(time, _)| time)
|
|
||||||
.collect::<Vec<u64>>()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn race_distances(total_time: u64) -> impl Iterator<Item = (u64, u64)> {
|
|
||||||
(0..total_time)
|
|
||||||
.map(move |charge_time| (charge_time, distance(charge_time, total_time - charge_time)))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn distance(charge_time: u64, remaining_time: u64) -> u64 {
|
|
||||||
charge_time * remaining_time
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_winners() {
|
|
||||||
assert_eq!(optimal_winners(7, 9), vec![2, 3, 4, 5]);
|
|
||||||
assert_eq!(optimal_winners(15, 40), vec![4, 5, 6, 7, 8, 9, 10, 11]);
|
|
||||||
assert_eq!(
|
|
||||||
optimal_winners(30, 200),
|
|
||||||
vec![11, 12, 13, 14, 15, 16, 17, 18, 19]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
368
2023/src/day7.rs
368
2023/src/day7.rs
|
@ -1,368 +0,0 @@
|
||||||
use std::{
|
|
||||||
cmp::Ordering,
|
|
||||||
collections::{HashMap, HashSet},
|
|
||||||
};
|
|
||||||
|
|
||||||
const INPUT: &str = include_str!("../data/day7.txt");
|
|
||||||
|
|
||||||
pub fn day7a() -> String {
|
|
||||||
// format!("{}", calculate_game(INPUT))
|
|
||||||
format!("card values changed in part 2")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn day7b() -> String {
|
|
||||||
format!("{}", calculate_game(INPUT))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn calculate_game(game: &str) -> u64 {
|
|
||||||
let mut hands = game
|
|
||||||
.lines()
|
|
||||||
.map(|line| parse_line(line))
|
|
||||||
.collect::<Vec<(Hand, u64)>>();
|
|
||||||
for hand in hands.iter() {
|
|
||||||
println!("{:?} {:?} ", hand.0, hand.0.classify());
|
|
||||||
}
|
|
||||||
|
|
||||||
println!("");
|
|
||||||
|
|
||||||
hands.sort_by(|(hand1, bid1), (hand2, bid2)| {
|
|
||||||
if hand1.cmp(hand2) == Ordering::Equal {
|
|
||||||
bid1.cmp(bid2)
|
|
||||||
} else {
|
|
||||||
hand1.cmp(hand2)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
for hand in hands.iter() {
|
|
||||||
println!("{:?} {:?} ", hand.0, hand.0.classify());
|
|
||||||
}
|
|
||||||
|
|
||||||
hands
|
|
||||||
.into_iter()
|
|
||||||
.enumerate()
|
|
||||||
.map(|(rank, (_, bid))| (rank as u64 + 1) * bid)
|
|
||||||
.fold(0, |acc, val| acc + val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_line(s: &str) -> (Hand, u64) {
|
|
||||||
let mut parts = s.split(" ");
|
|
||||||
let hand = parts.next().unwrap();
|
|
||||||
let bid = parts.next().unwrap();
|
|
||||||
|
|
||||||
(Hand::from(hand), bid.parse::<u64>().unwrap())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Hash, Eq, Ord)]
|
|
||||||
enum Card {
|
|
||||||
Joker,
|
|
||||||
Card(u32),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<char> for Card {
|
|
||||||
fn from(s: char) -> Card {
|
|
||||||
match s {
|
|
||||||
'J' => Card::Joker,
|
|
||||||
'2' => Card::Card(2),
|
|
||||||
'3' => Card::Card(3),
|
|
||||||
'4' => Card::Card(4),
|
|
||||||
'5' => Card::Card(5),
|
|
||||||
'6' => Card::Card(6),
|
|
||||||
'7' => Card::Card(7),
|
|
||||||
'8' => Card::Card(8),
|
|
||||||
'9' => Card::Card(9),
|
|
||||||
'T' => Card::Card(10),
|
|
||||||
'Q' => Card::Card(11),
|
|
||||||
'K' => Card::Card(12),
|
|
||||||
'A' => Card::Card(13),
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Ord)]
|
|
||||||
enum HandType {
|
|
||||||
HighCard,
|
|
||||||
OnePair,
|
|
||||||
TwoPair,
|
|
||||||
ThreeOfAKind,
|
|
||||||
FullHouse,
|
|
||||||
FourOfAKind,
|
|
||||||
FiveOfAKind,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
||||||
struct Hand(Vec<Card>);
|
|
||||||
|
|
||||||
fn remove_highest(set: &mut HashSet<Card>) -> Card {
|
|
||||||
let mut lst = set.iter().cloned().collect::<Vec<Card>>();
|
|
||||||
lst.sort();
|
|
||||||
lst.reverse();
|
|
||||||
let highest = lst.first().unwrap().clone();
|
|
||||||
set.remove(&highest);
|
|
||||||
highest
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Hand {
|
|
||||||
fn classify(&self) -> HandType {
|
|
||||||
let mut cards: HashSet<Card> = HashSet::new();
|
|
||||||
let mut jokers: u32 = 0;
|
|
||||||
let mut pairs: HashSet<Card> = HashSet::new();
|
|
||||||
let mut triples: HashSet<Card> = HashSet::new();
|
|
||||||
let mut quads: HashSet<Card> = HashSet::new();
|
|
||||||
let mut quints: HashSet<Card> = HashSet::new();
|
|
||||||
|
|
||||||
for card in self.0.iter() {
|
|
||||||
if *card == Card::Joker {
|
|
||||||
jokers += 1;
|
|
||||||
} else if quads.contains(card) {
|
|
||||||
quads.remove(card);
|
|
||||||
quints.insert(*card);
|
|
||||||
} else if triples.contains(card) {
|
|
||||||
triples.remove(card);
|
|
||||||
quads.insert(*card);
|
|
||||||
} else if pairs.contains(card) {
|
|
||||||
pairs.remove(card);
|
|
||||||
triples.insert(*card);
|
|
||||||
} else if cards.contains(card) {
|
|
||||||
cards.remove(card);
|
|
||||||
pairs.insert(*card);
|
|
||||||
} else {
|
|
||||||
cards.insert(*card);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if jokers == 5 {
|
|
||||||
return HandType::FiveOfAKind;
|
|
||||||
}
|
|
||||||
|
|
||||||
for _ in 0..jokers {
|
|
||||||
if quads.len() > 0 {
|
|
||||||
let highest = remove_highest(&mut quads);
|
|
||||||
quints.insert(highest);
|
|
||||||
} else if triples.len() > 0 {
|
|
||||||
let highest = remove_highest(&mut triples);
|
|
||||||
quads.insert(highest);
|
|
||||||
} else if pairs.len() > 0 {
|
|
||||||
let highest = remove_highest(&mut pairs);
|
|
||||||
triples.insert(highest);
|
|
||||||
} else if cards.len() > 0 {
|
|
||||||
let highest = remove_highest(&mut cards);
|
|
||||||
pairs.insert(highest);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if quints.len() > 0 {
|
|
||||||
HandType::FiveOfAKind
|
|
||||||
} else if quads.len() > 0 {
|
|
||||||
HandType::FourOfAKind
|
|
||||||
} else if triples.len() > 0 && pairs.len() > 0 {
|
|
||||||
HandType::FullHouse
|
|
||||||
} else if triples.len() > 0 {
|
|
||||||
HandType::ThreeOfAKind
|
|
||||||
} else if pairs.len() == 2 {
|
|
||||||
HandType::TwoPair
|
|
||||||
} else if pairs.len() == 1 {
|
|
||||||
HandType::OnePair
|
|
||||||
} else {
|
|
||||||
HandType::HighCard
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&str> for Hand {
|
|
||||||
fn from(s: &str) -> Hand {
|
|
||||||
Hand(s.chars().map(|c| Card::from(c)).collect::<Vec<Card>>())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialOrd for Hand {
|
|
||||||
fn partial_cmp(&self, other: &Hand) -> Option<Ordering> {
|
|
||||||
Some(self.cmp(other))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Ord for Hand {
|
|
||||||
fn cmp(&self, other: &Hand) -> Ordering {
|
|
||||||
let class1 = self.classify();
|
|
||||||
let class2 = other.classify();
|
|
||||||
|
|
||||||
if class1 == class2 {
|
|
||||||
for (card1, card2) in self.0.iter().zip(other.0.clone()) {
|
|
||||||
let cmp = card1.cmp(&card2);
|
|
||||||
if cmp != Ordering::Equal {
|
|
||||||
return cmp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Ordering::Equal;
|
|
||||||
} else {
|
|
||||||
class1.cmp(&class2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
const INPUT: &str = "32T3K 765
|
|
||||||
T55J5 684
|
|
||||||
KK677 28
|
|
||||||
KTJJT 220
|
|
||||||
QQQJA 483
|
|
||||||
JJJJJ 1";
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn it_calculates_test_data() {
|
|
||||||
assert_eq!(calculate_game(INPUT), 5906);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn parses_hand() {
|
|
||||||
let test_cases = [
|
|
||||||
(
|
|
||||||
"32T3K",
|
|
||||||
Hand(vec![
|
|
||||||
Card::Card(3),
|
|
||||||
Card::Card(2),
|
|
||||||
Card::Card(10),
|
|
||||||
Card::Card(3),
|
|
||||||
Card::Card(12),
|
|
||||||
]),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"T55J5",
|
|
||||||
Hand(vec![
|
|
||||||
Card::Card(10),
|
|
||||||
Card::Card(5),
|
|
||||||
Card::Card(5),
|
|
||||||
Card::Joker,
|
|
||||||
Card::Card(5),
|
|
||||||
]),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"KK677",
|
|
||||||
Hand(vec![
|
|
||||||
Card::Card(12),
|
|
||||||
Card::Card(12),
|
|
||||||
Card::Card(6),
|
|
||||||
Card::Card(7),
|
|
||||||
Card::Card(7),
|
|
||||||
]),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"KTJJT",
|
|
||||||
Hand(vec![
|
|
||||||
Card::Card(12),
|
|
||||||
Card::Card(10),
|
|
||||||
Card::Joker,
|
|
||||||
Card::Joker,
|
|
||||||
Card::Card(10),
|
|
||||||
]),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"QQQJA",
|
|
||||||
Hand(vec![
|
|
||||||
Card::Card(11),
|
|
||||||
Card::Card(11),
|
|
||||||
Card::Card(11),
|
|
||||||
Card::Joker,
|
|
||||||
Card::Card(13),
|
|
||||||
]),
|
|
||||||
),
|
|
||||||
];
|
|
||||||
|
|
||||||
for (hand_str, hand) in test_cases {
|
|
||||||
assert_eq!(Hand::from(hand_str), hand)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn classifies_a_hand() {
|
|
||||||
let test_cases = [
|
|
||||||
(
|
|
||||||
Hand(vec![
|
|
||||||
Card::Card(11),
|
|
||||||
Card::Joker,
|
|
||||||
Card::Card(10),
|
|
||||||
Card::Card(9),
|
|
||||||
Card::Card(8),
|
|
||||||
]),
|
|
||||||
HandType::OnePair,
|
|
||||||
),
|
|
||||||
(
|
|
||||||
Hand(vec![
|
|
||||||
Card::Card(3),
|
|
||||||
Card::Card(2),
|
|
||||||
Card::Card(10),
|
|
||||||
Card::Card(3),
|
|
||||||
Card::Card(12),
|
|
||||||
]),
|
|
||||||
HandType::OnePair,
|
|
||||||
),
|
|
||||||
(
|
|
||||||
Hand(vec![
|
|
||||||
Card::Card(10),
|
|
||||||
Card::Card(5),
|
|
||||||
Card::Card(5),
|
|
||||||
Card::Joker,
|
|
||||||
Card::Card(5),
|
|
||||||
]),
|
|
||||||
HandType::FourOfAKind,
|
|
||||||
),
|
|
||||||
(
|
|
||||||
Hand(vec![
|
|
||||||
Card::Card(12),
|
|
||||||
Card::Card(12),
|
|
||||||
Card::Card(6),
|
|
||||||
Card::Card(7),
|
|
||||||
Card::Card(7),
|
|
||||||
]),
|
|
||||||
HandType::TwoPair,
|
|
||||||
),
|
|
||||||
(
|
|
||||||
Hand(vec![
|
|
||||||
Card::Card(12),
|
|
||||||
Card::Joker,
|
|
||||||
Card::Card(10),
|
|
||||||
Card::Card(10),
|
|
||||||
Card::Joker,
|
|
||||||
]),
|
|
||||||
HandType::FourOfAKind,
|
|
||||||
),
|
|
||||||
(
|
|
||||||
Hand(vec![
|
|
||||||
Card::Card(11),
|
|
||||||
Card::Card(11),
|
|
||||||
Card::Card(11),
|
|
||||||
Card::Joker,
|
|
||||||
Card::Card(13),
|
|
||||||
]),
|
|
||||||
HandType::FourOfAKind,
|
|
||||||
),
|
|
||||||
(
|
|
||||||
Hand(vec![
|
|
||||||
Card::Card(11),
|
|
||||||
Card::Card(11),
|
|
||||||
Card::Card(11),
|
|
||||||
Card::Card(10),
|
|
||||||
Card::Card(10),
|
|
||||||
]),
|
|
||||||
HandType::FullHouse,
|
|
||||||
),
|
|
||||||
(
|
|
||||||
Hand(vec![
|
|
||||||
Card::Joker,
|
|
||||||
Card::Joker,
|
|
||||||
Card::Joker,
|
|
||||||
Card::Joker,
|
|
||||||
Card::Joker,
|
|
||||||
]),
|
|
||||||
HandType::HighCard,
|
|
||||||
),
|
|
||||||
];
|
|
||||||
|
|
||||||
for (hand, classification) in test_cases {
|
|
||||||
assert_eq!(hand.classify(), classification, "{:?}", hand);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -3,8 +3,6 @@ mod day2;
|
||||||
mod day3;
|
mod day3;
|
||||||
mod day4;
|
mod day4;
|
||||||
mod day5;
|
mod day5;
|
||||||
mod day6;
|
|
||||||
mod day7;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let day = std::env::args().skip(1).next();
|
let day = std::env::args().skip(1).next();
|
||||||
|
@ -20,10 +18,6 @@ fn main() {
|
||||||
Some("4b") => day4::day4b(),
|
Some("4b") => day4::day4b(),
|
||||||
Some("5a") => day5::day5a(),
|
Some("5a") => day5::day5a(),
|
||||||
Some("5b") => day5::day5b(),
|
Some("5b") => day5::day5b(),
|
||||||
Some("6a") => day6::day6a(),
|
|
||||||
Some("6b") => day6::day6b(),
|
|
||||||
Some("7a") => day7::day7a(),
|
|
||||||
Some("7b") => day7::day7b(),
|
|
||||||
_ => panic!("unrecognized day"),
|
_ => panic!("unrecognized day"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue