Compare commits

..

2 commits

Author SHA1 Message Date
adda315684 day 7 part 2 2023-12-07 18:38:45 -05:00
6b09514019 day 7 part 1 2023-12-07 18:29:15 -05:00
5 changed files with 1128 additions and 58 deletions

25
Cargo.lock generated
View file

@ -22,10 +22,17 @@ name = "aoc2023"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"counter",
"fancy-regex", "fancy-regex",
"regex", "regex",
] ]
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]] [[package]]
name = "bit-set" name = "bit-set"
version = "0.5.3" version = "0.5.3"
@ -41,6 +48,15 @@ version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
[[package]]
name = "counter"
version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d458e66999348f56fd3ffcfbb7f7951542075ca8359687c703de6500c1ddccd"
dependencies = [
"num-traits",
]
[[package]] [[package]]
name = "fancy-regex" name = "fancy-regex"
version = "0.12.0" version = "0.12.0"
@ -57,6 +73,15 @@ version = "2.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
[[package]]
name = "num-traits"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
dependencies = [
"autocfg",
]
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.10.2" version = "1.10.2"

View file

@ -7,5 +7,6 @@ edition = "2021"
[dependencies] [dependencies]
anyhow = "1.0.75" anyhow = "1.0.75"
counter = "0.5.7"
fancy-regex = "0.12.0" fancy-regex = "0.12.0"
regex = "1.10.2" regex = "1.10.2"

View file

@ -1,2 +1,5 @@
Time: 7 15 30 32T3K 765
Distance: 9 40 200 T55J5 684
KK677 28
KTJJT 220
QQQJA 483

1002
input.txt

File diff suppressed because it is too large Load diff

View file

@ -1,76 +1,119 @@
use std::io::stdin; use std::{collections::HashMap, io::stdin};
use anyhow::{bail, Result}; use anyhow::{bail, Result};
use counter::Counter;
use regex::Regex; use regex::Regex;
/// solve ax² + bx + c = 0 #[derive(Debug, PartialEq, Eq, Hash)]
fn solve_quadratic(a: f64, b: f64, c: f64) -> (f64, f64) { enum HandType {
let r1 = (-b + f64::sqrt(b * b - 4.0 * a * c)) / 2.0 * a; FiveOfAKind,
let r2 = (-b - f64::sqrt(b * b - 4.0 * a * c)) / 2.0 * a; FourOfAKind,
(r1, r2) FullHouse,
ThreeOfAKind,
TwoPair,
OnePair,
HighCard,
} }
fn parse_input() -> Result<(Vec<i64>, Vec<i64>)> { fn hand_type(hand: &str) -> HandType {
let numbers = Regex::new(r"(\d+)")?; let counter_without_joker: Counter<char> = hand.chars().filter(|c| *c != 'J').collect();
let mut times = vec![]; if counter_without_joker.is_empty() {
let mut distances = vec![]; // it's JJJJJ
for line in stdin().lines().map_while(Result::ok) { return HandType::FiveOfAKind;
if line.starts_with("Time:") { }
times = numbers let hand = hand.replace(
.captures_iter(&line.replace(' ', "")) 'J',
.map(|c| c.get(1).unwrap().as_str().parse()) &counter_without_joker
.map_while(Result::ok) .k_most_common_ordered(1)
.collect(); .first()
} else if line.starts_with("Distance:") { .unwrap()
distances = numbers .0
.captures_iter(&line.replace(' ', "")) .to_string(),
.map(|c| c.get(1).unwrap().as_str().parse()) );
.map_while(Result::ok) let counter: Counter<char> = hand.chars().collect();
.collect(); if counter.keys().len() == 1 {
} else { return HandType::FiveOfAKind;
bail!("unexpected line: {}", line); }
if counter.keys().len() == 2 {
if counter.k_most_common_ordered(1)[0].1 == 4 {
return HandType::FourOfAKind;
}
if counter.k_most_common_ordered(1)[0].1 == 3 {
return HandType::FullHouse;
} }
} }
Ok((times, distances)) if counter.keys().len() == 3 {
if counter.k_most_common_ordered(1)[0].1 == 3 {
return HandType::ThreeOfAKind;
}
if counter.k_most_common_ordered(1)[0].1 == 2 {
return HandType::TwoPair;
}
}
if counter.keys().len() == 4 {
return HandType::OnePair;
}
HandType::HighCard
}
type CmpKey = (u8, u8, u8, u8, u8, u8);
fn hand_cmp_key(hand: &str) -> CmpKey {
let hand_strength = HashMap::from([
(HandType::FiveOfAKind, 7u8),
(HandType::FourOfAKind, 6u8),
(HandType::FullHouse, 5u8),
(HandType::ThreeOfAKind, 4u8),
(HandType::TwoPair, 3u8),
(HandType::OnePair, 2u8),
(HandType::HighCard, 1u8),
]);
let card_strength: HashMap<char, u8> = "AKQT98765432J"
.chars()
.enumerate()
.map(|(i, c)| (c, (14 - i) as u8))
.collect();
let mut r = vec![*hand_strength.get(&hand_type(hand)).unwrap()];
r.extend(hand.chars().map(|c| card_strength.get(&c).unwrap()));
(r[0], r[1], r[2], r[3], r[4], r[5])
} }
fn main() -> Result<()> { fn main() -> Result<()> {
let (times, distances) = parse_input()?; let mut bids = vec![];
for line in stdin().lines().map_while(Result::ok) {
let parts: Vec<&str> = line.split_whitespace().collect();
let hand = parts[0];
let bid: i64 = parts[1].parse().unwrap();
println!("{} {:?} {}", hand, hand_type(hand), bid);
if times.len() != distances.len() { bids.push((hand.to_owned(), bid));
bail!(
"times has {} elements, but distances has {} elements",
times.len(),
distances.len()
);
} }
bids.sort_by_key(|(hand, _)| hand_cmp_key(hand));
let mut prod = 1; let mut winnings = 0;
for i in 0..times.len() { for (i, b) in bids.iter().enumerate() {
let t = times[i]; let (_, bid) = b;
let d = distances[i]; winnings += (i as i64 + 1) * bid;
// the equation to solve is x * (t - x) - d = 0
// = t*x - x*x - d = 0
// = -1x² + tx - d = 0
let (r1, r2) = solve_quadratic(-1.0, t as f64, -d as f64);
let r1 = (r1 + 1.0).floor() as i64;
let r2 = (r2 - 1.0).ceil() as i64;
let ways = (r2 - r1) + 1;
println!("{t} {d}");
println!("ways: {ways}");
prod *= ways;
} }
println!("{}", winnings);
println!("{prod}");
Ok(()) Ok(())
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*;
#[test] #[test]
fn test() {} fn test_hand_types() {
assert_eq!(hand_type("AAAAJ"), HandType::FiveOfAKind);
assert_eq!(hand_type("AAAJJ"), HandType::FiveOfAKind);
assert_eq!(hand_type("AAJJJ"), HandType::FiveOfAKind);
assert_eq!(hand_type("T55J5"), HandType::FourOfAKind);
assert_eq!(hand_type("KTJJT"), HandType::FourOfAKind);
assert_eq!(hand_type("QQQJA"), HandType::FourOfAKind);
assert_eq!(hand_type("2J432"), HandType::ThreeOfAKind);
assert_eq!(hand_type("A23J4"), HandType::OnePair);
assert_eq!(hand_type("23456"), HandType::HighCard);
}
} }