Build red coloring for actual output if different from expected Removed dependency colon ... with prettytable
124 lines
3.6 KiB
Rust
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);
|
|
}
|
|
}
|