adventofcode23/src/day6.rs

92 lines
2 KiB
Rust

//! Day 6: Wait For It
use std::ops::RangeInclusive;
use itertools::Itertools;
pub const DAY: u8 = 6;
pub const TITLE: &str = "Wait For It";
#[derive(Debug)]
struct Race {
t: u64,
d: u64,
}
impl Race {
fn win_range(&self) -> RangeInclusive<u64> {
let t_r = self.t as f64;
let d = self.d as f64;
let discriminant = (t_r.powi(2) - (4.0 * d)).sqrt();
let a = (-t_r + discriminant) / -2.0;
let b = (-t_r - discriminant) / -2.0;
let min = a.min(b);
let max = a.max(b);
let mut l = min.ceil();
if l == min {
l += 1.0;
}
let mut h = max.floor();
if h == max {
h -= 1.0
}
l as u64..=h as u64
}
}
pub fn part1(input: Vec<String>) -> String {
let races = input[0]
.split_ascii_whitespace()
.skip(1)
.zip(input[1].split_ascii_whitespace().skip(1))
.map(|(a, b)| Race {
t: a.parse().unwrap(),
d: b.parse().unwrap(),
})
.collect_vec();
races
.iter()
.map(|r| r.win_range().try_len().unwrap())
.product::<usize>()
.to_string()
}
pub fn part2(input: Vec<String>) -> String {
let (_, l1) = input[0].split_once(' ').unwrap();
let (_, l2) = input[1].split_once(' ').unwrap();
let t = l1.replace(' ', "").parse::<u64>().unwrap();
let d = l2.replace(' ', "").parse::<u64>().unwrap();
let race = Race { t, d };
race.win_range().try_len().unwrap().to_string()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn t_example1() {
assert_eq!(part1(crate::read_example(DAY, 1)), "288");
}
#[test]
fn t_part1() {
assert_eq!(part1(crate::read_input(DAY)), "505494");
}
#[test]
fn t_example2() {
assert_eq!(part2(crate::read_example(DAY, 2)), "71503");
}
#[test]
fn t_part2() {
assert_eq!(part2(crate::read_input(DAY)), "23632299");
}
}