advent_of_code_2023_in_rust/crates/solutions/src/day6.rs
BoolPurist 603ee1827d Benchmark reporting;
Build red coloring for actual output if different from expected
Removed dependency colon ... with prettytable
2024-08-30 15:17:22 +02:00

124 lines
3.6 KiB
Rust

mod parsing;
mod race_record;
type NumericValue = u64;
pub fn solve_task_1(input: &str) -> String {
let parsed = parsing::parsing(input);
let mut how_many_times_won = 1;
for next_record in parsed {
how_many_times_won *= all_rounds_of_durations(next_record.time())
.filter(|&distance| distance > next_record.reached_distance())
.count() as NumericValue;
}
how_many_times_won.to_string()
}
pub fn solve_task_2(input: &str) -> String {
let parsed = parsing::parsing_part_2(input);
let time_to_beat = parsed.time();
assert!(time_to_beat > 1, "Race time must be at least 2");
const FIRST_AND_LAST_CYCLE_DO_NOT_MOVE: NumericValue = 2;
const HALF_AT_OR_OVER_PEAK: NumericValue = 2;
let range: NumericValue =
(parsed.time() - FIRST_AND_LAST_CYCLE_DO_NOT_MOVE) / HALF_AT_OR_OVER_PEAK;
const FIRST_CYCLE_NO_DISTANCE: usize = 1;
for (index, next_distance) in all_rounds_of_durations(parsed.time())
.enumerate()
.skip(FIRST_CYCLE_NO_DISTANCE)
{
if next_distance > parsed.reached_distance() {
const EVEN_TIME_TO_BEAT_LEADS_UNEVEN_PICK: NumericValue = 1;
let one_offset = if time_to_beat % 2 == 0 {
EVEN_TIME_TO_BEAT_LEADS_UNEVEN_PICK
} else {
0
};
let lower_than_distance_over_pick = (index as NumericValue) - 1;
let both_halves = (range - lower_than_distance_over_pick) * 2;
let how_many_times_won = both_halves + one_offset;
return how_many_times_won.to_string();
}
}
unreachable!();
}
fn all_rounds_of_durations(duration: NumericValue) -> impl Iterator<Item = NumericValue> {
let limit = duration as usize;
std::iter::repeat(duration)
.take(limit)
.enumerate()
.map(|(speed_duration, duration)| {
simuluate_reached_distance_at(duration, speed_duration as NumericValue)
})
}
fn simuluate_reached_distance_at(
duration: NumericValue,
speed_duration: NumericValue,
) -> NumericValue {
assert!(
duration >= speed_duration,
"Duration {:?}. Speed Duration: {:?}",
duration,
speed_duration
);
let rest_time = duration - speed_duration;
rest_time * speed_duration
}
#[cfg(test)]
mod testing {
use crate::day6::{simuluate_reached_distance_at, solve_task_2, NumericValue};
use super::solve_task_1;
#[test]
fn should_simuluate_reached_distance_at() {
fn assert_case(
duration: NumericValue,
speed_duration: NumericValue,
expected: NumericValue,
) {
let actual = simuluate_reached_distance_at(duration, speed_duration);
assert_eq!(
expected, actual,
"Duration: {}\n Speed Duration: {}",
duration, speed_duration
);
}
const DURATION: NumericValue = 7;
for (speed_duration, expected) in [
(0, 0),
(1, 6),
(2, 10),
(3, 12),
(4, 12),
(5, 10),
(6, 6),
(7, 0),
] {
assert_case(DURATION, speed_duration, expected)
}
}
#[test]
fn should_solve_task_1() {
let input = include_str!("day6/day_example_input.txt");
let actual = solve_task_1(input);
let expected = "288";
assert_eq!(expected, actual);
}
#[test]
fn should_solve_task_2() {
let input = include_str!("day6/day_example_input.txt");
let actual = solve_task_2(input);
let expected = "71503";
assert_eq!(expected, actual);
}
}