diff --git a/file_input/day6_example_input.txt b/file_input/day6_example_input.txt new file mode 100644 index 0000000..28f5ae9 --- /dev/null +++ b/file_input/day6_example_input.txt @@ -0,0 +1,2 @@ +Time: 7 15 30 +Distance: 9 40 200 diff --git a/src/solutions.rs b/src/solutions.rs index b6dc2fd..f76b91a 100644 --- a/src/solutions.rs +++ b/src/solutions.rs @@ -1,4 +1,5 @@ pub mod day5; +pub mod day6; pub fn create_solutions() -> Vec String>> { vec![ @@ -7,7 +8,7 @@ pub fn create_solutions() -> Vec String>> { vec![not_implemented_yet, not_implemented_yet], vec![not_implemented_yet, not_implemented_yet], vec![day5::solve_task_1, day5::solve_task_2], - vec![not_implemented_yet, not_implemented_yet], + vec![day6::solve_task_1, day6::solve_task_2], vec![not_implemented_yet, not_implemented_yet], vec![not_implemented_yet, not_implemented_yet], vec![not_implemented_yet, not_implemented_yet], diff --git a/src/solutions/day6.rs b/src/solutions/day6.rs new file mode 100644 index 0000000..14d5df1 --- /dev/null +++ b/src/solutions/day6.rs @@ -0,0 +1,96 @@ +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()) + .into_iter() + .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 how_many_times_won = all_rounds_of_durations(parsed.time()) + .into_iter() + .filter(|&distance| distance > parsed.reached_distance()) + .count() as NumericValue; + how_many_times_won.to_string() +} + +fn all_rounds_of_durations(duration: NumericValue) -> Vec { + std::iter::repeat(duration) + .take(duration as usize) + .enumerate() + .map(|(speed_duration, duration)| { + simuluate_reached_distance_at(duration, speed_duration as NumericValue) + }) + .collect() +} + +fn simuluate_reached_distance_at( + duration: NumericValue, + speed_duration: NumericValue, +) -> NumericValue { + assert!(duration >= speed_duration); + let rest_time = duration - speed_duration; + rest_time * speed_duration +} + +#[cfg(test)] +mod testing { + use crate::solutions::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); + } +} diff --git a/src/solutions/day6/day_example_input.txt b/src/solutions/day6/day_example_input.txt new file mode 100644 index 0000000..28f5ae9 --- /dev/null +++ b/src/solutions/day6/day_example_input.txt @@ -0,0 +1,2 @@ +Time: 7 15 30 +Distance: 9 40 200 diff --git a/src/solutions/day6/parsing.rs b/src/solutions/day6/parsing.rs new file mode 100644 index 0000000..1a84b85 --- /dev/null +++ b/src/solutions/day6/parsing.rs @@ -0,0 +1,67 @@ +use super::{race_record::RaceRecord, NumericValue}; + +pub fn parsing(input: &str) -> Vec { + let mut must_be_2_lines = input.lines().take(2); + match (must_be_2_lines.next(), must_be_2_lines.next()) { + (Some(first_line), Some(second_line)) => { + let stripped_first = first_line.strip_prefix("Time:").unwrap(); + let stripped_second = second_line.strip_prefix("Distance:").unwrap(); + let splitted_first = stripped_first + .split_whitespace() + .map(|to_parse| to_parse.parse::().unwrap()); + let splitted_second = stripped_second + .split_whitespace() + .map(|to_parse| to_parse.parse::().unwrap()); + splitted_first + .zip(splitted_second) + .map(|(time, distance)| RaceRecord::new(time, distance)) + .collect() + } + _ => unreachable!(), + } +} + +pub fn parsing_part_2(input: &str) -> RaceRecord { + let (time_str, reached_str) = parsing(input) + .into_iter() + .map(|record| { + ( + record.time().to_string(), + record.reached_distance().to_string(), + ) + }) + .fold( + (String::new(), String::new()), + |(acc_time_str, acc_reached_str), (time_str, distance_str)| { + (acc_time_str + &time_str, acc_reached_str + &distance_str) + }, + ); + RaceRecord::new(time_str.parse().unwrap(), reached_str.parse().unwrap()) +} + +#[cfg(test)] +mod testing { + use crate::solutions::day6::race_record::RaceRecord; + + #[test] + fn should_parse() { + let input = include_str!("day_example_input.txt"); + let parsed = super::parsing(input); + + let expected = vec![ + RaceRecord::new(7, 9), + RaceRecord::new(15, 40), + RaceRecord::new(30, 200), + ]; + assert_eq!(expected, parsed); + } + + #[test] + fn should_parse_part_2() { + let input = include_str!("day_example_input.txt"); + let parsed = super::parsing_part_2(input); + + let expected = RaceRecord::new(71530, 940200); + assert_eq!(expected, parsed); + } +} diff --git a/src/solutions/day6/race_record.rs b/src/solutions/day6/race_record.rs new file mode 100644 index 0000000..705a918 --- /dev/null +++ b/src/solutions/day6/race_record.rs @@ -0,0 +1,25 @@ +use derive_more::derive::Debug; + +use super::NumericValue; +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub struct RaceRecord { + time: NumericValue, + reached_distance: NumericValue, +} + +impl RaceRecord { + pub fn new(time: NumericValue, reached_distance: NumericValue) -> Self { + Self { + time, + reached_distance, + } + } + + pub fn time(&self) -> NumericValue { + self.time + } + + pub fn reached_distance(&self) -> NumericValue { + self.reached_distance + } +}