Day 6 initial solution

This commit is contained in:
pjht 2023-12-06 08:14:51 -06:00
parent 77a2c79f41
commit b187600bb5
Signed by: pjht
GPG Key ID: 7B5F6AFBEC7EE78E
3 changed files with 96 additions and 0 deletions

2
input/2023/day6.txt Normal file
View File

@ -0,0 +1,2 @@
Time: 46 68 98 66
Distance: 358 1054 1807 1080

93
src/day06.rs Normal file
View File

@ -0,0 +1,93 @@
use aoc_runner_derive::{aoc_generator, aoc};
use nom::{sequence::{preceded, separated_pair, pair}, bytes::complete::tag, IResult, character::complete::{multispace0, line_ending}, multi::separated_list0};
fn parse_number_list(start_tag: &str) -> impl Fn(&str) -> IResult<&str, Vec<u64>> + '_ {
move |input| {
preceded(pair(tag(start_tag), multispace0), separated_list0(pair(tag(" "), multispace0), nom::character::complete::u64))(input)
}
}
fn parse_input(input: &str) -> IResult<&str, (Vec<u64>, Vec<u64>)> {
separated_pair(parse_number_list("Time:"), line_ending, parse_number_list("Distance:"))(input)
}
#[aoc_generator(day6, part1)]
fn input_generator_part1(input: &str) -> (Vec<u64>, Vec<u64>) {
parse_input(input).unwrap().1
}
#[aoc_generator(day6, part2)]
fn input_generator_part2(input: &str) -> (u64, u64) {
let mut lines = input.split('\n');
let time_line = lines.next().unwrap();
let dist_line = lines.next().unwrap();
let time_line = time_line.replace(' ', "");
let dist_line = dist_line.replace(' ', "");
let time = time_line[5..].parse().unwrap();
let dist = dist_line[9..].parse().unwrap();
(time, dist)
}
fn race_dist(speed: u64, total_time: u64) -> u64 {
speed*(total_time-speed)
}
// let n be the number of ms you hold the button
// let t be the race time
// let d be the record distance
// time units is ms unless specified, distance is mm unless specified
// n(t-n)>d
// nt-n^2>d
// nt-n^2-d>0
//
// nt-n^2-d=0
// -n^2+tn-d=0
//
// n=-t(+-)sqrt(t^2-4*1*-d)/2
// n=-t(+-)sqrt(t^2+4d)/2
//
// Let the two values be n_1 and n_2
//
// d/dn(nt-n^2-d)=t-2n
// d/dn(t-2n)=-2
//
// Function is always concave down
// Concave down parabolas are >0 between their roots
//
// Range of winning times are ceil(n_1) to floor(n_2)
// Excluding an n value if distance is = record distance
fn ways_to_win_race(time: u64, dist: u64) -> u64 {
let f_time = time as f64;
let f_dist = dist as f64;
let sqr_discr = ((f_time * f_time) - (4.0 * f_dist)).sqrt();
let n_1 = (((-f_time) + sqr_discr)/(-2.0)).ceil() as u64;
let n_2 = (((-f_time) - sqr_discr)/(-2.0)).floor() as u64;
let (n_1, n_2) = if n_1 > n_2 {
(n_2, n_1)
} else {
(n_1, n_2)
};
let excl_n1 = race_dist(n_1, time) == dist;
let excl_n2 = race_dist(n_2, time) == dist;
let total_offset = match (excl_n1, excl_n2) {
(false, false) => 0,
(false, true) => 1,
(true, false) => 1,
(true, true) => 2,
};
((n_2 - n_1) + 1) - total_offset
}
#[aoc(day6, part1)]
fn part1((times, dists): &(Vec<u64>, Vec<u64>)) -> u64 {
times.iter().zip(dists.iter()).map(|(&time, &dist)| {
ways_to_win_race(time, dist)
}).product()
}
#[aoc(day6, part2)]
fn part2(&(time, dist): &(u64, u64)) -> u64 {
ways_to_win_race(time, dist)
}

View File

@ -5,5 +5,6 @@ mod day02;
mod day03; mod day03;
mod day04; mod day04;
mod day05; mod day05;
mod day06;
aoc_lib! { year = 2023 } aoc_lib! { year = 2023 }